Change Viewbox Path Data based on DataTrigger value - wpf

I have the following XAML where I declare a Button containing a Viewbox that displays Geometry data. After MANY attempts and reviewing SO questions, I still cannot get the Geometry data to appear inside the button.
<Button
x:Name="ChangeViewButton"
Style="{DynamicResource TransparentButtonRight}"
Command="{Binding ExecuteChangeViewCommand}">
<Viewbox Margin="-10">
<Viewbox.Style>
<Style TargetType="Viewbox">
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="24" />
<Setter Property="Margin" Value="1" />
<Setter Property="Opacity" Value=".75" />
<Setter Property="Path.Stretch" Value="Uniform" />
<Setter Property="Path.StrokeThickness" Value="2" />
<Setter Property="Path.Stroke" Value="{Binding ElementName=ChangeViewButton, Path=Foreground}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CylinderManagementViewType}" Value="DataGridView">
<Setter Property="Path.Data" Value="{StaticResource GridGlyph}"/>
<Setter Property="Path.ToolTip" Value="Change to Grid View"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=CylinderManagementViewType}" Value="TileView">
<Setter Property="Path.Data" Value="{StaticResource TileGlyph}"/>
<Setter Property="Path.ToolTip" Value="Change to Tile View"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Viewbox.Style>
</Viewbox>
</Button>
The DataTriggers are bound to an enum value in the ViewModel that is defined as follows:
public enum CylinderManagementViewTypes
{
DataGridView,
TileView
}
private CylinderManagementViewTypes _cylinderManagementViewType;
public CylinderManagementViewTypes CylinderManagementViewType
{
get { return _cylinderManagementViewType; }
set { SetProperty(ref _cylinderManagementViewType, value); }
}
The Geometry data is defined in a Resource Dictionary as:
<Geometry x:Key="TileGlyph">
M5.9,6 18.9,6 18.9,19 5.9,19zM31.1,6 44.1,6 44.1,19 31.1,19zM5.9,30.9 18.9,30.9 18.9,43.9 5.9,43.9zM31.1,30.9 44.1,30.9 44.1,43.9 31.1,43.9z
</Geometry>
<Geometry x:Key="GridGlyph">
M19.1,6.1 19.1,25 19.1,43.9M31.2,6.1 31.2,25.2 31.2,43.9M44.2,19.1 25.1,19.1 6.1,19.1M44.2,30.9 25.1,30.9 6.1,30.9M44,43.9 6,43.9 6,5.9 44,5.9z
</Geometry>
If I just declare the Button as follows, the Geometry data is displayed in the button:
<Button
x:Name="ChangeViewButton"
Style="{DynamicResource TransparentButtonRight}"
Command="{Binding ExecuteChangeViewCommand}"
ToolTip="Change to Grid View">
<Viewbox Margin="-10">
<Path
Data="{StaticResource GridGlyph}"
Stroke="{Binding ElementName=ChangeViewButton, Path=Foreground}"
Style="{StaticResource IconPath}" />
</Viewbox>
</Button>
where IconPath is defined as:
<Style x:Key="IconPath" TargetType="Path">
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="24" />
<Setter Property="Margin" Value="1" />
<Setter Property="Opacity" Value=".75" />
<Setter Property="Stretch" Value="Uniform" />
<Setter Property="StrokeThickness" Value="2" />
</Style>
Any help solving this is greatly appreciated!

Well after doing even more investigation, and taking a hint from this SO post answer, I discovered that I needed to set the Style on the Path rather than the Viewbox. The Button declaration works and now appears as:
<Button
x:Name="ChangeViewButton"
Style="{StaticResource TransparentButtonRight}"
Command="{Binding ExecuteChangeViewCommand}">
<Viewbox Margin="-10">
<Path>
<Path.Style>
<Style TargetType="Path">
<Setter Property="Data" Value="{StaticResource GridGlyph}"/>
<Setter Property="ToolTip" Value="Change to Grid View"/>
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="24" />
<Setter Property="Margin" Value="1" />
<Setter Property="Opacity" Value=".75" />
<Setter Property="Stretch" Value="Uniform" />
<Setter Property="StrokeThickness" Value="2" />
<Setter Property="Stroke" Value="{Binding ElementName=ChangeViewButton, Path=Foreground}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CylinderManagementViewType}" Value="TileView">
<Setter Property="Path.Data" Value="{StaticResource TileGlyph}"/>
<Setter Property="Path.ToolTip" Value="Change to Tile View"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Viewbox>
</Button>

Related

How can I highlight the cell which contains the error?

