I have a WPF application and the content of should be displayed in German and English. Therefore, I created two seperate resource dictionaries which contain string snippets in each language. It is possible to switch between the languages while the application is running. At this point I got stuck at a problem. There are some settings the user can make. If the setting was completed successfully a message shows up. The text of the message is taken from the resource dictionary. Based on a success or error message the text is displayed green or red.
<TextBlock Text="{Binding UpdateTaxPercentageSettingsMessage}" FontWeight="Bold">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding UpdateTaxPercentageSettingsMessage}" Value="{DynamicResource tax_percentage_update_went_wrong}">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding UpdateTaxPercentageSettingsMessage}" Value="{StaticResource active_tax_law_update_went_wrong}">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding UpdateTaxPercentageSettingsMessage}" Value="{StaticResource tax_percentage_was_updated_successfully}">
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding UpdateTaxPercentageSettingsMessage}" Value="{StaticResource active_tax_law_was_updated_successfully}">
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding UpdateTaxPercentageSettingsMessage}" Value="{StaticResource differential_taxation_info_update_went_wrong}">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding UpdateTaxPercentageSettingsMessage}" Value="{StaticResource differential_taxation_info_was_updated_successfully}">
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
To make switching languages possible while the application is running, the string snippets taken from the resource dictionary has to be a DynamicResource
. Unfortunately, I can not use DynamicResource
s as condition in data triggers. Has anyone faced a similar problem yet? I am grateful for your suggestions!
CodePudding user response:
Do not use triggers on localized text, neither does it work with DynamicResouce
, because Value
is not a dependency property, nor is it readable. Instead, create an enum
that describes your errors.
public enum ErrorType
{
WhoCares, // No comment on this.
ThisIsSuspicious, // Suspicous value.
ItsATrap, // Admiral Ackbar warned us.
ItIsNotWhatYouThinkItIs, // It is exactly what you think.
ItCannotBeThatSerious, // Serious Sam approves.
WhatDoesTheFlashingRedLightMean // If it is still flashing, how bad can it be, really?
}
Expose anothe property for the error and implement INotifyPropertyChanged
if necessary.
public ErrorType ErrorType { get; }
Use the property instead of your resources as Value
of the triggers.
<TextBlock Text="{Binding UpdateTaxPercentageSettingsMessage}" FontWeight="Bold">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ErrorType}" Value="{x:Static local:ErrorType.WhoCares}">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding ErrorType}" Value="{x:Static local:ErrorType.ThisIsSuspicious}">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding ErrorType}" Value="{x:Static local:ErrorType.ItsATrap}">
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding ErrorType}" Value="{x:Static local:ErrorType.ItIsNotWhatYouThinkItIs}">
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding ErrorType}" Value="{x:Static local:ErrorType.ItCannotBeThatSerious}">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding ErrorType}" Value="{x:Static local:ErrorType.WhatDoesTheFlashingRedLightMean}">
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Bonus round. As your data triggers are repetitive (they set the same values often), consider using a Binding
with a custom converter that simply says, if the bound value matches any of the given values, apply this setter.
public class IsMatchingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(parameter is IEnumerable enumerable))
return false;
return enumerable.Cast<object>().Contains(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
Create an instance of the converter in any resource dictionary in scope.
<Window.Resources>
<local:IsMatchingConverter x:Key="IsMatchingConverter"/>
</Window.Resources>
Change the data triggers and pass the target values in an array as converter parameters.
<TextBlock Text="{Binding UpdateTaxPercentageSettingsMessage}" FontWeight="Bold">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<Binding Path="ErrorType" Converter="{StaticResource IsMatchingConverter}">
<Binding.ConverterParameter>
<x:Array Type="local:ErrorType">
<local:ErrorType>WhoCares</local:ErrorType>
<local:ErrorType>ThisIsSuspicious</local:ErrorType>
<local:ErrorType>ItCannotBeThatSerious</local:ErrorType>
</x:Array>
</Binding.ConverterParameter>
</Binding>
</DataTrigger.Binding>
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Value="True">
<DataTrigger.Binding>
<Binding Path="ErrorType" Converter="{StaticResource IsMatchingConverter}">
<Binding.ConverterParameter>
<x:Array Type="local:ErrorType">
<local:ErrorType>ItsATrap</local:ErrorType>
<local:ErrorType>ItIsNotWhatYouThinkItIs</local:ErrorType>
<local:ErrorType>WhatDoesTheFlashingRedLightMean</local:ErrorType>
</x:Array>
</Binding.ConverterParameter>
</Binding>
</DataTrigger.Binding>
<Setter Property="Foreground" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>