Data Trigger conditions check in WPF - c#

If any possible to give condition on DataTrigger?
<DataTrigger Binding="{Binding MessageBoxImage}" Value="{x:Static MessageBoxImage.Error}">
<Setter Property="Source" Value="../Images/Error48.png"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding MessageBoxImage}" Value="{x:Static MessageBoxImage.Hand}">
<Setter Property="Source" Value="../Images/Error48.png"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding MessageBoxImage}" Value="{x:Static MessageBoxImage.Stop}">
<Setter Property="Source" Value="../Images/Error48.png"></Setter>
</DataTrigger>
So, this is my Xaml code, in that Error,Hand,Stop all are setting same image
My question is any possible to give OR condition for these three values? (or one line statement)
Thanks,

You can use MultiDataTrigger for AND condition. As for OR condition you can use converter.
<Window.Resources>
<someNs:ORConverter x:Key = "ORConverter"/>
</Window.Resources>
....
<DataTrigger Value="True">
<DataTrigger.Binding>
<Binding Path="MessageBoxImage" Converter="{StaticResource ORConverter}">
<Binding.ConverterParameter>
<x:Array Type="MessageBoxImage">
<x:Static MemberType="MessageBoxImage" Member="Error" />
<x:Static MemberType="MessageBoxImage" Member="Information" />
<x:Static MemberType="MessageBoxImage" Member="Question" />
</x:Array>
</Binding.ConverterParameter>
</Binding>
</DataTrigger.Binding>
<Setter Property="Source" Value="../Images/Error48.png"></Setter>
</DataTrigger>
And the converter's code:
public class ORConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
var list = parameter as IList;
if (list == null)
return false;
foreach (var o in list)
{
if (Equals(o, value))
return true;
}
return false;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("Cannot convert back");
}
}

With the simple DataTrigger is meant to check for a single values. if Possible you could use the Multi-DataTrigger to check the multiple conditions.

Related

Update DataGrid styling on key press

