【问题标题】:Binding to a sub-property and updating if any property in chain has changed如果链中的任何属性已更改,则绑定到子属性并更新
【发布时间】:2011-08-21 20:50:31
【问题描述】:

在学习 MVVM 时,我为我的一个视图模型创建了一个 DataTemplate

<DataTemplate DataType="{x:Type task:NodeDefinitionVM}">
    <Ellipse Width="4" Height="4" Fill="Red" >
        <Ellipse.RenderTransform>
            <TranslateTransform X="{Binding Location.X, Mode=TwoWay}"
                                Y="{Binding Location.Y, Mode=TwoWay}" />
        </Ellipse.RenderTransform>
    </Ellipse>
</DataTemplate>

简化视图模型类:

class NodeDefinitionVM : (...)
{
    public Point Location
    {
        get { return model.Location; }
        set { model.Location = value; }
    }
(...)
}

在我的例子中,模型实现了 INotifyPropertyChanged,因为我需要对模型的所有更改都反映在 View 中(注意 XAML 中的 Mode=TwoWay)。

问题: 设置了变换偏移量(X,Y)的初始值,当“Location”属性发生变化时我会收到通知。但是,没有通知 .X 已更改,并且由于我绑定到 Location.X,因此未更新转换(第一次除外),因为它需要 Location.X 更改通知。 Point 类型是一个轻量级的struct

问题:是否可以绑定到 .X,同时在 Location.X 链上的任何属性发生变化时更新绑定?有没有像Binding prop1.prop2.prop3 这样的“更长链”的通用解决方案?

【问题讨论】:

    标签: c# xaml binding


    【解决方案1】:

    通常,当链中的任何属性发生更改时,绑定应该更新。但这只有在链中的每个属性都正确引发 PropertyChanged 时才有效,因为没有办法找出其他情况发生了变化。

    为此,您需要在Point 上实现INotifyPropertyChanged 并在XY 更改时引发PropertyChanged,或者您需要在发生这种情况时引发Location 的事件.

    【讨论】:

    • 事实上,没有办法只改变 X 或 Y,因为 Location 是模型上的 ValueType 属性。所以唯一的办法就是:model.Location = new Point(...)。所以整个位置会发生变化并发出通知。现在我想问题是“TranslateTransform”,它不是 FrameworkElement(没有 DataContext)。 WPF 输出错误:“找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement”。我不知道有什么解决方法。特别是绑定最初有效。
    • 您只能更改Xmodel.Location.X = 42 应该可以工作(除非Point 是只读的,它确实应该是只读的——可变结构是坏事)。它什么时候输出那个错误?
    • LocationValueType 属性 时,你不能这样做。 model.Location 此作业的一部分将制作本地点副本。 model.Location.X = 42 将更改该副本上的 X。这甚至不会编译。
    • 运行应用程序后,VS 的输出窗口中会显示此错误。
    • @rook,不,如果Point 是可变的,它不会复制并且它会工作。
    【解决方案2】:

    奇怪的是,直接绑定到 TranslateTransform 的 X 或 Y 属性不会很好,尽管这些是 DependencyProperties。以下修改使其工作:

    <DataTemplate DataType="{x:Type task:NodeDefinitionVM}">
        <Ellipse x:Name="ellipse" Width="4" Height="4" Fill="Red" 
                 RenderTransform="{Binding TranslateMatrix}">
        </Ellipse>
    </DataTemplate>
    

    我需要在我的 ViewModel 中创建一个新的“TranslateMatrix”属性:

        public TranslateTransform TranslateMatrix
        {
            get
            {
                var tt = new TranslateTransform(model.Location.X, model.Location.Y);
                return tt;
            }
        }
    

    最后,VM 需要在每次Location 属性更改时发布TranslateMatrix 属性更改的通知。因此,VM 会监听模型更改并在必要时通知:

        void NodeDefinitionVM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Location")
                NotifyPropertyChanged(() => TranslateMatrix);
        }
    

    【讨论】:

    • 谢谢!偶然发现了您的答案,这是此页面上唯一可以解决我的问题的答案。
    【解决方案3】:

    没有办法实现你所说的,就我所知并在我的 WPF 体验中遇到的那样。

    在分配X 时,您会跳过实际属性。

    所以您需要手动通知做绑定机制属性已更改,但是如果您直接将值分配给公共 field结构?

    问候。

    【讨论】:

    • 问题是 X 和 Y 都不会被直接修改,因为它们是属性而不是字段。所以我不能做例如“model.Location.X = 数字”。位置设置为一个整体:“位置 = 新点()”。我开始相信这是关于 RenderTransform 的问题。
    猜你喜欢
    • 1970-01-01
    • 2013-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-23
    • 1970-01-01
    相关资源
    最近更新 更多