【问题标题】:WPF Databinding - Getter/Setter for intermediary object not getting hitWPF 数据绑定 - 中间对象的 Getter/Setter 未命中
【发布时间】:2017-02-23 09:04:55
【问题描述】:
  1. 我的 WPF 文本框使用一个类实例(称为“SelectedDocument”)作为其数据上下文。此类实现 INOtifyPropertyChanged。
  2. SelectedDocument 实例拥有另一个类型为“CellContent”的对象(名为“Description”),通过属性公开。
  3. CellContent 还实现了 INotifyPropertyChanged。
  4. CellContent 类有一个可以绑定的字符串属性(“TextValue”)。
  5. 我将 TextBox 的 Text 属性绑定到该 TextValue 属性。像这样:

    <TextBox DataContext="{Binding SelectedDocument}" Text="{Binding Path=Description.TextValue" />
    

数据绑定没有问题 - 它可以双向工作。但是为了使该绑定起作用,WPF 可能每次都必须点击 SelectedDocument 中的 Description 属性才能检索 CellContent 对象:

public CellContent Description
{ get; set; }

(这个属性在我的代码中更复杂。)然后 WPF 可以到达实际的 CellContent 对象内部并获取/设置 TextValue。

问题: Description 属性永远不会命中。看起来 WPF 正在绕过它,并创建了与 Description 对象内的 TextValue 属性的直接连接。 我想每次都点击 Description getter 和 setter,这样我就可以在那里执行一些额外的代码。

我该怎么做?

【问题讨论】:

  • 如果没有一个好的minimal reproducible example,就不可能对正在发生的事情做出任何自信的陈述。但是很自然,WPF 将检索Description 属性值,除非该属性值实际更改。只要更改的是Description.TextValue,就只会检索TextValue 属性。鉴于此,您需要问一个不同的问题:如何解决您的任何更广泛的目标导致您出现这种错误的设计,您期望在没有理由的情况下检索一个属性值。跨度>
  • 由于我们不知道更广泛的目标是什么,我们实际上无法帮助您。到目前为止,我们所能做的就是告诉您该框架正在按预期工作,并且 您的 预期存在缺陷。
  • 这里的底层设计并没有什么神奇之处:描述曾经是一个字符串属性,我曾经直接绑定到它。该描述属性中有一些额外的代码将被执行(每次反馈数据时,文档都被标记为脏)。现在每条数据不仅仅是一个字符串,因此将所有数据封装到一个新类中并通过旧属性访问该类是有意义的。除了它不再被击中。
  • 获取属性值并不会固有地修改对象(例如文档)。 “脏”标志通常表示对象已被修改。因此,当代码获取一个属性值时设置一个“脏”标志充其量是不典型的,最坏的情况是完全错误的。最好在属性更改时修改标志。如果你有一个多层设计,文档本身应该订阅它所依赖的对象中的属性更改通知,并更新它的“脏”标志以响应 that。让您的业务逻辑依赖于 UI 逻辑的副作用是错误的。
  • “当数据绑定进入 CellContent 时,我预计中间的 getter 和 setter 会被命中(只是代码路径,忘记 NotifyPropertyChanged)” -- 请解释您期望的原因setter 被调用,当所有 WPF 需要执行它时 get 属性值。

标签: c# wpf xaml data-binding


【解决方案1】:

如果您希望在孩子的属性更改时将文档标记为脏,您可以订阅孩子的PropertyChanged 事件。

我假设您的 CurrentDocument 看起来像这样。

public class Doc
{
    public Doc()
    {
        _description = new CellContent();
       // subscribe to changes in child
        _description.PropertyChanged += DescriptionChanged; 
    }

    private void DescriptionChanged(object sender, PropertyChangedEventArgs e)
    {
        Debug.Write($"I'm a dirty dirty document. Property {e.PropertyName} has changed");
    }

    private CellContent _description;
    public CellContent Description
    {
        get
        {
            Debug.Write("I assure you this is called every time a getter of the child properties is called");
            return _description;
        }
        // If you have a setter, don't forget to -= unsubscribe and resubscribe += after changing
    }
}

【讨论】:

  • 感谢您在上面放纵我的愚蠢。我会将其标记为正确,因为...毕竟,这就是你应该这样做的方式。
【解决方案2】:

尝试在每次更改TextValue 属性时为描述引发PropertyChanged 事件。

【讨论】:

  • 嗯,我该怎么做?一切都是通过数据绑定直接从 XAML 启动的。
  • 嗯,基本上就是 NPras 所说的 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-12
  • 2011-02-26
  • 2012-11-03
相关资源
最近更新 更多