Custom Control Height and Width disappear when resizing in design window - wpf

I've created a WPF Custom Control, I put it on a form and give it a height and a width - all works fine. I'm referencing Height and Width using TemplateBinding in the control, so I need these to be set.
Should I decide to resize the control using the gui, the height and width disappear completely and the control formatting goes wrong.
How do I get the new height and width of the control and set it when this happens?
Posting code as requested:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GraphControls">
<Style TargetType="{x:Type local:ContourPlot}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ContourPlot}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Viewbox>
<Border BorderBrush="Black" BorderThickness="1">
<Canvas x:Name="cvGraph" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" >
<Rectangle Canvas.Left="40" Canvas.Top="31" Width="48" Height="41" Fill="AliceBlue"/>
</Canvas>
</Border>
</Viewbox>
<Canvas Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" >
<Label x:Name="lblTest" Canvas.Left="0" Canvas.Top="10" Content="Label" FontSize="12" />
</Canvas>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Control is used in a form as follows:
<Window x:Class="GraphWrapper.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gc="clr-namespace:GraphControls;assembly=GraphControls"
Title="MainWindow" Height="350" Width="525">
<Grid>
<gc:ContourPlot Background="#FFC3EAC3" Margin="65,42,128,118" Width="310" Height="150"/>
</Grid>
</Window>
As previously stated, when the control is resized via the gui, the Width and Height properties disappear.

<Style TargetType="{x:Type local:ContourPlot}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ContourPlot}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}">
<Grid>
<Viewbox Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}">
<Border BorderBrush="Black" BorderThickness="1">
<Canvas x:Name="cvGraph" >
<Rectangle Canvas.Left="40" Canvas.Top="31" Width="48" Height="41" Fill="AliceBlue"/>
</Canvas>
</Border>
</Viewbox>
<Canvas >
<Label x:Name="lblTest" Canvas.Left="0" Canvas.Top="10" Content="Label" FontSize="12" />
</Canvas>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
The Templated width and Height are not recommended to use in multiple controls inside its control Template. In Your case, Height and Width are going to be same as if you set like above.
More over you have placed the ViewBox and the Canvas in same area so its going to be overlap with same width and height. The problem might be with the Viewbox.

Related

Set size of border inside ControlTemplate to size of button

I want a ControlTemplate for a few buttons so I can control the colour of the button when the mouse is over it. The problem is that I use a border as the ControlTemplate content and I want the size (BorderThickness) of that border to be equal to the button's size. And since the button is part of a grid, its size is flexible. This is my code so far:
<Window x:Class="WPFTesting.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFTesting"
mc:Ignorable="d"
Title="MainWindow" Height="400" Width="350">
<Window.Resources>
<Style TargetType="Button" x:Key="ex">
<Setter Property="Background" Value="Black"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="50"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Content="Btn0" Margin="0, 10, 0, 30" Style="{StaticResource ex}" Grid.Row="0"/>
<Button Content="Btn1" Margin="0, 10, 0, 30" Grid.Row="1"/>
<Button Content="Btn2" Margin="0, 10, 0, 30" Grid.Row="2"/>
</Grid>
How can I make the BorderThickness fill the entire grid row. Should I even be using a border as the ControlTemplate content in the first place?
You should just write
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>

Setting a Thumb's cursor when IsDragging = True

