WPF、MVVM 和 ComboBox:更改为不同的视图模型时,ComboBox 会将绑定到 SelectedItem 的属性清空

发布于 2024-10-22 21:28:34 字数 1033 浏览 3 评论 0原文

我有一个窗口,它使用 DataTemplates 根据其 Content 属性的类型在 ContentPresenter 中显示不同的 UserControl(视图),该属性绑定到保存当前视图模型的属性。这样,通过使用事件更改 viewmodel 属性,我可以促进我需要的基本后退/前进导航。

创建新视图模型时,它会传递对当前视图模型的引用。返回到旧的视图模型实例对于 CheckBox 控件来说效果很好,但对于我制作的包含 TextBlock 和 ComboBox 的 UserControl 来说则不然。

问题是,当包含 ComboBox 的视图被卸载时,ComboBox 的 ItemsSource 被清空,这会触发它清除其 SelectedItem/Text 属性,这些属性由于某种原因仍然绑定到我的视图模型 - 从而清除它存储的数据。我不知道如何在适当的时候手动解除它们的绑定。 (同样,复选框工作得很好。)

我读到其他用户也遇到了同样的问题。对于他们来说,更改 ItemsSource 和 SelectedItem/Text 绑定的声明顺序,以便将后者的属性放置在前者之前可以解决问题。然而,就我而言,事实并非如此。其他人也通过忽略 null/空值来解决该问题,但这在我的情况下不起作用。

我可以通过将有趣的数据复制到一个单独的对象,然后从该对象重新加载来解决这个问题,但我需要添加代码来触发重新加载数据=更多要维护的数据链接代码。

我还可以避免使用 DataTemplates 并在代码隐藏中手动添加 UserControls,这将允许我在删除 UserControl 之前中断数据绑定。但这与MVVM的观点背道而驰。

我不会修改我的非 MVVM UserControl 来处理它包含的 ComboBox 上的任何事件来解决此问题。


更新:

我已经缩小了问题的范围。我重构了代码,以便它根据已设置的视图模型手动创建并添加视图 UserControl。现在仅当我将视图 UserControl 的 DataContext 设置为 null 时才会出现此问题。如果我只是替换视图而不删除引用,它就不再删除有问题的值。这是一个可用的解决方法,还是会产生内存泄漏等问题?

I have a Window that uses DataTemplates to display a different UserControl (view) in a ContentPresenter based on the type of its Content property, which is bound to a property that holds the current viewmodel. In this way, by changing the viewmodel property with an event, I can facilitate the basic back/forward navigation I need.

When creating a new viewmodel, it is passed a reference to the current one. Going back to the old viewmodel instance works fine for a CheckBox control, but not for a UserControl I made that contains a TextBlock and a ComboBox.

The problem is that, when the view containing the ComboBox gets unloaded, the ComboBox's ItemsSource gets nulled, which triggers it to clear its SelectedItem/Text properties, which are for some reason still bound to my viewmodel--thus clearing the data it stores. I don't know how to manually unbind them at the appropriate time. (Again, the CheckBox works just fine.)

I have read that other users have had this exact same problem. For them, changing the declaration order of the ItemsSource and SelectedItem/Text bindings so that the attributes for the latter are placed before the former fixes the issue. However, in my case, it does not. Others have also fixed the issue by ignoring null/empty values, but this won't work in my case.

I could work around the issue by copying the interesting data to a separate object, and reloading it from that, but I would need to add code to trigger reloading the data = more data linkage code to maintain.

I could also avoid using DataTemplates and manually add the UserControls in the codebehind, which would allow me to break the data binding before removing the UserControl. But this runs counter to the point of MVVM.

I'm not above modifying my very non-MVVM UserControl to handle any events on the ComboBox it contains to work around this issue.


UPDATE:

I have narrowed down the issue a little bit. I refactored the code so that it manually creates and adds the view UserControl based on which viewmodel has been set. The issue now only occurs when I set the DataContext of the view UserControl to null. If I simply replace the view without removing the reference, it no longer erases the values in question. Is this a usable workaround, or does it create issues like memory leaks?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眼眸印温柔 2024-10-29 21:28:34

也许会“开放思想”以获得更简单的解决方案......如果我理解你的问题,它类似于我们过去遇到的问题。在我们的例子中,我们只是假设在通过绑定属性访问时不可能将特定值设置为 null,因此我们稍微调整了相应的 ViewModel 属性:

public MyItem SelectedItem {
  get {
    return Model.MyItem;
  }
  set {
     if (value != null) {
       // Set and notify if not null
       Model.MyItem = value;
       OnPropertyChanged("SelectedItem");
     }
     else // just notify when trying to set to null
       OnPropertyChanged("SelectedItem");
  }
}

使用此类调整后的属性,我们能够阻止任何尝试设置将值设置为 null,然后通过调用 OnPropertyChanged(..),UI 重新调用现有值。如果需要能够将值设置为null,则必须提供一个单独的属性来允许该操作。

不确定这是否适用于您的问题。
祝你好运。

更新
哦,我看到这可能描述了与“其他人也通过忽略空/空值解决了问题”相同的方法,这似乎不适用于您的情况。但我不明白为什么不应该这样做。

Maybe something that would "open mind" for a simpler solution... If I understand your problem, it's similar to a past problem we had. In our case, we simply made the assumption that it's not possible to set a specific value to null when accessed by the bound property, so we tweaked the appropriate ViewModel Properties a bit:

public MyItem SelectedItem {
  get {
    return Model.MyItem;
  }
  set {
     if (value != null) {
       // Set and notify if not null
       Model.MyItem = value;
       OnPropertyChanged("SelectedItem");
     }
     else // just notify when trying to set to null
       OnPropertyChanged("SelectedItem");
  }
}

Using such tweaked properties we were able to block any try to set the value to null, by calling OnPropertyChanged(..) insead, the existing value was recalled by the UI. If there is a need to be able to set a value to null, you have to provide a seperate property allowing that.

Not sure if this applies to your problem.
Good luck.

UPDATE
oh, I see probably this describes same method as "Others have also fixed the issue by ignoring null/empty values" which seems not to work in your case. But I dont unterstand why it shouldn't.

灯角 2024-10-29 21:28:34

这是 WPF 早期版本中由事件跳跃引起的已知错误。它针对 .NET 4.0 中的选择器派生控件进行了修复。

有关更多详细信息,请参阅此博客文章:http://blogs.interknowlogy.com/ 2011/03/09/事件-跨越式/

This is a known bug in the early versions of WPF caused by event leapfrogging. It was fixed for the Selector-derived controls in .NET 4.0.

See this blog post for more details: http://blogs.interknowlogy.com/2011/03/09/event-leapfrogging/

旧时模样 2024-10-29 21:28:34

我通过向我的基本视图模型类添加属性 Active 和相应的 Activate()/Deactivate() 方法来解决这个问题,并在交换视图模型时根据需要调用这些方法。这非常适合我的应用程序。当然,我仍然愿意接受其他建议。

I have worked around the issue by adding a property Active and corresponding Activate()/Deactivate() methods to my base viewmodel class, and calling these as appropriate when swapping out viewmodels. This fits into my application pretty well. I'm still open to other suggestions, of course.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文