I am trying to use triggers to modify the property of my control.I have a RadioButton and a Border, I want to modify the border Background when the
RadioButton IsSelected. So here is my code:
<Border BorderBrush="{DynamicResource MaterialDesignDivider}">
<RadioButton IsChecked="{Binding Erase_IsSelected}" Content="E">
<RadioButton.Resources>
<Style TargetType="{x:Type RadioButton}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="{DynamicResource MaterialDesignSelection}" />
</Trigger>
</Style.Triggers>
</Style>
</RadioButton.Resources>
</RadioButton>
</Border>
This seems don't work, how should I fix it? Thanks!
Use a Style for the Border that binds to the IsChecked property of the RadioButton:
<Border BorderBrush="{DynamicResource MaterialDesignDivider}">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=rb}" Value="True">
<Setter Property="Background" Value="{DynamicResource MaterialDesignSelection}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<RadioButton x:Name="rb" IsChecked="{Binding Erase_IsSelected}" Content="E" />
</Border>
A RadioButton style cannot change the property of a Border.
Add the OnChecked event in your xaml:
<RadioButton Checked="Radiobutton_OnChecked" Content="E">
<RadioButton.Resources>
<Style TargetType="{x:Type RadioButton}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="{DynamicResource MaterialDesignSelection}" />
</Trigger>
</Style.Triggers>
</Style>
</RadioButton.Resources>
</RadioButton>
this will create you a function in your .cs like this, where you can change the background:
private void Radiobutton_OnChecked(object sender, RoutedEventArgs e)
{
RadioButton rdb = (RadioButton) sender;
rdb.Background = new SolidColorBrush(Colors.Green);
}
Related
I want to implement a ListBox with ToggleButton when I press then the template of ListBox should be updated. The template one will have only icons and one will have both icons and text as shown in the image.
I have created one attached property for this and binded it to the ToggleButton IsChecked property inside control template, but this attached property is not updating and my template is not changing.
First time when I load the application it is working.
<Style x:Key="NavigationListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="{StaticResource PrimaryDarkBrush}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="SelectedIndex" Value="0"/>
<Setter Property="Width" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border Background="{TemplateBinding Background}"
BorderThickness="0"
Padding="0"
SnapsToDevicePixels="true">
<ScrollViewer Padding="{TemplateBinding Padding}"
Focusable="false">
<StackPanel>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<ToggleButton IsChecked="{Binding local:IsOpenInfo.IsOpen,Mode=TwoWay}" Style="{DynamicResource ToggleButtonstyle}" Foreground="White">
</ToggleButton>
</StackPanel>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate" Value="{DynamicResource NavigationDataTemplate}"/>
<Style.Triggers>
<Trigger Property="local:IsOpenInfo.IsOpen" Value="True">
<Setter Property="ItemTemplate" Value="{DynamicResource NavigationDataTemplate1}"/>
</Trigger>
<Trigger Property="local:IsOpenInfo.IsOpen" Value="False">
<Setter Property="ItemTemplate" Value="{DynamicResource NavigationDataTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="ToggleButtonstyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<StackPanel Orientation="Horizontal">
<iconPacks:PackIconMaterialDesign x:Name="MenuItemIcon" VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="12" Kind="ArrowBack"/>
<TextBlock Text="Collapse" VerticalAlignment="Center" HorizontalAlignment="Center" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="ArrowForward"/>
<Setter TargetName="txtBlock" Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsChecked" Value="false">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="ArrowBack"/>
<Setter TargetName="txtBlock" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="NavigationDataTemplate">
<iconPacks:PackIconMaterialDesign x:Name="MenuItemIcon" VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="12"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="Home">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Home"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="Email">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Email"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="Cloud">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Cloud"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="Collapse">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Mail"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate x:Key="NavigationDataTemplate1">
<StackPanel Orientation="Horizontal">
<iconPacks:PackIconMaterialDesign x:Name="MenuItemIcon" VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="12"/>
<TextBlock Text="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="Home">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Home"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="Email">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Email"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="Cloud">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Cloud"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
The attached property class as below:
public class IsOpenInfo
{
public static bool GetIsOpen(DependencyObject obj)
{
return (bool)obj.GetValue(IsOpenProperty);
}
public static void SetIsOpen(DependencyObject obj, bool value)
{
obj.SetValue(IsOpenProperty, value);
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsOpenProperty =
DependencyProperty.RegisterAttached("IsOpen", typeof(bool), typeof(IsOpenInfo), new PropertyMetadata(true));
}
I am clueless why the attached property not updating when IsChecked property is changed and style triggers not working?
Is there any simple way to achieve this?
Anyone guide me to handle this case?
Your style is defined with TargetType set to ListBox, the triggers will resolve the value of your custom local:IsOpenInfo.IsOpen property for the ListBox instance that your style is applied to.
However, the ToggleButton is defined inside the ControlTemplate of the ListBox. Its IsChecked binding will not automatically set the value of the attached property on its templated parent control. It will be set on the ToggleButton itself. So practically, you are setting the value on the ToggleButton, but you are checking it on the ListBox in the style, so you are operating on different values.
You can make it work by explicitly binding to the TemplatedParent, which is a ListBox instance. Both the style and the toggle button will resolve the attached property value for the same ListBox instance.
<ToggleButton IsChecked="{Binding (local:IsOpenInfo.IsOpen), RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
Style="{DynamicResource ToggleButtonstyle}"
Foreground="White"/>
I have a UserControl, which contains a Grid which contains a Border:
<UserControl Focusable="True" Name="uctrlScenePanel">
<Grid MouseDown="Grid_MouseDown">
<Border BorderThickness="0" BorderBrush="Black">
</Border>
</Grid>
I now wanted to change the Border-Thickness once the usercontrol "uctrlScenePanel" got Focus, but i can't get it to work and i dont really find useful Eventtrigger-Tutorials which a can understand, because i am very new to WPF.
edit:
d.moncada's answer was very helpful! my xaml now looks like this:
<Border BorderBrush="Black">
<Border.Style>
<Style TargetType="Border">
<Setter Property="BorderThickness" Value="0" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsKeyboardFocusWithin, ElementName=uctrlScenePanel}" Value="true">
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding IsKeyboardFocusWithin, ElementName=uctrlScenePanel}" Value="false">
<Setter Property="BorderThickness" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
I have still problems,because the focusing of a user control behaves weird, but thats another story...this one is solved for me, thanks for the lesson ;)
You can bind to the UserControl IsFocused property using a DataTrigger.
<UserControl Focusable="True" x:Name="uctrlScenePanel">
<Grid MouseDown="Grid_MouseDown">
<Border BorderBrush="Black">
<Broder.Style>
<Style TargetType="Border">
<Setter Property="BorderThickness" Value="1"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsFocused, ElementName=uctrlScenePanel}" Value="True">
<Setter Property="BorderThickness" Value="0"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</Grid>
</UserControl>
I have an style template for my Button control that looks like that:
<Style x:Key="myBtnStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border" Width="100" Height="25"
Padding="5,5,5,5" CornerRadius="5,5,5,5"
Background="LightGray" BorderBrush="Black"
BorderThickness="1,1,1,1">
<ContentPresenter
x:Name="cpButton"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Width="Auto" Height="Auto" Margin="-6">
</ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="border" Value="GhostWhite"></Setter>
<Setter Property="BorderBrush" TargetName="border" Value="Gainsboro"></Setter>
<Setter Property="Foreground" Value="Gray"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" TargetName="border" Value="SkyBlue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
My button instance itself:
<Button Name="btnResetCount" Content="Reset" Command="{Binding Path=CalcViewModel.ResetCounter}" Style="{StaticResource myBtnStyle}" IsEnabled="{Binding IsButtonCounterEnabled,Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
The binding for the IsEnabled Property works fine. So the IsEnabled gets set correct from my ViewModel.
But my problem is that my Styles for IsEnabled <ControlTemplate.Triggers> do not get loaded/refreshed automatically in the UI. I always have to click to any other control first. Once i clicked to another control the style of the button changes also.
What can i do to automatically update the/refresh the style of the button/any control based on the IsEnabled event?
EDIT:
Finally i got it working with an workaround. Im not happy and im sure that there are better ways. But it works.
In my ViewModel i implemented:
CommandManager.InvalidateRequerySuggested();
By calling this method the controls get refreshed.
I just call it in one of my Properties if the condition is given to enable the button..
Thanks in advance!
Create one more trigger and set the style for IsEnabled=true:
<Trigger Property="IsEnabled" Value="true">
<Setter Property="Background" TargetName="border" Value="Black"/>
<Setter Property="BorderBrush" TargetName="border" Value="Black"/>
<Setter Property="Foreground" Value="Gray"/>
</Trigger>
In my WPF app I have a datagrid. I am trying to change the colour of a cell in a datagrid based on some property value. This part is working. However the issue is the entire row has its font colour changed, I just want the one cell's font to change colour if the condition is meet.
Below is my code. I thought by putting the TargetType as a DatagridCell that it would only effect a cell not the entire row.
<!-- DataGrid Cell style -->
<Style x:Key="DG_Cell" TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border x:Name="border"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="1"
SnapsToDevicePixels="True">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding NominalDiff, Converter={StaticResource nominalPosToBool}, ConverterParameter=0}" Value="True">
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding NominalDiff, Converter={StaticResource nominalNegToBool}, ConverterParameter=0}" Value="True">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding PriceDiff, Converter={StaticResource priceToBool}, ConverterParameter=0}" Value="True">
<Setter Property="Foreground" Value="Blue"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
You should probably change the SelectionUnit property in your datagrid:
SelectionUnit="Cell"
I'd like to get rid of the grey-fading out behavior of datagrid cells (Checkboxes, Timepicker, comboboxes etc) when they have been set to disabled.
So this is what I'm trying to do:
<Style TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{x:Null}" />
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
But it doesn't work.
Do I need to define the styles individually for the controls that's actually inside the datagridcell (Checkboxes, comboboxes etc)? What's a good way of making this work?
Firstly, the fact is that the property IsEnabled hard-coded in certain control, so setting properties such as Background impossible, because the color hardcoded in the control. For example - Background in: ComboBox, TextBox, etc. Therefore, in such cases, create styles and templates, overriding the default behavior of the control (in our case: IsEnabled=False behavior).
Secondly, what control in the assigned property DataTemplate IsEnabled like this:
<DataGridTemplateColumn x:Name="ComboBoxColumn" Header="ComboBox Header" Width="110">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox IsEnabled="False" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Not to say that DataGridCell will be False, therefore, the trigger will not fire:
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Black" />
</Trigger>
</Style.Triggers>
Hence the conclusion:
Determine the behavior of the control when it is enabled false. Styles for each control can be taken from MSDN.
Example style for CheckBox (link):
<Style x:Key="{x:Type CheckBox}" TargetType="CheckBox">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="FocusVisualStyle" Value="{StaticResource CheckBoxFocusVisual}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<BulletDecorator Background="Transparent">
<BulletDecorator.Bullet>
<Border x:Name="Border" Width="13" Height="13" CornerRadius="0" Background="{StaticResource NormalBrush}" BorderThickness="1" BorderBrush="{StaticResource NormalBorderBrush}">
<Path Width="7" Height="7" x:Name="CheckMark" SnapsToDevicePixels="False" Stroke="{StaticResource GlyphBrush}" StrokeThickness="2" Data="M 0 0 L 7 7 M 0 7 L 7 0" />
</Border>
</BulletDecorator.Bullet>
<ContentPresenter Margin="4,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Left" RecognizesAccessKey="True" />
</BulletDecorator>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="false">
<Setter TargetName="CheckMark" Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsChecked" Value="{x:Null}">
<Setter TargetName="CheckMark" Property="Data" Value="M 0 7 L 7 0" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DarkBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PressedBorderBrush}" />
</Trigger>
<!-- Here set the some properties there IsEnabled will be false -->
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="Red" />
<Setter TargetName="Border" Property="BorderBrush" Value="Green" />
<Setter Property="Foreground" Value="Orange"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have defined the attached DependencyProperty for a column that shows whether it is turned off. Thereafter, each control in the template column is referenced like that:
<DataGridTemplateColumn x:Name="CheckBoxColumn" local:MyDependencyClass.IsEnabledColumn="False" Width="110" Header="CheckBox Header">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Content="My CheckBox" IsEnabled="{Binding Source={x:Reference Name=CheckBoxColumn}, Path=(local:MyDependencyClass.IsEnabledColumn)}" IsChecked="False" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Set the property IsEnabledColumn, you can set for those controls that you want to disable (IsEnabled=False).
Listing of MyDependencyClass:
public class MyDependencyClass : DependencyObject
{
public static readonly DependencyProperty IsEnabledColumnProperty;
public static void SetIsEnabledColumn(DependencyObject DepObject, bool value)
{
DepObject.SetValue(IsEnabledColumnProperty, value);
}
public static bool GetIsEnabledColumn(DependencyObject DepObject)
{
return (bool)DepObject.GetValue(IsEnabledColumnProperty);
}
static MyDependencyClass()
{
PropertyMetadata MyPropertyMetadata = new PropertyMetadata(false);
IsEnabledColumnProperty = DependencyProperty.RegisterAttached("IsEnabledColumn",
typeof(bool),
typeof(MyDependencyClass),
MyPropertyMetadata);
}
}
P.S. Don't worry about {x:Reference} warning message, it can be ignored.