【问题标题】:Can I connect two ViewModels without DependencyProperty?我可以在没有 DependencyProperty 的情况下连接两个 ViewModel 吗?
【发布时间】:2019-07-11 00:48:00
【问题描述】:

我有 MainWindow(为清楚起见进行了简化):

<Window>
    <!-- (...) -->

    <Window.DataContext>
         <vm:MainWindowViewModel />
    </Window.DataContext>

    <!-- (...) -->

    <CheckBox IsChecked="{Binding ShowAdvanced}" Content="Advanced view" />
    <uc:MyUserControl DataContext={Binding MyUserControlViewModel} />
</Window>

MainWindowViewModel:

public partial class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
         MyUserControlVM = new MyUserControlViewModel();
    }

    private bool _showAdvanced;
    public bool ShowAdvanced
    {
        get => _showAdvanced;
        set { _showAdvanced = value; NotifyPropertyChanged(); }
    }

    private MyUserControlViewModel _myUserControlVM;
    public MyUserControlViewModel MyUserControlVM
    {
        get => _myUserControlVM;
        set { _myUserControlVM= value; NotifyPropertyChanged(); }
    }
}

在我的 UserControl 中,当未选中“显示高级”复选框时,我应该隐藏一些控件。

<GroupBox Header="Some advanced stuff"
    Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.(vm:MainWindowViewModel.ShowAdvanced), Converter={StaticResource BoolToVis}}">
    <!-- (...) -->
</GroupBox>

这确实有效,但我不喜欢这样,因为 UserControl 依赖于 MainWindow。

如何在没有 DependencyProperty 的情况下正确连接这些视图模型?

我已尝试将此添加到 MyUserControlViewModel:

public MyUserControlViewModel(MainWindowViewModel parent)
{
    Parent = parent;
}

private MainWindowViewModel _parent;
public MainWindowViewModel Parent
{
    get { return _parent; }
    set { _parent = value; NotifyPropertyChanged(); }
}

并在 MyUserControl 控件之一上绑定可见性,如下所示:

Visibility="{Binding Parent.ShowAdvanced}"

但这不起作用(MyUserControl 没有收到通知?)。

【问题讨论】:

  • 通常情况下,通过这样的路径绑定可以正常工作。我刚刚编写了一个超级简单的示例,它按预期更新了更改。所以你的初始化有问题,可能在某处使用了错误的视图模型实例。您需要解决您的问题,以便它包含一个良好的 minimal reproducible example 可靠地重现问题。
  • ShowAdvanced 应该是MyUserControlViewModel 的属性
  • @PeterDuniho 正如我所写 - 我在 XAML 中与 Path 的绑定有效。我想从我的视图中摆脱它(并将这种关系移动到视图模型。
  • @SirRufo:这里的重点是他的UserControl 视图模型将该属性委托给定义该属性的主视图模型类。 MyUserControlViewModel 具有Parent 属性,绑定路径应该通过该属性找到主视图模型的ShowAdvanced 属性。
  • @PeterDuniho 我知道,但我建议属性应该属于控制VM

标签: wpf mvvm parent-child viewmodel


【解决方案1】:

ShowAdvanced 属性添加到控制VM,并在为MainViewModelShowAdvanced 属性分配新值时将值分配给每个控制VM。

public class MainViewModel : Base.ViewModelBase
{
    private bool _showAdvanced;

    public MainViewModel()
    {
        MyUserControl1 = new MyUserControlViewModel { Message = "Control 1" };
        MyUserControl2 = new MyUserControlViewModel { Message = "Control 2" };
        MyUserControl3 = new MyUserControlViewModel { Message = "Control 3" };
    }

    public bool ShowAdvanced
    {
        get => _showAdvanced;
        set
        {
            this.RaiseAndSetIfChanged( ref _showAdvanced, value );
            MyUserControl1.ShowAdvanced = value;
            MyUserControl2.ShowAdvanced = value;
            MyUserControl3.ShowAdvanced = value;
        }
    }

    public MyUserControlViewModel MyUserControl1 { get; }
    public MyUserControlViewModel MyUserControl2 { get; }
    public MyUserControlViewModel MyUserControl3 { get; }
}

public class MyUserControlViewModel : Base.ViewModelBase
{
    private bool _showAdvanced;
    private string _message;

    public bool ShowAdvanced { get => _showAdvanced; set => this.RaiseAndSetIfChanged( ref _showAdvanced, value ); }
    public string Message { get => _message; set => this.RaiseAndSetIfChanged( ref _message, value ); }
}

【讨论】:

  • 谢谢。可能没有更好的方法来做到这一点。我的思绪停留在 DependencyObject 魔法上,我认为无需“手动”重写子视图模型的值是可能的。顺便说一句 - 你能展示你的 RaiseAndSetIfChanged 实现吗?它是否真的检查值是否通过某个比较器更改,或者即使您将“Abc”更改为“Abc”也只是触发一个事件?
  • 有人投票 -1... 你能解释一下这有什么问题吗?
  • @Kamil NuGet ReactiveUI.WPF ;o) - 如果发生更改,它会引发事件
  • 该死的框架。每当我学会如何很好地使用一个框架时,就会出现一个新的框架,我开始使用它,我又觉得自己像个初学者了 ;)
猜你喜欢
  • 2016-09-14
  • 1970-01-01
  • 2019-02-18
  • 1970-01-01
  • 1970-01-01
  • 2021-03-28
  • 2018-11-02
  • 2016-08-28
  • 1970-01-01
相关资源
最近更新 更多