Возврат динамического ресурса из конвертера

#wpf #ivalueconverter #dynamicresource

#wpf #ivalueconverter #dynamicresource

Вопрос:

Я хочу изменить цвет элемента управления WPF в зависимости от состояния bool, в данном случае состояния флажка. Это работает нормально, пока я работаю со StaticResources:

Мой контроль

 <TextBox Name="WarnStatusBox" TextWrapping="Wrap" Style="{DynamicResource StatusTextBox}" Width="72" Height="50" Background="{Binding ElementName=WarnStatusSource, Path=IsChecked, Converter={StaticResource BoolToWarningConverter}, ConverterParameter={RelativeSource self}}">Status</TextBox>
  

Мой конвертер:

 [ValueConversion(typeof(bool), typeof(Brush))]

public class BoolToWarningConverter : IValueConverter
{
    public FrameworkElement FrameElem = new FrameworkElement();

    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {                      
        bool state = (bool)value;
        try
        {              
            if (state == true)
                return (FrameElem.TryFindResource("WarningColor") as Brush);
            else
                return (Brushes.Transparent);
        }

        catch (ResourceReferenceKeyNotFoundException)
        {
            return new SolidColorBrush(Colors.LightGray);
        }
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        return null;
    }
}
  

Проблема в том, что у меня есть несколько определений ресурса «WarningColor», зависящих от настройки дневного или ночного режима. Эти события не запускают изменение WarningColor.
Есть ли способ сделать возвращаемое значение динамическим или мне нужно переосмыслить свой дизайн?

Комментарии:

1. Не могли бы вы использовать IMultiValueConverter вместе с MultiBinding? мне кажется, что у вас есть 2 значения, которые должны инициировать изменение, а не только проверенное.

2. Да. В итоге я так и сделал. Мне пришлось добавить обработчик, чтобы перехватить событие обновления отображения для обновления наблюдаемого счетчика.

Ответ №1:

Вы не можете вернуть что-то динамическое из конвертера, но если вашим единственным условием является bool, вы можете легко заменить весь конвертер с Style помощью Triggers :

например

 <Style TargetType="TextBox">
    <Setter Property="Background" Value="Transparent" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsChecked, ElementName=WarnStatusSource}" Value="True">
            <Setter Property="Background" Value="{DynamicResource WarningColor}" />
        </DataTrigger>
    </Style.Triggers>
</Style>
  

Если теперь ресурс с этим ключом изменен, фон также должен измениться.

Ответ №2:

Способ возврата ссылки на динамический ресурс довольно прост, используя конструктор DynamicResourceExtension и предоставляя ему ключ ресурса.

Использование:

 return new DynamicResourceExtension(Provider.ForegroundBrush);
  

Определение класса поставщика должно содержать ключ:

 public static ResourceKey ForegroundBrush 
{ 
    get 
    { 
        return new ComponentResourceKey(typeof(Provider), "ForegroundBrush"); 
    } 
}
  

И значение для ключа будет объявлено в словаре ресурсов:

 <ResourceDictionary
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:theme="clr-namespace:Settings.Appearance;assembly=AppearanceSettingsProvider">

<Color x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type theme:Provider}, ResourceId=ForegroundColor}">#FF0000FF</Color>

<SolidColorBrush x:Key="{ComponentResourceKey {x:Type theme:Provider}, ForegroundBrush}" Color="{DynamicResource {ComponentResourceKey {x:Type theme:Provider}, ForegroundColor}}" />
</ResourceDictionary>
  

Таким образом, конвертер будет динамически назначать DynamicResource связанному свойству в зависимости от предоставленного ключа ресурса.

Комментарии:

1. Кроме того, использование ComponentResource необязательно. Вы можете определить DynamicResource с помощью простого строкового ключа.