I used the following code to preselect some rows in a listbox:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding f_selected, Mode=OneWay}" />
</Style>
</ListBox.ItemContainerStyle>
The value of f_selected in the code can be only true or false, but on the DB the values are y/n.
I've used a trick to convert y/n to true/false by using an object, but higher heads have asked me to work only with y/n in the objects.
Is there any way to work with a string instead of a bool or to do the conversion in the XAML or the viewmodel?
Thanks for the help and as always sorry for the bad english.
In WPF you could use a DataTrigger:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding f_selected}" Value="y">
<Setter Property="IsSelected" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
In UWP you could accomplish the same thing using a DataTriggerBehavior.
Note: mm8's answer using DataTrigger's is great if you're developing a WPF application.
In WPF and UWP, you can create a custom implementation of the IValueConverter interface to achieve this with almost the same code. Basically, it will transform your string input to a boolean depending on the rules you define.
WPF:
public class StringToBooleanConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.ToString().Equals("y");
}
// This is not really needed because you're using one way binding but it's here for completion
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if(value is bool)
{
return value ? "y" : "n";
}
}
}
UWP:
The above code is exactly the same except for the last parameter in Convert and ConvertBack methods:
public object Convert(object value, Type targetType, object parameter, string language) { }
public object ConvertBack(object value, Type targetType, object parameter, string language) { }
The following is more or less the same for both WPF and UWP. You can use the converter in XAML to convert from string to bool:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding f_selected, Mode=OneWay, Converter={StaticResource StringToBooleanConverter}}" />
</Style>
</ListBox.ItemContainerStyle>
Also, remember to introduce the converter in the beginning:
<Window.Resources>
<local:YesNoToBooleanConverter x:Key="StringToBooleanConverter" />
</Window.Resources>
Related
I set up a style for a label which should be triggered if the value of the bound filed in the underlying DataTable is greater than zero:
<c:Groesser0BooleanValueConverter x:Key="G0" />
<Style x:Key="DashboardProzent" TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource G0}}" Value="{x:Null}">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
The label itself is set up this way (a DataTemplate in a resource Dictionary):
<Label Content="{Binding percentCol}" Style="{StaticResource DashboardPrzoent}" Grid.Row="0" Grid.Column="2"/>
The converter looks like this:
public class Groesser0BooleanValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (System.Convert.ToInt32(value) > 0)
{
return true;
}
else
{
return false;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
If a run the whole thing, i get the error in the Convert method of the Groesser0BooleanValueConverter class:
Unable to cast object of type 'System.Data.DataRowView' to type
'System.IConvertible'
If I check the parameter of the Convert method of the Converter, it shows that a System.Data.DataRowView has been passed, instead of the value of the percentCol field, which I would have expected. How can I get the Label to pass the value instead of the whole row?
Update:
If I set the Label to
<Label Content="{Binding Path=percentCol}" Style="{StaticResource DashboardPrzoent}" Grid.Row="0" Grid.Column="2"/>
the error still occurs. If I disable the trigger, the value is shown (even without the Path= segment.
I don't want to state the field name in the style segment, as I would like to use it for other values to.
First I think the main problem is due to your Binding in the DataTrigger
<DataTrigger Binding="{Binding Converter={StaticResource G0}}" Value="{x:Null}">
This will pass on the direct DataContext of your Label to your Converter, which is obviously not what you want.
You should have:
<DataTrigger Binding="{Binding Converter={StaticResource G0}, Path=percentCol}" Value="False">
I also corrected the Value part, since your 'Converter' only sends back True/False. If you want to change back to Value="{x:Null}", you will have to modify your converter.
I would also advise to be safer in your Converter, otherwise the explicit conversion System.Convert.ToInt32(value) may (will...) raise an error.
I wanted to set the Binding Path and the Binding Converter in two different locations, for example a DataTemplate and a Style file.
This can be done by using {Binding Content, RelativeSource={RelativeSource Self}, Converter={StaticResource converterName}} in the Style and setting the Binding Path as usual in the DataTemplate
Converter
<Style x:Key="DashboardPrzoent" TargetType="{x:Type Label}">
...
<Style.Triggers>
<DataTrigger Binding="{Binding Content, RelativeSource={RelativeSource Self}, Converter={StaticResource G0}}" Value="True">
<Setter Property="Foreground" Value="{StaticResource Gruen}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Content, RelativeSource={RelativeSource Self}, Converter={StaticResource G0}}" Value="False">
<Setter Property="Foreground" Value="{StaticResource Rot}"/>
</DataTrigger>
</Style.Triggers>
</Style>
DataTemplate
<Label Content="{Binding Path=percentCol}" ... />
So I don't know if this is really possible, but it is worth a shot. I have two different DatagridRowStyles that I want to set in the DataGridBaseStyle Conditionally.
For example:
<Style x:Key="DataGridBaseStyle"
TargetType="sdk:DataGrid">
<Setter Property="CellStyle" Value="{StaticResource DataGridCellBaseStyle}" />
<Setter Property="ColumnHeaderStyle" Value="{StaticResource DataGridColumnHeaderBaseStyle}" />
<Setter Property="RowHeaderStyle" Value="{StaticResource DataGridRowHeaderBaseStyle}" />
<Setter Property="RowStyle" Value="{StaticResource DataGridRowBaseStyle} />
...
The property setter value of RowStyle I want to use one of two Styles depending on what "Custom Theme" I am using.
So far I tried setting it this way, but it only defaults to the normal style.
<Setter Property="RowStyle">
<Setter.Value>
<Binding>
<Binding.Converter>
<conv:DataGridRowStyleConverter/>
</Binding.Converter>
</Binding>
</Setter.Value>
</Setter>
And the same with
<Setter Property="RowStyle" Value="{StaticResource DataGridRowBaseStyle} Converter={StaticResource DataGridRowStyleConverter}" />
Converter Coding
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (ColourScheme == "Dark")
return Application.Current.Resources["DataGridRowBaseDarkStyle"] as Style;
return Application.Current.Resources["DataGridRowBaseStyle"] as Style;
}
I am kind of thinking that my converter return values are incorrect, but I also did play around with those values with no luck.
Provided that ColorScheme is a public property in the current DataContext, the Setter should look like this:
<Setter Property="RowStyle"
Value="{Binding ColorScheme, Converter={StaticResource DataGridRowStyleConverter}}"/>
or like this in XML tag syntax:
<Setter Property="RowStyle">
<Setter.Value>
<Binding Path="ColorScheme"
Converter="{StaticResource DataGridRowStyleConverter}"/>
</Setter.Value>
</Setter>
The Converter would get the current value of the ColorScheme by the value argument of the Convert method:
public object Convert(
object value, Type targetType, object parameter, CultureInfo culture)
{
return value.ToString == "Dark"
? Application.Current.Resources["DataGridRowBaseDarkStyle"] as Style
: Application.Current.Resources["DataGridRowBaseStyle"] as Style;
}
im struggling with figuring out how to check if a string contains certain characters / words and make the datatriggers go off based on that.
In my example below I would like the datatrigger to go off when there is a color in the value, and what comes after doesnt matter. The first trigger, if value contains "RED" trigger should go off no matter if it says RED Apple ,RED car, RED little ball etc.
<DataTrigger Binding="{Binding Name}" Value="RED Apple" >
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="YELLOW Lemon" >
<Setter Property="Foreground" Value="Yellow" />
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="GREEN Pear" >
<Setter Property="Foreground" Value="Green" />
</DataTrigger>
How can I achieve this
Create a Converter
public class ColorConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
return ((string)value.Contains("Color");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
Then use the following XAML.
<Window.Resources>
<myNamespace:ColorConverter x:Key="ColorConverter" Color="red" />
</Window.Resources>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Color,
Converter={StaticResource ColorConverter}}">
<DataTrigger.Value>true</DataTrigger.Value>
<Setter TargetName="Color" Property="Foreground" Value="Red"/>
</DataTrigger>
</DataTemplate.Triggers>
I have a ToggleButton being a standard WPF class and I want to bind IsChecked to a property status of my model and the Status can have more than 2 values: Status1, Status2, Status3, Status4. The type of Status is SomeThirdPartyClassStatus and I don't have access to its source code.
<ToggleButton IsChecked="{Binding Status???}" />
So how can I bind Status to IsChecked then? I prefer a xaml solution.
I want to bind IsChecked property so that it's True when the Status is equal to Status1, and it's false in other cases. I prefer not to write any code in a *.cs file, but only xaml code.
As an alternative you can use pure XAML solution with DataTrigger. Assuming that you have something like
public enum SomeThirdPartyClassStatus {
Status1,
Status2,
Status3,
Status4
}
you can do
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="IsChecked" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="{x:Static local:SomeThirdPartyClassStatus.Status1}">
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Where local is namespace for SomeThirdPartyClassStatus like
xmlns:local="clr-namespace:WpfApplication1"
Caveat is that it will work one-way only
EDIT
For two-way binding you'll need custom IValueConverter
public class EnumConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (SomeThirdPartyClassStatus)value == SomeThirdPartyClassStatus.Status1;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool?)value == true ? SomeThirdPartyClassStatus.Status1 : SomeThirdPartyClassStatus.Status2;
}
}
and then the binding would look like
<ToggleButton IsChecked="{Binding Path=Status, Converter={StaticResource EnumConverter}}"/>
Create a class derived from IValueConverter which you apply to your binding.
https://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter(v=vs.110).aspx
Update:
Simply use this style for toggle button
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="Status1" >
<Setter Property="IsChecked" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
So if ever Status has value Status1 toggle button will be checked.
I have custom control in wpf which change his look based on one Property:
...
<Grid>
<Rectangle Fill="[Something]" />
</Grid>
In code i have the property AlarmLevel, when AlarmLevel is bigger than 5 I want the fill to be red, otherwise blue.
How can I do this. (I don't want the fill property to be exposed)
Tnx
Since you're basing your fill value on an inequality, you could do this a couple of ways.
The recommended way is probably to use a converter on your binding to make it into a boolean value. Then use a data trigger to set the fill value based on whether the value is true or false, like so:
<Rectangle>
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<DataTrigger Binding="{Binding AlarmLevel, Converter={StaticResource AlarmLevelConverter}}" Value="True">
<Setter Property="Fill">
<Setter.Value>
<SolidColorBrush Color="Red" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding AlarmLevel, Converter={StaticResource AlarmLevelConverter}}" Value="False">
<Setter Property="Fill">
<Setter.Value>
<SolidColorBrush Color="Black" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
Your converter could look something like (perhaps with more exception handling):
public class AlarmLevelConverter: IValueConverter {
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return ((int)(value) > 5);
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotSupportedException();
}
}
Don't forget you'll need to add a reference to the converter class as a resource on your user control:
If you wanted to forego the converter method, you could also create a "helper" boolean property in your data context called something like "IsAlarming". It would look something like:
public bool IsAlarming {
get { return AlarmLevel > 5; }
}
You would then bind your data trigger to IsAlarming rather than AlarmLevel. This isn't recommended though, because it's not pure MVVM.