I want to change the foreground setter property using a boolean equals true.
I tried:
public bool RED = false;
if (condition)
{
RED = true;
}
and have the DataTrigger triggered by the boolean:
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Height" Value="16" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RED}" Value="True">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
But no luck. Whats the best/simplest way to write this?
You need to create a property. What you have is a field. Also, you need to implement INotifyPropertyChanged or use a DependencyProperty or other type type of property that is able to notify a WPF binding.
private bool _red;
public bool Red {
get { return _red; }
set
{
_red = value;
OnPropertychanged();
}
}
Related
Let's say I have the following class:
public class MyClass : System.Windows.FrameworkElement
{
public static readonly DependencyProperty HasFocusProperty = DependencyProperty.RegisterAttached("HasFocus", typeof(bool), typeof(MyClass), new PropertyMetadata(default(bool)));
public bool HasFocus
{
get => (bool)GetValue(HasFocusProperty);
set => SetValue(HasFocusProperty, value);
}
public System.Windows.Controls.TextBox TextBox { get; set; }
}
I want to change some UI properties of TextBox via XAML Template Trigger based on the property HasFocus, so I do the following:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:win="clr-namespace:System.Windows.Controls">
<Style TargetType="{x:Type win:TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type win:TextBox}">
<ControlTemplate.Triggers>
<Trigger Property="MyClass.HasFocus" Value="True">
<Setter TargetName="Border" Property="BorderBrush" Value="Red" />
<Setter TargetName="Border" Property="BorderThickness" Value="2" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
However, the style is not applied when setting HasFocus = true.
Within the properties of TextBox, I can see that the trigger is registered. If I change <Trigger Property="MyClass.HasFocus" Value="True"> to <Trigger Property="MyClass.HasFocus" Value="False">, my style is applied initially. So I think my XAML definition is okay.
Any ideas how to solve this?
An element in a template that is applied to a TextBox cannot bind to a property of a MyClass, unless there is a MyClass element to bind to somewhere in the visual tree.
If you want to be able to set a custom HasFocus property of a TextBox, you should create an attached property:
public class FocusExtensions
{
public static readonly DependencyProperty SetHasFocusProperty = DependencyProperty.RegisterAttached(
"HasFocus",
typeof(bool),
typeof(FocusExtensions),
new FrameworkPropertyMetadata(false)
);
public static void SetHasFocus(TextBox element, bool value)
{
element.SetValue(SetHasFocusProperty, value);
}
public static bool GetHasFocus(TextBox element)
{
return (bool)element.GetValue(SetHasFocusProperty);
}
}
It can be set for any TextBox element:
<TextBox local:FocusExtensions.HasFocus="True">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="local:FocusExtensions.HasFocus" Value="True">
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BorderThickness" Value="2" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
I have a customcontrol which render a textbox. I've also a style that set the color of the background based on some conditions as follows:
<Style x:Key="ArtParamStyle" TargetType="av:DC_Base">
<Setter Property="Background" Value="{StaticResource EditableAreaBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Info.Upd.IsAutoCalc}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Forced}" Value="True">
<Setter Property="Background" Value="LightGreen" />
</DataTrigger>
</Style.Triggers>
</Style>
Initially as the value of my textbox is autocalculated, the background is correctly red. If I also set the Forced as true (by ticking a chebckbox) I've a weird result, the border of textbox is lightgreen but background not.
It seems to be a strange color, a combination of red and lightgreen. As test, if I set the "IsAutoCalc" color as Transparent, the trigger works correctly. How can I solve this?
your code seems to be correct. But I provide you my sample:
XAML:
<Window.Resources>
<Style x:Key="ArtParamStyle" TargetType="TextBox">
<Setter Property="Background" Value="Yellow" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Bool1}" Value="True"/>
<Condition Binding="{Binding Bool2}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="Red" />
<Setter Property="BorderBrush" Value="Red" />
</MultiDataTrigger>
<DataTrigger Binding="{Binding Bool2}" Value="True">
<Setter Property="Background" Value="LightGreen" />
<Setter Property="BorderBrush" Value="LightGreen" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<TextBox Style="{StaticResource ArtParamStyle}" Height="50" Margin="4"/>
<CheckBox IsChecked="{Binding Bool1}"/>
<CheckBox IsChecked="{Binding Bool2}"/>
</StackPanel>
</Grid>
In this case I used Multidatatrigger to set red background when Bool2(your forced) is not checked.
MainWindow.cs:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChaged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
private bool bool1;
public bool Bool1
{
get { return bool1; }
set { bool1 = value; RaisePropertyChaged("Bool1"); }
}
private bool bool2;
public bool Bool2
{
get { return bool2; }
set { bool2 = value; RaisePropertyChaged("Bool2"); }
}
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
}
Probably your problem is related to your custom control.
I have a StackPanel with a few buttons. I want to change the color of a button when clicked and reset it to the original when another button in StackPanel is clicked. Is it possible with a single style applied on StackPanel or I have to create Style for each button? If yes then how.
Here is the code of Style applied to StackPanel but this changes the color of the button but does not reset it on clicking another button.
<Style TargetType="StackPanel" x:Key="GlobalStackPanelStyle" BasedOn="{StaticResource FlatStackPanel}">
<Style.Resources>
<Style TargetType="Button">
<Setter Property="Button.Background" Value="Blue"/>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)" To="Green"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
Sorry for the delayed response. Here are the steps that you can follow to get the required output.
Assuming you are following MVVM design pattern.
Create buttons in .xaml and bind command to each button as shown below,
<Button Height="32" Width="180" Grid.Column="1" Content="Button 1"
Command="{Binding ClickCommand}" CommandParameter="Button 1">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsButton1Active}" Value="True">
<Setter Property="Background" Value="Green" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
<DataTrigger Binding="{Binding IsButton1Active}" Value="False">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button Height="32" Width="180" Grid.Column="2" Content="Button 2"
Margin="5,0,0,0"
Command="{Binding ClickCommand}" CommandParameter="Button 2">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsButton2Active}" Value="True">
<Setter Property="Background" Value="Green" />
<Setter Property="Foreground" Value="White" />
</DataTrigger>
<DataTrigger Binding="{Binding IsButton2Active}" Value="False">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Note: You can add how many buttons you want to add to above xaml.
Create 2 boolean properties and set the values of those boolean properties from your ClickCommand method.
private bool isButton1Active;
private bool isButton2Active;
public bool IsButton1Active
{
get { return isButton1Active; }
set { isButton1Active = value; OnPropertyChanged(); }
}
public bool IsButton2Active
{
get { return isButton2Active; }
set { isButton2Active = value; OnPropertyChanged(); }
}
Here is code for command - Add it in your ViewModel
private UICommand _clickCommand;
public UICommand ClickCommand
{
get { return _clickCommand; }
}
Write below statement in your view model constructor
public YourViewModelConstructor()
{
_clickCommand = new UICommand(OnClick);
}
Here is the method that is bound to ClickCommand
private void OnClick(object parameter)
{
switch(parameter.ToString())
{
case "Button 1":
IsButton1Active = true;
IsButton2Active = false;
break;
case "Button 2":
IsButton2Active = true;
IsButton1Active = false;
break;
}
}
Here is the code for my UICommand class
public class UICommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<bool> _canExecute;
public UICommand(Action<object> onExecuteMethod, Func<bool> onCanExecuteMethod =
null)
{
_execute = onExecuteMethod;
_canExecute = onCanExecuteMethod;
}
public bool IsCanExecute { get; set; }
#region ICommand Members
public event EventHandler CanExecuteChanged
{
add { if (_canExecute != null) CommandManager.RequerySuggested += value; }
remove { if (_canExecute != null) CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
public bool CanExecute(object parameter)
{
IsCanExecute = (_canExecute == null || _canExecute());
return IsCanExecute;
}
#endregion
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
I assume you know on how to setting datacontext to your window.
This examples gives you an idea on how to achieve functionality by creating some properties created in your ViewModel and bind a command in your View to ViewModel Command property and invoke click command by passing Command Parameter.
Still have any doubts after implementing the solution, kindly let us know.
I have a CheckBox set up something like this:
<CheckBox Unchecked="checkBox_Unchecked">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="IsChecked" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding MyVal}" Value="{x:Null}">
<Setter Property="IsChecked" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
Is there any way to get the Unchecked event to fire when my Setter sets IsChecked = False?
This may not be a procedural approach; But for your statement, I guess I should specify that by "force"... You can make this using this work around;
1) In your ViewModel have a boolean property listening to 'INotifyPropertyChanged'
2) Let the default value of property be true;
3) In your constructor re-assign the property's value to 'false'.
4) This will trigger the unchecked event;
XAML:
<CheckBox IsChecked="{Binding CheckboxChecked}" Unchecked="ToggleButton_OnUnchecked"/>
C#:
public partial class MainWindow : INotifyPropertyChanged
{
private bool m_CheckboxChecked = true;
public bool CheckboxChecked
{
get { return m_CheckboxChecked; }
set { m_CheckboxChecked = value; OnPropertyChanged("CheckboxChecked"); }
}
public MainWindow()
{
DataContext = this;
InitializeComponent();
CheckboxChecked = false;
}
private void ToggleButton_OnUnchecked(object sender, RoutedEventArgs e)
{
Console.WriteLine("Un-Checked");
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
You need a Setter for the Case IsChecked = false too. Also I would recommend to bind to a Command in the ViewModel Try this:
<Style.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Command" Value="{Binding ElementName=this, Path=DataContext.ItemCheckedCommand}"></Setter>
</Trigger>
<Trigger Property="IsChecked" Value="false">
<Setter Property="Command" Value="{Binding ElementName=this, Path=DataContext.ItemCheckedCommand}"></Setter>
</Trigger>
</Style.Triggers>
And define a command where you have your logic in the VM:
public RelayCommand ItemCheckCommand {get; private set;}
I have a TreeView with two levels, parents and children and I would like to get the value of a selected child. I used Josh Smith's TreeView with MVVM pattern to get me started and modified the IsSelected method to get the item that is selected but I'm always getting the parent item.
static object _selectedItem = null;
......
......
public bool IsSelected
{
get { return _isSelected; }
set
{
if (value != _isSelected)
{
_isSelected = value;
this.OnPropertyChanged("IsSelected");
{
_selectedItem = this;
}
}
}
}
Snippet of my XAML:
Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
<Setter Property="FontWeight" Value="Normal"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>