I have a DataGrid with four columns for which I have defined a style as well as a triggered style for the case the user enters an invalid value.
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontFamily" Value="ArialMT"/>
<Setter Property="Height" Value="24"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="ValidationErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Ellipse Width="12" Height="12" Fill="Red" Stroke="Black" StrokeThickness="0.5"/>
<TextBlock FontWeight="Bold" Padding="4,0,0,0" Margin="0" VerticalAlignment="Top" Foreground="White" Text="!" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="IsEnabled" Value="True" />
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
This works well and the complete DataGridRow is marked as faulty because I used this in the XAML:
<DataGrid.RowValidationRules>
<local:CycleValidationRule ValidationStep="UpdatedValue" />
</DataGrid.RowValidationRules>
Now I want to highlight the DataGridCell with the invalid value explictely additionally (setting the background colour). Hence, I defined another style:
<Style x:Key="cycleErrStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="Magenta"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true" >
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
but this doesn't work.
When I set <Trigger Property="Validation.HasError" Value="false" > to false, the style affects. It seems as if the Validation.HasError property has been reset after validation for the grid's row.
In the XAML I defined this:
<DataGridTextColumn x:Name="TagCycle" Header="Cycle" Binding="{Binding Mode=TwoWay, Path=RawTag.Cycle, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
ElementStyle="{StaticResource ResourceKey=cycleErrStyle}" />
How can I highlight the invalid cell additionally to marking the row as faulty?
You could use a DataTrigger that binds to the Validation.HasError attached property of the parent DataGridRow:
<Style x:Key="cycleErrStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="Magenta"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(Validation.HasError), RelativeSource={RelativeSource AncestorType=DataGridRow}}" Value="true" >
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>

Mouseover on overlapped control template elements

I am trying to create a control template that presents a geometric figure (Path) and some joints (Ellipses) on it. I need to highlight figure and joints when mouse over a figure, and highlight figure and make joint bigger and change it colour when mouse over a joint.
The problem is, when mouse is over a joint inside path, then mouse is not over a path. How to solve it?
<ControlTemplate x:Key="ctConnector">
<Canvas>
<Path x:Name="ConnectorPath" Data="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=PathData}" Fill="White">
<Path.Style>
<Style TargetType="Path">
<Setter Property="StrokeThickness" Value="1" />
<Setter Property="Stroke" Value="{StaticResource PathNormalBrush}" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" Value="{StaticResource PathMouseOverBrush}" />
</Trigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
<ItemsControl x:Name="ConnectorJoints" ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Joints}">
<ItemsControl.Style>
<Style TargetType="ItemsControl">
<Setter Property="Visibility" Value="Hidden" />
</Style>
</ItemsControl.Style>
<ItemsControl.ItemContainerStyle>
<Style TargetType="FrameworkElement">
<Setter Property="Canvas.Left" Value="{Binding Left, Converter={x:Static local:CoordConverter.Instance}, ConverterParameter=X}" />
<Setter Property="Canvas.Top" Value="{Binding Top, Converter={x:Static local:CoordConverter.Instance}, ConverterParameter=Y}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse>
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Width" Value="3" />
<Setter Property="Height" Value="3" />
<Setter Property="Margin" Value="-1.5,-1.5" />
<Setter Property="Fill" Value="{StaticResource PathMouseOverBrush}" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Width" Value="7" />
<Setter Property="Height" Value="7" />
<Setter Property="Margin" Value="-3.5,-3.5" />
<Setter Property="Fill" Value="{StaticResource JointMouseOverBrush}" />
</Trigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
<ControlTemplate.Triggers>
<Trigger SourceName="ConnectorPath" Property="IsMouseOver" Value="True">
<Setter TargetName="ConnectorJoints" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

WPF DockPanel IsMouseOver only triggered when child controls are moused over

I have a sort of tile system for my application. See the below code:
<WrapPanel Grid.Column="0" Grid.Row="1">
<DockPanel Style="{StaticResource Panel}">
<Label Content="Upload"/>
<Image Width="40">
<Image.Source>
<BitmapImage DecodePixelWidth="40" UriSource="images/download.png" />
</Image.Source>
</Image>
</DockPanel>
</WrapPanel>
As you can see, I have got the main container ([icode]WrapPanel[/icode]), and then I have got multiple [icode]DockPanel[/icode]'s which makeup the tile itself.
For some reason when I mouseover the DockPanel, the IsMouseOver trigger doesn't trigger, but it does when I mouse over any of it's children. Once triggered it remains triggered until my mouse leaves the DockPanel.
Here is the style:
<Style x:Key="Panel" TargetType="DockPanel">
<Setter Property="Margin" Value="4" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Height" Value="118" />
<Setter Property="Width" Value="118" />
<Setter Property="LastChildFill" Value="True" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FF212121" />
</Trigger>
</Style.Triggers>
<Style.Resources>
<Style TargetType="Label">
<Setter Property="Foreground" Value="White" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="Margin" Value="3" />
<Setter Property="DockPanel.Dock" Value="Bottom" />
</Style>
</Style.Resources>
</Style>
Any ideas?
Try to set DockPanel's background to Transparent.
When background is null, WPF will not include it in hit test.

