Dotted border around a button - wpf

I'm trying to draw a dotted border around a button, however the border doesn't appear. Not sure what I'm doing wrong here, can you please help?
My Xaml code:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid Background="Ivory">
<Border Width="101" Height="31">
<Border.BorderBrush>
<VisualBrush>
<VisualBrush.Visual>
<Rectangle StrokeThickness="1" Stroke="Red" StrokeDashArray="1 2"/>
</VisualBrush.Visual>
</VisualBrush>
</Border.BorderBrush>
<Button Width="100" Height="30">
Focus Here</Button>
</Border>
</Grid>
</Page>
Note: The immediate issue was with border thickness, but still the dotted border is not appearing even after adding borderthickness.

Visual of the VisualBrush was not able to determine its size automatically so the VisualBrush was not drawn according to the size of the Border. Also note that you need to set same BorderThickness for Border as well as Rectangle. Have a look on the XAML below. Hope it will work good for you.
<Border x:Name="MyBorderedButton" Width="101" Height="31" BorderThickness="2" >
<Border.BorderBrush>
<VisualBrush>
<VisualBrush.Visual>
<Rectangle StrokeDashArray="4 2"
Stroke="Red"
StrokeThickness="2"
RadiusX="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=CornerRadius.TopRight}"
RadiusY="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=CornerRadius.BottomLeft}"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}"/>
</VisualBrush.Visual>
</VisualBrush>
</Border.BorderBrush>
<Button>Focus Here</Button>
</Border>
Its working for me

In your solution, your rectangle has no size, so when it is drawn, there is nothing to draw, the solution is to inherit the size from the parent border:
<Border Width="101" Height="31" BorderThickness="1">
<Border.BorderBrush>
<VisualBrush>
<VisualBrush.Visual>
<Rectangle StrokeThickness="1"
Stroke="Red"
StrokeDashArray="1 2"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}" />
</VisualBrush.Visual>
</VisualBrush>
</Border.BorderBrush>
<Button>
Focus Here
</Button>
</Border>

Related

Bind the error data of datagridrow to a tooltip textblock

I am trying to show the validation error message of data grid row in a tooltip. Here is the code that works when I use the ToolTip property of the Grid control directly (wihtout styling):
<Grid Margin="0,-2,0,-2" ToolTip="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}, Path=(Validation.Errors)[0].ErrorContent}">
<Ellipse StrokeThickness="0" Fill="Red"
Width="{TemplateBinding FontSize}"
Height="{TemplateBinding FontSize}" />
<TextBlock Text="!" FontSize="{TemplateBinding FontSize}"
FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" />
</Grid>
Now this shows the tooltip correctly. Everything is fine.
Problem:
As soon as I start styling the ToolTip separately, the binding stops working somehow. Here is the code that I am trying which does not work:
<Grid Margin="0,-2,0,-2">
<Ellipse x:Name="ErrorEllipse" StrokeThickness="0" Fill="Red"
Width="{TemplateBinding FontSize}"
Height="{TemplateBinding FontSize}" />
<TextBlock Text="!" FontSize="{TemplateBinding FontSize}"
FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center"/>
<Grid.ToolTip>
<ToolTip Background="Transparent" BorderBrush="Transparent" Height="Auto" Width="Auto">
<Border >
<TextBlock Text= "{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}, Path=(Validation.Errors)[0].ErrorContent}"
MinHeight="20"
MinWidth="100"
Foreground="White"
Background="Red"/>
</Border>
</ToolTip>
</Grid.ToolTip>
</Grid>
What am I missing here and how can I achieve the proper binding? Probably its something basic but I have no idea...
You should style the ToolTip separately with a ControlTemplate.
<Style x:Key="ValidationToolTipStyle" TargetType="{x:Type ToolTip}">
<Setter Property="Background" Value="Transparent" />
...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}">
<Border >
<TextBlock
Text="{TemplateBinding Content}"
MinHeight="20"
MinWidth="100"
Foreground="White"
Background="Red"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then in your XAML, use the ToolTip like this:
<Grid Margin="0,-2,0,-2">
<Ellipse x:Name="ErrorEllipse"
StrokeThickness="0" Fill="Red"
Width="{TemplateBinding FontSize}"
Height="{TemplateBinding FontSize}" />
<TextBlock
Text="!"
FontSize="{TemplateBinding FontSize}"
FontWeight="Bold"
Foreground="White"
HorizontalAlignment="Center" />
<ToolTipService.ToolTip>
<ToolTip
Style="{StaticResource ValidationToolTipStyle}"
Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}, Path=(Validation.Errors)[0].ErrorContent}" />
</ToolTip>
</ToolTipService.ToolTip>
</Grid>
I hope this helps.

