【问题标题】:Hair loss and MVVM user controls脱发和 MVVM 用户控制
【发布时间】:2018-04-06 06:35:40
【问题描述】:

我有一个使用 MVVM 模式用 C# 和 WPF 编写的用户控件。

我想要做的就是在绑定的 ViewModel 中有一个属性暴露在控件之外。我希望能够绑定到它,并且我希望对属性的任何更改都能被绑定到公开值的控件之外的任何东西拾取。

这听起来很简单,但它让我拔掉了我的头发(而且剩下的不多了)。

我在用户控件中有一个依赖属性。 ViewModel 具有实现 INotifyPropertyChanged 接口的属性,并且正在正确调用 PropertyChanged 事件。

一些问题: 1)如何在不破坏 MVVM 分离的情况下获取对 ViewModel 属性的更改并将其绑定到 Dependency 属性?到目前为止,我设法做到这一点的唯一方法是在后面的 Controls 代码中分配 ViewModels PropertyChanged 事件,这绝对不是 MVVM。

2) 使用上面的软糖,我可以让 Dependency 属性启动它的 PropertyChangedCallback,但是在控件之外绑定到它的任何东西都不会接收到更改。

必须有一种简单的方法来完成所有这些工作。请注意,我没有在这里发布任何代码 - 我希望不要用我现有的代码影响答案。还有,反正你们都可能会笑吧……

罗伯

好的,澄清一下 - 代码示例:

usercontrol 后面的代码:

   public static DependencyProperty NewRepositoryRunProperty = DependencyProperty.Register("NewRepositoryRun", typeof(int?), typeof(GroupTree),
                                                                new FrameworkPropertyMetadata( null, new PropertyChangedCallback(OnNewRepositoryRunChanged)));
    public int? NewRepositoryRun
    {
        get { return (int?)GetValue(NewRepositoryRunProperty); }
        set
        {
            SetValue(NewRepositoryRunProperty, value);
        }
    }

    private static void OnNewRepositoryRunChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.OldValue != e.NewValue)
        {

        }
    }

    public GroupTree()
    {
        InitializeComponent();

        GroupTreeVM vm = new GroupTreeVM();

        this.DataContext = vm;

    }

视图模型(GroupTreeVM.cs)

   private int? _NewRepositoryRun;
    public int? NewRepositoryRun
    {
        get
        {
            return _NewRepositoryRun;
        }
        set
        {
            _NewRepositoryRun = value; 
            NotifyPropertyChanged();
        }
    }

【问题讨论】:

  • 请发布您的(相关)代码。
  • 脱发问题可能属于其他网站 - 我们有 Beauty.SE 吗?也许您的 CRT 显示器正在杀死您。请改用纸质。或者从您的帖子中编辑掉与编程无关的文本...
  • 我不知道你在说什么。 WPF 不支持或不支持头发,我在您的帖子中看不到任何 XAML 或 C# 代码。近距离投票。 -1
  • @Corcus 哦,ffs,那个。这里有一个提示:(this.Content as FrameworkElement).DataContext = this 是你能做的最愚蠢的事情。只需使用Binding.ElementName 来引用根上定义的属性。
  • 好吧,继续用锤子敲自己的头。毕竟是你的头。此外,POOF,不再有钢笔。喜欢坐下来小便。

标签: c# wpf mvvm user-controls


【解决方案1】:

现在我的每周“不要那样做”回答......

为您的 UserControl 创建 ViewModel 是一种代码味道。

由于这种气味,您遇到了这个问题,这应该表明您做错了什么。

解决方案是放弃为 UserControl 构建的 VM。如果它包含业务逻辑,则应将其移动到另一个 ViewModel 中的适当位置。

您应该将 UserControl 视为一个更复杂的控件。 TextBox 有自己的 ViewModel 吗?不会。您将 VM 的属性绑定到控件的 Text 属性,并且控件会在其 UI 中显示您的文本。

像这样考虑 MVVM 中的 UserControl——对于每个模型,您都有一个 UserControl,它旨在将模型中的数据呈现给用户。您可以在任何想要向用户展示该模型的地方使用它。它需要一个按钮吗?在您的 UserControl 上公开 ICommand 属性并让您的业务逻辑绑定到它。您的业​​务逻辑是否需要了解内部发生的事情?添加路由事件。

通常,在 WPF 中,如果您发现自己问为什么做某事会很痛苦,那是因为您不应该这样做。

【讨论】:

  • 很好的答案。我自己花了一段时间才意识到这一点。一个警告:当使用 UserControl 作为“子视图”(甚至它自己的视图)时,它自己的 VM 是有意义的。
  • 我完全同意你的看法。如果你在后面的代码中弄乱了 UI,......你做错了。
  • 一些用户控件的更多规则:如果你有依赖属性,你不应该将 DataContext 设置为 self 并且你不应该有一个用户控件的“自己的”视图模型。然后在您的用户控件中绑定到 DP 应该始终使用 Elementname 或 relativeSource。
  • @Will - 如果应用程序中的每个 View 都需要显示已登录的用户怎么办,这是否意味着应用程序中的每个 View Model 都需要一个 Username 属性以便此 UserControl 可以绑定到它?跨度>
  • @O.O 不。每个视图都应扩展具有适当属性的基本视图类。如果视图模型要求用户登录,那么所有 VM 都可以使用登录用户(并记录此类)的代码会很有帮助。你为什么要把它放在一个控件中?太牛了别傻了。
【解决方案2】:

也许我理解错了,但您似乎试图在后面的代码中使用绑定?

public MyUserControl()
{
    InitializeComponent();

    // Set your datacontext.

    var binding = new Binding("SomeVMProperty");
    binding.Source = this.DataContext;

    SetBinding(MyDependencyProperty, binding);
}

【讨论】:

    猜你喜欢
    • 2012-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-21
    • 2010-10-31
    • 2017-01-21
    • 1970-01-01
    相关资源
    最近更新 更多