wpf Treeview CheckBox Item ForeGround Color cannot Change when it is disabled?

This is the my xaml style for Treeview CheckBox Item. I'm using Syncfusion Treeview.
<Style x:Key="contractListItemContainerStyle" TargetType="{x:Type syncfusion:TreeViewItemAdv}">
<Setter Property="IsExpanded" Value="True" />
<Setter Property="IsSelected" Value="{Binding IsInitiallySelected, Mode=OneTime}" />
<Setter Property="KeyboardNavigation.AcceptsReturn" Value="True" />
<Setter Property="IsEditable" Value="False" />
<Setter Property="IsEnabled" Value="{Binding Enable}" />
<Setter Property="Foreground" Value="Red" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Foreground" Value="Green" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
<HierarchicalDataTemplate x:Key="selectedContractsDataTemplate" ItemsSource="{Binding Children}" >
<StackPanel Orientation="Horizontal">
<CheckBox Margin="2,0,2,0"
Focusable="False"
IsChecked="{Binding Content.IsChecked}"
VerticalAlignment="Center" />
<ContentPresenter Content="{Binding}" Margin="2,0" />
</StackPanel>
</HierarchicalDataTemplate>
If I set Enable to False from ViewModel, The Color doesn't change to red but If I set to true, it changes to Green. Why? Pelase advise.
The code should work, see/try this:
<StackPanel>
<CheckBox Name="chk" Content="check this...">
<CheckBox.Style>
<Style>
<Setter Property="CheckBox.Foreground" Value="Red" />
<Style.Triggers>
<Trigger Property="CheckBox.IsEnabled" Value="True">
<Setter Property="CheckBox.Foreground" Value="Green" />
</Trigger>
<Trigger Property="CheckBox.IsEnabled" Value="False">
<Setter Property="CheckBox.Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<Button Content="press" Click="Button_Click"/>
</StackPanel>
Probably something is wrong with the binding?
Try this
<Setter Property = "Foreground" Value = "Red"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Foreground" Value="Green" />
</Trigger>
</Style.Triggers>

Dotted border on ListBoxItem in WPF

How can I make the default border on my ListBoxItems a dotted border? See following way of styling it:
<Grid.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Height" Value="30" />
<Setter Property="BorderThickness" Value="0,0,0,1" />
<Setter Property="BorderBrush" Value="Silver" />
<Setter Property="Content" Value="" />
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="3">
<Setter Property="BorderBrush" Value="Black"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
Here I make the AlternationIndex 0, 1 and 2 to a dotted border instead of a solid line. How can this be done?
Try this:
<Window.Resources>
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
<!-- SimpleStyles: ListBoxItem -->
<Style TargetType="ListBoxItem" x:Key="ListBoxItemTemplate">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Rectangle x:Name="Rectangle" Fill="Transparent" Stroke="Black"
StrokeDashCap="Square" StrokeThickness="0" SnapsToDevicePixels="True">
<Rectangle.StrokeDashArray>
<sys:Double>5</sys:Double>
</Rectangle.StrokeDashArray>
</Rectangle>
<Border
Name="Border"
Padding="2"
BorderThickness="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness}"
BorderBrush="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderBrush}">
<ContentPresenter />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Rectangle" Property="StrokeThickness" Value="1" />
<Setter TargetName="Border" Property="BorderThickness" Value="0" />
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Rectangle" Property="Fill" Value="{StaticResource SelectedBackgroundBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource ListBoxItemTemplate}">
<Setter Property="Height" Value="30" />
<Setter Property="BorderThickness" Value="0,0,0,1" />
<Setter Property="BorderBrush" Value="Silver" />
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="3">
<Setter Property="BorderBrush" Value="Black"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<ListBox>
<ListBoxItem Content="Item 1" />
<ListBoxItem Content="Item 2" />
<ListBoxItem Content="Item 3" />
<ListBoxItem Content="Item 4" />
</ListBox>
</StackPanel>
So I put a rectangle bellow the actual border in the control template. The rectangle can have its border be dotted, or dashed or w/e (to make the dash smaller just change the part to 2, 1 is not noticeable). So the default value of the rectangle's border thickness is 0, but when selected I set the thickness to 1 so it's visible. I made some border properties to be binded to its templated parent too, so it can look like what you set on your style (brush silver, thickness 0,0,0,1).

Resources