【问题标题】:Change brushes based on ViewModel property根据 ViewModel 属性更改画笔
【发布时间】:2015-10-10 06:30:43
【问题描述】:

我有一个具有CarViewModel + view (UserControl) 的应用程序。 我想要实现的是在绑定的DataContextCar.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;

但这是View 和ViewModel 之间的紧密耦合。

我也可以通过 Messenger(来自 MVVM Light)来实现,但这会在整个应用程序中广播,似乎有点过头了。

还有其他方法吗?还是首选方式?

【问题讨论】:

    标签: c# wpf mvvm mvvm-light fody-propertychanged


    【解决方案1】:

    我会准备一些附加属性(用于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 类声明一个普通的DependencyProperty,并使用它来代替附加属性(用法相同)。

    【讨论】:

    • 感谢它的工作!真的需要使用单独的类而不是直接在 UserControl 代码中执行吗?我在尝试这样做时遇到了一些错误:stackoverflow.com/questions/33076560/…
    • @RvdK 我相信你可以这样做,但是在你的代码中,你实际上让它理解 Status 作为附加属性,但它当然不是,尝试用 views:CarView.Status 替换只是Status。
    • 如果我这样做,它会给出错误。在类型 'UserControl' 中找不到属性 'Status'"
    • @RvdK 是的,没错。它在UserControl 上查找该属性,您也可以尝试更改标签,而不是UserControl,使用您的自定义用户控件名称,不要忘记使用在您的UserControl 中定义的前缀命名空间,例如:&lt;local:CustomUserControl .... xmlns:local="..."&gt;...
    【解决方案2】:

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

    也就是说,在转换器中加载主题/资源(View 和 ViewModel 之间的有意桥梁),以便您的 View 获得所需的 Brush,而您的 ViewModel 只需公开“重要”信息(有助于决定加载什么刷子)。决策逻辑全部在转换器中。

    【讨论】:

    • 您的意思是纯 XAML 解决方案?您有任何示例代码吗?
    • 我想我有点误解了你——你想做什么?为什么要根据单个布尔值加载整个主题字典?
    • 我正在尝试设置用户控件(和内部用户控件)的样式。很多刷子需要更换。这些画笔在 Car UserControl 和子控件中使用。
    • 转换器比修改资源更可取,如果您将转换器基于值的枚举,那么您可以确保所有 Staus 值的颜色选项。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多