I have a control template for a Thumb defined in a Resource Dictionary.
<ControlTemplate TargetType="{x:Type Thumb}">
<Border x:Name="PART_Border"
Cursor="SizeWE"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ControlTemplate>
The ControlTemplate is implemented in a style I call GridColumnHeaderGripper and this style is implemented in another Resource Dictionary
<ControlTemplate TargetType="GridViewColumnHeader">
<DockPanel>
<Thumb x:Name="PART_HeaderGripper"
DockPanel.Dock="Right"
Margin="0,0,-8,0"
Cursor="SizeWE"
Style="{StaticResource GridColumnHeaderGripper}" />
etc...
It works great, however, when I begin dragging the Thumb, then the cursor changes from "SizeWE" to "None". I saw another post similar to this on StackOverflow that suggested a Trigger to set the Cursor.
<ControlTemplate.Triggers>
<Trigger Property="IsDragging" Value="True">
<Setter Property="Cursor" Value="SizeWE"/>
</Trigger>
</ControlTemplate.Triggers>
However this solution didn't work for me.
From what I can understand is that we can override the cursor using the Mouse.OverrideCursor static property. Is it possible to set this static property using a Trigger? Is there anything I can do to change the cursor when dragging a thumb?
Add 'Cursor' attribute where you actually declare thumb.
<Window x:Class="ThumbCursor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ThumbCursor"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<ControlTemplate x:Key="template" TargetType="{x:Type Thumb}">
<Border x:Name="PART_Border"
Cursor="SizeWE"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ControlTemplate>
</Window.Resources>
<Grid>
<Thumb x:Name="thmb" Height="50" Width="100" Cursor="SizeWE" Template="{StaticResource template}" DragDelta="thmb_DragDelta"/>
</Grid>
</Window>

How to create a button with a smaller hit area than its visual area?

I'm trying to create buttons with smaller hit area to prevent misoperation in an industrial touchscreen PC program. Here is a sample,
and only the white area should response to touch and mouse operations.
I've tried to use ControlTemplate
<ControlTemplate x:Key="ButtonToTouch" TargetType="{x:Type Button}">
<Grid>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"/>
<Button Background="{x:Null}" BorderBrush="{x:Null}" FontSize="{TemplateBinding FontSize}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<Button.Content>
<Grid Margin="8" >
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Rectangle Fill="Transparent" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
</Grid>
</Button.Content>
</Button>
</Grid>
</ControlTemplate>
Now mouse enter event works that way, but it seems that every visible pixel in the button template can trigger the click event, so i have to set the background of the border to null, and set the background somewhere out of the template.
Any suggestions? Thanks for any help.
set IsHitTestVisible="False" on Border. With 8 Margin on Grid, 8px wide area will not register input.
<ControlTemplate x:Key="ButtonToTouch" TargetType="{x:Type Button}">
<Grid>
<Border BorderBrush="{TemplateBinding BorderBrush}"
IsHitTestVisible="False"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"/>
<Grid Margin="8">
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Rectangle Fill="Transparent" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
</Grid>
</Grid>
</ControlTemplate>

wpf itemscontrol items outside of control

I have an own control which derives from itemscontrol with an own template. I am using a Canvas inside the itemscontrol as ItemsPanel. Why f.e. on resize of the window the items also can be outside of the itemscontrol?
Templates:
<Style TargetType="{x:Type local:Dashboard}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Dashboard}">
<Grid>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
The items use this:
<Style TargetType="{x:Type local:Widget}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Widget}">
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderThickness="2" BorderBrush="Black" Background="WhiteSmoke"
x:Name="Part_Header">
<ContentPresenter ContentSource="Header"/>
</Border>
<Border Grid.Row="1" BorderThickness="2" BorderBrush="Black" Background="WhiteSmoke">
<Grid>
<ContentPresenter />
<ResizeGrip x:Name="Part_Resize"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Cursor="SizeNWSE" />
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Depending on your alignment and margin settings, resizing a parent can cause children to move outside of a parent's boundaries. The easiest way I've found to check this is to load Blend and resize the parent, watching how contained controls move. By tweaking the anchors in Blend (which changes alignments and margins), you should be able to troubleshoot why they move.

Styling GridSplitter wpf C#