I have a DataGrid that styles the background of rows based on if the row is listed as "to delete".
The rows change colour when loading into the table and when scrolling around, but do not immediately change.
I use "ctrl+del" to mark the selected rows for deletion.
How can I get the row to update on this keypress?
DataGrid Implementation
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="WhiteSmoke" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="LightGray" />
</Trigger>
<DataTrigger Value="True">
<DataTrigger.Binding>
<Binding>
<Binding.Converter>
<local:IsDeletedConverter/>
</Binding.Converter>
</Binding>
</DataTrigger.Binding>
<DataTrigger.Setters>
<Setter Property="Background" Value="OrangeRed"/>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
<Setter Property="Background">
<Setter.Value>
<Binding Path="">
<Binding.Converter>
<local:ValueToBrushConverter/>
</Binding.Converter>
</Binding>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
Converter
public class IsDeletedConverter : IValueConverter
{
public object Convert(object values, Type targetType, object parameter, CultureInfo culture)
{
if (values is ExpandoObject eo)
{
if ((Application.Current.MainWindow as MainWindow).LoadedTable.ToDelete.Contains((int)ExpandoUtils.GetExpandoProperty(eo, "id")))
return true;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

WPF - TextBox won't respond to PropertyChanged in multibinding

I have a textbox that should show hex value of a color. App can be in two states:
1) In edit mode (IsEdit==true) textbox binds to my model property and
2) when is not in edit mode (IsEdit==false) textbox binds to slider
representing RGB colors. Changing each color value with slider, hex value in textbox also changes and vice versa. Textbox is also binded to my model property so that I could save changes later.
Problem: When app is in edit mode changing textbox text property manually triggers converter and sends text value to model and sliders but when I change sliders, textbox text is changing but it doesn’t send data to model. Why?! I’ve tried everything I could think of. Changing binding mode, notifyontargetupdated… It should work… Can someone please explain.
I tried to simplify so if I missed anything important please let me know.
XAML code:
<Rectangle Grid.Column="0" Width="120" Height="120" Stroke="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,0,0" Fill="{Binding ElementName=tbxHexColor, Path=Text, Converter={StaticResource HexToColorConverter}}"/>
<TextBox x:Name="tbxHexColor" CharacterCasing="Upper">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEdit}" Value="False">
<Setter Property="Text" Value="{Binding SelectedColor.RGBHex}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsEdit}" Value="True">
<Setter Property="Text">
<Setter.Value>
<MultiBinding Converter="{StaticResource SlidersToHexConverter}" UpdateSourceTrigger="PropertyChanged">
<Binding ElementName="sliderRed" Path="Value"/>
<Binding ElementName="sliderGreen" Path="Value"/>
<Binding ElementName="sliderBlue" Path="Value"/>
<Binding Path="RGBHelper"/>
</MultiBinding>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Slider x:Name="sliderRed" Grid.Column="1" Grid.Row="0" Margin="0,5,0,3" Maximum="255">
<Slider.Style>
<Style TargetType="Slider">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEdit}" Value="False">
<Setter Property="Value" Value="{Binding SelectedColor.RGBHex, Converter={StaticResource HexToRGBConverter}, ConverterParameter=red, FallbackValue=0}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsEdit}" Value="True">
<Setter Property="Value" Value="{Binding SelectedColor.RGBHex, Converter={StaticResource HexToRGBConverter}, ConverterParameter=red, Mode=OneTime}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Slider.Style>
</Slider>
<Slider x:Name="sliderGreen" Grid.Column="1" Grid.Row="1" Margin="0,3" Maximum="255">
<Slider.Style>
<Style TargetType="Slider">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEdit}" Value="False">
<Setter Property="Value" Value="{Binding SelectedColor.RGBHex, Converter={StaticResource HexToRGBConverter}, ConverterParameter=green, FallbackValue=0}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsEdit}" Value="True">
<Setter Property="Value" Value="{Binding SelectedColor.RGBHex, Converter={StaticResource HexToRGBConverter}, ConverterParameter=green, Mode=OneTime}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Slider.Style>
</Slider>
<Slider x:Name="sliderBlue" Grid.Column="1" Grid.Row="2" Margin="0,3" Maximum="255">
<Slider.Style>
<Style TargetType="Slider">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEdit}" Value="False">
<Setter Property="Value" Value="{Binding SelectedColor.RGBHex, Converter={StaticResource HexToRGBConverter}, ConverterParameter=blue, FallbackValue=0}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsEdit}" Value="True">
<Setter Property="Value" Value="{Binding SelectedColor.RGBHex, Converter={StaticResource HexToRGBConverter}, ConverterParameter=blue, Mode=OneTime}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Slider.Style>
</Slider>
Converters:
public class HexToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string input = "#" + value as string;
if (string.IsNullOrEmpty(input) || input == "#" || input.Length < 7)
{
input = "#00FFFFFF";
}
return new SolidColorBrush((Color)ColorConverter.ConvertFromString(input));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class SlidersToHexConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string hex = "";
for (int i = 0; i < 3; i++)
{
int itemInt = System.Convert.ToInt32(values[i]);
if (itemInt != 0)
{
string a = itemInt.ToString("X");
if (a.Length == 1)
{
hex += "0" + a;
}
else
{
hex += a;
}
}
else
{
hex += "00";
}
}
return hex;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
object[] sliderValues = new object[4] { 0, 0, 0, "" };
if (value.ToString().Length == 6)
{
string r = value.ToString().Substring(0, 2);
string g = value.ToString().Substring(2, 2);
string b = value.ToString().Substring(4, 2);
double rr = int.Parse(r, NumberStyles.HexNumber);
double gg = int.Parse(g, NumberStyles.HexNumber);
double bb = int.Parse(b, NumberStyles.HexNumber);
sliderValues[0] = (object)rr;
sliderValues[1] = (object)gg;
sliderValues[2] = (object)bb;
}
sliderValues[3] = value.ToString();
return sliderValues;
}
}
public class HexToRGBConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return 0;
}
string hex = value.ToString();
string colorHex = "0";
switch (parameter.ToString())
{
case "red":
colorHex = hex.Substring(0, 2);
break;
case "green":
colorHex = hex.Substring(2, 2);
break;
case "blue":
colorHex = hex.Substring(4, 2);
break;
default:
break;
}
return int.Parse(colorHex, NumberStyles.HexNumber);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Tried everything in MultiBinding part of XAML. Changing: NotifyOnSourceUpdated, NotifyOnTargetUpdated, Mode, UpdateSourceTrigger... Nothing works.

Cant set Style in Trigger wpf

