根据 ViewModel 更改画笔 属性

Change brushes based on ViewModel property

我有一个包含 CarViewModel + view (UserControl) 的应用程序。 我想要实现的是当绑定的 DataContext Car.Status 改变时改变画笔的样式。

我找到了如何更改画笔(在视图后面的代码中):

private void LoadThemeResources(bool isPrepareMode)
{
    if (isPrepareMode)  
    {
        Uri themeUri = new Uri(@"/../Resources/MyBrushes.Light.xaml", UriKind.Relative);
        ResourceDictionary themeDictionary = Application.LoadComponent(themeUri) as ResourceDictionary;
        this.Resources.MergedDictionaries.Add(themeDictionary);
    }
    else
    {
        this.Resources.MergedDictionaries.Clear();
    }
}

默认情况下,应用程序和所有内容都有一个分布在多个文件中的深色主题。 MyBrushes.Light 覆盖了其中的一些。

但我不知道如何以 MVVM 友好的方式基于 ViewModel 中的 属性 更改执行 LoadThemeResources 函数。

我可以在视图后面的代码中做:

var vm = (CarViewModel) DataContext;
vm.Car.PropertyChanged += HandleStatusChanged;

但这是 ViewViewModel 之间的紧密耦合。

我也可以通过 Messenger(来自 MVVM Light)执行此操作,但这会在整个应用程序中广播,似乎有点过分了。

还有别的方法吗?或者首选方式?

您可以绑定到您的 ViewModel 上的 属性,并在您的视图中使用 IValueConverter 将 属性(无论是布尔值、状态枚举,还是其他)转换为要使用的 Brush。

也就是说,在转换器中加载 theme/resources(View 和 ViewModel 之间的故意桥梁),以便您的 View 获得它想要的 Brush,而您的 ViewModel 只需要公开 'important' 信息(帮助决定加载什么画笔的位)。决策逻辑都在转换器中。

我会准备一些附件属性(用于UserControl)。将 属性 绑定到您的视图模型,并在 属性 更改的回调中添加 LoadThemeResources 的代码逻辑,如下所示:

public static class ThemeService {
    public static DependencyProperty IsPrepareModeProperty = 
                  DependencyProperty.RegisterAttached("IsPrepareMode", typeof(bool), typeof(ThemeService), 
                  new PropertyMetadata(isPrepareModeChanged));
    public static bool GetIsPrepareMode(UserControl e){
       return (bool) e.GetValue(IsPrepareModeProperty);
    }
    public static void SetIsPrepareMode(UserControl e, bool value){
       e.SetValue(IsPrepareModeProperty, value);
    }
    static void isPrepareModeChanged(object sender, DependencyPropertyChangedEventArgs e){
       var u = sender as UserControl;
       u.LoadThemeResources((bool)e.NewValue);
    }        
}
//you need some public method of LoadThemeResources
public void LoadThemeResources(bool isPrepareMode) {
     //...
}

在XAML中的用法:

<UserControl ...
             local:ThemeService.IsPrepareMode="{Binding Car.Status}">
      <!-- ... -->
</UserControl>

您也可以为您的 UserControl 的 class 声明一个普通的 DependencyProperty 并使用它来代替附加的 属性(用法是一样的)。