i want to style my GridSplitter like adding dots on it (as found on http://msdn.microsoft.com/en-us/library/aa970265.aspx).
i also want to change gridsplitter color on mouseOver, or apply Aero Theme.
<Style x:Key="GridSplitterStyle1" TargetType="{x:Type GridSplitter}">
<Setter Property="Background"
Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="PreviewStyle">
<Setter.Value>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Fill="#80000000"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GridSplitter}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--Theme-->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="/RibbonControlsLibrary;component/Themes/Office2007Blue.xaml" />
</ResourceDictionary.MergedDictionaries>
<GridSplitter x:Name="gridSplitterTreeNodes" Width="10"
BorderThickness="1,0" Cursor="SizeWE"
RenderTransformOrigin="-1.2,0.507" ShowsPreview="True"
Style="{DynamicResource GridSplitterStyle1}">
<GridSplitter.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFE3EFFF" Offset="0"/>
<GradientStop Color="#FFAFD2FF" Offset=".45"/>
</LinearGradientBrush>
</GridSplitter.Background>
</GridSplitter>
Mostly for my own future reference, here is a vertical grid splitter that has the rounded shape of a button (but doesn't react to mouseover properly):
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Center" Width="8">
<GridSplitter.Template>
<ControlTemplate TargetType="{x:Type GridSplitter}">
<Grid>
<Button Content="⁞" />
<Rectangle Fill="#00FFFFFF" />
</Grid>
</ControlTemplate>
</GridSplitter.Template>
</GridSplitter>
A horizontal splitter could just use "····" as the Button's Content.
<GridSplitter x:Name="gridSplitterTreeNodes" Width="5" BorderThickness="1,0"
Cursor="SizeWE" RenderTransformOrigin="-1.2,0.507" ShowsPreview="True"
Style="{DynamicResource GridSplitterStyle1}">
<GridSplitter.Background>
<ImageBrush ImageSource="Images\gripDots.png" TileMode="FlipXY"
Stretch="UniformToFill"/>
</GridSplitter.Background>
</GridSplitter>
You can also save image from Msnd Microsoft to get the same effect, More Info
Another way of adding a 'gripper' button/graphic to a GridSplitter, without losing mouse events, would be to use a simple label on top of the splitter.
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" Background="Gray"/>
<Label Grid.Column="1" Content="⁞" Foreground="White" VerticalAlignment="Center" FontSize="26" FontWeight="Bold" IsHitTestVisible="False"/>
Making sure the GridSplitter and Label are in the same Column, and that IsHitTestVisible=False is set in the Label.
For a different type of style you can do the below.
Produces a nice overlaping style. The Gridsplitter overlaps both the left and right content.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="#777"/>
<GridSplitter
Grid.Column="1"
HorizontalAlignment="Stretch"
ResizeDirection="Columns"
ResizeBehavior="PreviousAndNext"
Panel.ZIndex="2">
<GridSplitter.Template>
<ControlTemplate TargetType="{x:Type GridSplitter}">
<Grid>
<Rectangle IsHitTestVisible="False" Fill="Black"/>
<Border
Background="White"
Width="25" Height="25" c
CornerRadius="25" Margin="-13 0">
<Path Stroke="Black" StrokeThickness="0.5" Width="17" Height="7" Data="m 4.4549201,1048.4664 -4.33056515,1.9095 4.33056515,1.9094 0,-3.8189 z m 3.0901599,0 0,3.8189 4.330565,-1.9094 -4.330565,-1.9095 z m -3.2239449,0.2053 0,3.4083 -3.86518514,-1.7041 3.86518514,-1.7042 z m 3.3577349,0 3.865185,1.7042 -3.865185,1.7041 0,-3.4083 z" Stretch="Fill"/>
</Border>
</Grid>
</ControlTemplate>
</GridSplitter.Template>
</GridSplitter>
<Border Grid.Column="2" Background="#777"/>
</Grid>
Sample Output
In response to Burton Radons's answer, I personally prefer the styling:
<GridSplitter
Width="8"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<GridSplitter.Template>
<ControlTemplate TargetType="{x:Type GridSplitter}">
<Grid>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="⁞" />
<Rectangle Fill="#00FFFFFF" />
</Grid>
</ControlTemplate>
</GridSplitter.Template>
</GridSplitter>
This implementation produces the same aesthetic effect whilst also maintaining functionality.

Resources