【问题标题】:Using a dependency property with a view model to change the Fill of a Rectangle使用视图模型的依赖属性来更改矩形的填充
【发布时间】:2016-05-30 08:40:11
【问题描述】:

我有一个带有矩形的视图,并且根据一个布尔变量,我想将填充设置为特定的画笔。为此,我向 ViewModel 添加了一个 DependencyProperty。

public static readonly DependencyProperty FalseColorProperty = DependencyProperty.Register(
            "FalseColor",
            typeof(Brush),
            typeof(BooleanRectangleView),
            new FrameworkPropertyMetadata(Application.Current.FindResource("LightGreyBrush"), FrameworkPropertyMetadataOptions.AffectsRender));

public Brush FalseColor
{
    get { return (Brush)GetValue(FalseColorProperty); }
    set { SetValue(FalseColorProperty, value); }
}

在视图中,我使用以下触发器为矩形添加了一个样式

<DataTrigger Binding="{Binding DataContext.Model.Variable, RelativeSource={RelativeSource AncestorType=UserControl}}" Value="false">
                        <Setter Property="Fill" Value="{Binding DataContext.FalseColor, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</DataTrigger>

由于我在 ViewModel 中有 DependencyProperty,我不知道在创建 UserControl 时如何设置它。例如,以下不起作用

<BooleanRectangleView FalseColor="..."/>

另外,当我运行程序时,我在 ViewModel 的构造函数中得到一个异常:

默认类型与属性FalseColor的类型不匹配(翻译自德语)

编辑:

当我将 FindResource 转换为 Brush 时,我得到一个新异常:

属性FalseColor的默认值不能绑定到特定线程

我猜这与不一定从调度程序线程调用 FindResource 有关?

【问题讨论】:

  • 如果你在 ViewModel 类中放置一个 DP,这个类将是一个 DependencyObject。你不想要那个。您只需要一个引发 INotifyPropertyChanged 的​​属性。你可能写错了,它可能在你的 View 类中。关于您的问题:您需要在 Style 和 DataTrigger 中设置 FalseColor。关于您的默认值问题:您需要将 FindResource 转换为 Brush
  • @nkoniishvt:你能解释一下为什么我不希望 ViewModel 成为 DependencyObject 吗?
  • 拥有依赖属性的原因(通常)都不适用于视图模型属性。您不希望视图模型属性成为绑定的目标,或者在样式设置器中设置,或者被动画等等。
  • ViewModel 层应该为 View 提供数据显示,并允许 View 层更新 Model 层中的数据。作为一个 DependencyObject 意味着它是一个视图元素并且有很多对 ViewModel 层没有用的开销(例如,Dispatcher、属性动画,它对 ViewModel 类没有用)
  • @nkoniishvt:好的,我明白了,但是我有两个数据上下文的问题。一个用于 ViewModel,一个用于 DependencyProperty。它是如何工作的?

标签: c# wpf xaml mvvm dependency-properties


【解决方案1】:

我不明白您的结构:您说 FalseColorProperty 在 ViewModel 层中,但该类称为 BooleanRectangleView 可能应该是 View 类(UserControl 或类似名称)的名称。

在您的情况下,除了一个名为 IsVariableTrue 的布尔值之外,您的视图中还会有这个 DP。

在您的 ViewModel 中,您将拥有使 Model 中的 Variable 属性可访问的 Variable 属性。

在 BooleanRectangleView XAMl 中,您将拥有一个样式:

<Rectangle>
    <Rectangle.Style>
        <Style TargetType="{x:Type Rectangle}">
            <Setter Property="Fill" Value="{Binding RelativeSource={RelativeSource Self}, Path=Fill}"/> <!-- Binding to the Rectangle Fill property -->
            <Style.Triggers>
                <DataTrigger Property="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type BooleanRectangleView}}, Path=IsVariableTrue}" Value="False">
                    <Setter Property="Fill" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type BooleanRectangleView}}, Path=FalseColor}"/> <!-- Binding to the DP in the View -->
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Rectangle.Style>
    ...
</Rectangle>

在使用 BooleanRectangleView 的 XAML 中:

<BooleanRectangleView IsVariableTrue="{Binding Variable}"/> <!-- Binding to the ViewModel -->

关于您的 DP 声明:

public static readonly DependencyProperty FalseColorProperty = DependencyProperty.Register(
    "FalseColor",
    typeof(Brush),
    typeof(BooleanRectangleView),
    new FrameworkPropertyMetadata(
        Brush.Red, 
        FrameworkPropertyMetadataOptions.AffectsRender
    )
);

public Brush FalseColor
{
    get { return (Brush)GetValue(FalseColorProperty); }
    set { SetValue(FalseColorProperty, value); }
}

您需要在 BooleanRectangleView 的构造函数中设置 DP 值:

public BooleanRectangleView() {

    InitializeComponents();
    FalseColor = (Brush)Application.Current.FindResource("Infoteam_LightGreyBrush");
}

我确信有更好的解决方案,但它应该可以正常工作。

已编辑

将绑定的 TemplateBinding 替换为 RelativeSource,因为我们不在 ControlTemplate 中。 将触发器替换为 DataTrigger,因为 IsVariableTrue 不存在于 Rectangle 中。

【讨论】:

  • 为了正确起见,我应该把 DP 声明放在哪里?在视图中?
  • 我在Value="{TemplateBinding FalseColor}" 上收到错误FalseColor member is not valid because it does not have a qualifying type nameThe member FalseColor is not recognized or is not accessible
  • @gartenriese 是的,DP 声明应该在视图的代码隐藏中
  • 编辑了一些不起作用的东西(没有测试代码)
猜你喜欢
  • 2013-03-15
  • 2014-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-08
  • 1970-01-01
  • 2012-09-03
  • 1970-01-01
相关资源
最近更新 更多