i want to change style when toggle button checked
<ToggleButton.Style>
<Style TargetType="ToggleButton" BasedOn="{StaticResource ToggleButtonPrimary}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ButtonNude, Path=IsChecked}" Value="True">
<Setter Property="Style" Value="{StaticResource ToggleButtonDanger}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
but my code not work and app crash
As suggested by #clemens , the right way would be to have template and apply in controlTemplate with TargetName
There is one more (may be ugly) way:
On view:
<StackPanel>
<StackPanel.Resources>
<local:Myconverter x:Key="MyConverter" />
<Style TargetType="ToggleButton" x:Key="ToggleButtonPrimary">
<Setter Property="Background" Value="blue" />
</Style>
<Style TargetType="ToggleButton" x:Key="ToggleButtonDanger">
<Setter Property="Background" Value="Red" />
</Style>
</StackPanel.Resources>
<CheckBox Margin="20" x:Name="chk" />
<ToggleButton Width="100" Height="100" >
<ToggleButton.Style>
<MultiBinding Converter="{StaticResource MyConverter}">
<MultiBinding.Bindings>
<Binding ElementName="chk" Path="IsChecked"/>
<Binding RelativeSource="{RelativeSource AncestorType=StackPanel}"/>
</MultiBinding.Bindings>
</MultiBinding>
</ToggleButton.Style>
</ToggleButton>
</StackPanel>
Converter:
public class Myconverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)values[0])
{
return (values[1] as FrameworkElement).Resources["ToggleButtonDanger"];
}
else
return (values[1] as FrameworkElement).Resources["ToggleButtonPrimary"];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Hope that helps.

Converter doesn't seem to fire at all times on mouse over

<Style TargetType="{x:Type dxg:GroupColumnSummaryControl}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<Binding Converter="{StaticResource c}"/>
</Setter.Value>
</Setter>
</Trigger>.
Whats wrong with this code here. my convertor doesnt seem to fire when i do a mouse over.
If i remove the convertor and assign the value as Red i can see the color.
this works perfectly fine
<Style TargetType="{x:Type dxg:GroupColumnSummaryControl}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red">
</Setter>
</Trigger>
This works for me: (I used RichTextBox)
<Window.Resources>
<my:ColorConverter x:Key="colorConverter" />
<Style TargetType="RichTextBox">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<Binding Converter="{StaticResource colorConverter}"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
This is the converter:
public class ColorConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return new SolidColorBrush(Colors.Red);
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return null;
}
}

How To Dynamically Change a Row's Style Based On Row Data?

How does one style a specific row or rows in a WPF Datagrid during runtime? Each change depends on some values of the shown data?
I can't tell from your question whether you are adding columns to your grid at run time, but either way you can add a CellStyle to the grid at design time that handles your specific styling needs using DataTriggers.
For instance, the following would make all rows red where the Name property = "Billy Bob":
<DataGrid AutoGenerateColumns="True" Name="dataGrid1">
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Binding="{Binding Name}" Value="Billy Bob" >
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
If you are adding columns programmatically at run time and you want to apply a certain style to them, you can still define those styles at design time in your xaml.
<DataGrid AutoGenerateColumns="False" Name="dataGrid1">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}" x:Key="MyCellStyle">
<Setter Property="Foreground" Value="Green"/>
</Style>
</DataGrid.Resources>
...
Then when you are adding the columns you can apply that style to them:
col.CellStyle = (Style)dataGrid1.Resources("MyCellStyle");
Update
If you have a list of songs and you want to change the row color of every song that has an artist whose name starts with an "a", then you could use an IValueConverter.
The following converter would do the trick:
public class ArtistNameConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
try
{
return value.ToString().StartsWith(parameter.ToString());
}
catch
{
return false;
}
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then you could use the converter in your xaml like so:
<DataGrid AutoGenerateColumns="True" Name="dataGrid1">
<DataGrid.Resources>
<converters:ArtistNameConverter x:Key="ArtistNameConverter"></converters:ArtistNameConverter>
</DataGrid.Resources>
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Binding="{Binding ArtistName, Converter={StaticResource ArtistNameConverter}, ConverterParameter=a}" Value="True" >
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
Notice how I am passing an "a" into the converter as the parameter. You can pass in whatever letter you want, and the rows that have artists that start with that letter will have their background color set to red.
Update 2
If you want to pass in a variable of some sort to the converter, you can use MultiBinding.
The Converter would look like this:
public class ArtistNameConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
try
{
return values[0].ToString().StartsWith(values[1].ToString());
}
catch
{
return false;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
The first parameter passed in is the artist name, the second is the letter.
And you would use it in your grid like this:
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Value="True" >
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource ArtistNameConverter}">
<Binding Path="ArtistName" />
<Binding Mode="OneWay" ElementName="FirstLetter" Path="Text" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
In this example, the first letter is coming from the "Text" property of a control called "FirstLetter". You can change that binding to whatever you want.

Categories