WPF Templated button - no click event

I'm trying to design a button that has a dashed border all around and an image in the middle. The ideal hit test would be on the image itself, but not a requirement. My problem is that I can't get the click event to fire. It's probably a hit test problem, but I can't figure it out.
In addition to the obvious onClick on the button, I tried MouseEvents on the image, ButtonBase.Click on the Stackpanel, Border.InputBindings on the border .. I thought setting Background=Transparent would do it, but no go.
Here's the xaml:
<Button Grid.Row="0" Click="Button_Click_1">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Transparent" Grid.Row="0" Margin="30,50" CornerRadius="10" BorderThickness="4">
<Border.BorderBrush>
<VisualBrush>
<VisualBrush.Visual>
<Rectangle StrokeDashArray="4 2"
Stroke="#CEAC2D"
StrokeThickness="4"
RadiusX="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=CornerRadius.TopRight}"
RadiusY="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=CornerRadius.BottomLeft}"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}"/>
</VisualBrush.Visual>
</VisualBrush>
</Border.BorderBrush>
<StackPanel Orientation="Vertical" VerticalAlignment="Center" ButtonBase.Click="Button_Click_1">
<Button Height="30" Width="30" Content="Start"/> // just a test button to see if it works
<Image Source="/Images/uploadIcon.png" Height="180"/>
<TextBlock Margin="0,20,0,0" Foreground="#CEAC2D" Text="Drag Folder or Click to Browse" FontFamily="Lato" FontSize="27"
FontWeight="SemiBold" HorizontalAlignment="Center"/>
</StackPanel>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
Why are you trying to set the whole thing as the button's template? If you only want the image bit actually clickable then set that as a button's control template and place it inside a regular visual tree:
<Border Background="Transparent" Grid.Row="0" Margin="30,50" CornerRadius="10" BorderThickness="4">
<Border.BorderBrush>
<VisualBrush>
<VisualBrush.Visual>
<Rectangle StrokeDashArray="4 2"
Stroke="#CEAC2D"
StrokeThickness="4"
RadiusX="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=CornerRadius.TopRight}"
RadiusY="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=CornerRadius.BottomLeft}"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}"/>
</VisualBrush.Visual>
</VisualBrush>
</Border.BorderBrush>
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<Button Click="Button_Click_1" Cursor="Hand">
<Button.Template>
<ControlTemplate TargetType="Button">
<Image Source="/Images/uploadIcon.png" Height="180"/>
</ControlTemplate>
</Button.Template>
</Button>
<TextBlock Margin="0,20,0,0" Foreground="#CEAC2D" Text="Drag Folder or Click to Browse" FontFamily="Lato" FontSize="27"
FontWeight="SemiBold" HorizontalAlignment="Center"/>
</StackPanel>
</Border>

WPF binding mahapps metro icons in template

I would like to transform this button code into a template version and put it in a style xaml file:
<Button Background="Transparent" BorderBrush="Transparent" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="20" Foreground="White" Opacity="1">
<StackPanel Orientation="Horizontal">
<Rectangle Width="24" Height="24" Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{iconPacks:PackIconMaterial Kind=Face, Width=24, Height=24}" />
</Rectangle.OpacityMask>
</Rectangle>
<TextBlock Margin="10 0 10 0" VerticalAlignment="Center" Text="John Doe" FontSize="24" FontWeight="Normal" FontFamily="Segoe UI Light" />
</StackPanel>
</Button>
I have this until now:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<StackPanel Name="ButtonGrid" RenderTransformOrigin="0.5,0.5">
<Rectangle Width="48" Height="48" Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{Binding Path=(extensions:Icons.IconKind), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"/>
</Rectangle.OpacityMask>
</Rectangle>
<iconPacks:PackIconSimpleIcons x:Name="btnIcon" Kind="{Binding Path=(**extensions:Icons.IconKind**), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" Width="48" Height="48" VerticalAlignment="Top" HorizontalAlignment="Center" Foreground="{TemplateBinding Foreground}" />
<TextBlock x:Name="tButton" HorizontalAlignment="Center" VerticalAlignment="Bottom" Foreground="{TemplateBinding Foreground}" FontWeight="Bold" Text="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" />
<StackPanel.RenderTransform>
<ScaleTransform ScaleX="1.0" ScaleY="1.0" CenterX="0.5" CenterY="0.5"/>
</StackPanel.RenderTransform>
</StackPanel>
<ControlTemplate.Triggers>
...
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
In a perfect world, the icon specified in the visual property should be set dynamically in the visual attribute of the template.
I came up with this solution but it doesn't work. Binding can only be done on DependencyProperty.
<VisualBrush Stretch="Fill" Visual="{iconPacks:PackIconMaterial Kind={Binding Path=(extensions:Icons.IconKind)}, Width=48, Height=48}"/>
Any idea how to do it? i'm not this good with template expressions :/
You could define a Template with a VisualBrush that binds to the Tag property of the Button:
<Style x:Key="IconStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<StackPanel Orientation="Horizontal"
DataContext="{Binding RelativeSource={RelativeSource AncestorType=Button}}">
<Rectangle Width="24" Height="24" Fill="{Binding Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{Binding Tag}" />
</Rectangle.OpacityMask>
</Rectangle>
<TextBlock Margin="10 0 10 0" VerticalAlignment="Center" Text="John Doe"
FontSize="24" FontWeight="Normal" FontFamily="Segoe UI Light" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
...and then set the Tag property to an icon:
<Button Style="{StaticResource IconStyle}" Foreground="Green">
<Button.Tag>
<iconPacks:PackIconMaterial Kind="Face" Width="24" Height="24" />
</Button.Tag>
</Button>

Canvas Z Order issue

Im trying to render a bunch of ellipses with lines coming out from the center, in north, east, south and west directions.
However, I also need all ellipses to be on top of all lines, not just on top of its own lines.
With the following code, I can't do this as each item template has its own canvas, and so setting the zindex wont help.
Any ideas of how I could solve this?
<Window x:Class="WpfApplication27.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="800" Width="800">
<ItemsControl ItemsSource="{Binding Nodes}">
<ItemsControl.Template>
<ControlTemplate>
<Grid>
<Canvas Name="PART_Canvas" IsItemsHost="True"/>
</Grid>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Line X1="25" Y1="25" X2="25" Y2="125" Stroke="Black"/>
<Line X1="25" Y1="25" X2="25" Y2="-75" Stroke="Black"/>
<Line X1="25" Y1="25" X2="125" Y2="25" Stroke="Black"/>
<Line X1="25" Y1="25" X2="-75" Y2="25" Stroke="Black"/>
<Ellipse Width="50" Height="50" Fill="Red"/>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Window>
You could add 2 ItemsCotrols on top of each other bound to the same collection, the back one would render the lines and the front one renders the ellipse's
<Grid>
<Grid.Resources>
<Style x:Key="NodeContainer" TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</Grid.Resources>
<!--Line-->
<ItemsControl ItemsSource="{Binding Nodes}" ItemContainerStyle="{StaticResource NodeContainer}">
<ItemsControl.Template>
<ControlTemplate>
<Grid>
<Canvas Name="PART_CanvasBack" IsItemsHost="True"/>
</Grid>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Line X1="25" Y1="25" X2="25" Y2="125" Stroke="Black"/>
<Line X1="25" Y1="25" X2="25" Y2="-75" Stroke="Black"/>
<Line X1="25" Y1="25" X2="125" Y2="25" Stroke="Black"/>
<Line X1="25" Y1="25" X2="-75" Y2="25" Stroke="Black"/>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!--Ellipse-->
<ItemsControl ItemsSource="{Binding Nodes}" ItemContainerStyle="{StaticResource NodeContainer}">
<ItemsControl.Template>
<ControlTemplate>
<Grid>
<Canvas Name="PART_CanvasFront" IsItemsHost="True"/>
</Grid>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<Ellipse Width="50" Height="50" Fill="Red"/>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>

Datatemplate for Tabitem doesn't cover all the tabitem space (WPF Tabcontrol)

i have a datatemplate for a tabitem in a tab control.
The datatemplate doesn't cover all the Tabitem control, the beckground is a gray or white, control default color.
The Datatemplate of the TabItem:
<DataTemplate x:Key="ClosableTabItemTemplate">
<Border BorderThickness="1" BorderBrush="Transparent" CornerRadius="4">
<!--Border to make the tab item gap from the content-->
<Border x:Name="InsideBorder" BorderThickness="3" BorderBrush="#D6EAFF" CornerRadius="4">
<!--Border for the rounded corners-->
<!--TabItem Content Grid-->
<Grid x:Name="tabItemGrid" ShowGridLines="True" Margin="0" Background="#D6EAFF">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<!--Icon Column-->
<ColumnDefinition Width="1*"/>
<!--Title Column-->
<ColumnDefinition Width="20"/>
<!--Close Button Column-->
</Grid.ColumnDefinitions>
<!--Icon of tab Item-->
<Image Grid.Column="0" Grid.Row="1" Height="18" HorizontalAlignment="Left" Source="Images/tab1.jpg"/>
<!--Title of tab Item-->
<Label Name="TabText" Grid.Column="1" Grid.Row="1" Content="TabItem" Height="23" HorizontalAlignment="Left"
Margin="4,1,0,0" VerticalAlignment="Top" FontFamily="Courier" FontSize="12" />
<!--Close button of tab Item-->
<Button Style="{DynamicResource TabButton}"
Name="button_close" Content="x"
Command="{Binding Path=CloseCommand}"
Grid.Column="2" Grid.Row="1"
Height="20" Width="20"
Margin="0,0,0,2" VerticalAlignment="Center" HorizontalAlignment="Right"
FontFamily="Courier" FontStretch="Normal" FontWeight="Bold" FontSize="14"
Visibility="Visible" ToolTip="Close"
BorderBrush="Transparent" BorderThickness="0" Background="Transparent" Padding="0,0,0,0"
>
</Button>
</Grid>
</Border>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TabItem}},Path=IsSelected}" Value="True">
<Setter TargetName="tabItemGrid" Property="Background" Value="#D6EAFF" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TabItem}},Path=IsSelected}" Value="False">
<!--<Trigger Property="IsSelected" Value="False">-->
<Setter TargetName="InsideBorder" Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFCCCCD0" />
<GradientStop Color="#FF526593" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="tabItemGrid" Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFCCCCD0" />
<GradientStop Color="#FF526593" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</DataTrigger>
<!--</Trigger>-->
</DataTemplate.Triggers>
</DataTemplate>
The Tabcontrol:
<TabControl Name="MainTabCtrl" Margin="0" Padding="0" BorderThickness="0" Background="Transparent"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Path=TabViewModels}"
ItemTemplate="{StaticResource ClosableTabItemTemplate}">
when the Xaml code of the tabitem wasn't inside a DataTemplate it worked fine - the "Transparent" of the first border did the job and no gray/white background appeared. but when i moved the code inside a DataTemplate the gray background appeared.
How do i make the background of the tabitem transparent?
I added HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" to the tabcontrol, it only narrows the gray area a bit but it still exsits.
Try to set Padding for TabItems to zero.

Resources