【问题标题】:Pass data from code behind and ViewModel to another ViewModel将数据从后面的代码和 ViewModel 传递到另一个 ViewModel
【发布时间】:2016-07-29 17:44:49
【问题描述】:

我有一个视图,上面有 2 个子视图,每个视图都分配了一个 ViewModel:

ViewParent - ViewModelParent
{ 
   ViewA - ViewModelA
   ViewB - ViewModelB
}

ViewParent 结构如下所示。

<StackPanel Orientation="Vertical">
    <local:AView DataContext="{Binding ViewModelA, Mode=TwoWay}"></localViews:AView>
</StackPanel>
<StackPanel Orientation="Vertical">
    <localViews:BView DataContext="{Binding ViewModelB, Mode=TwoWay}"></localViews:BView>
</StackPanel>

现在在ViewA 后面的代码中,我有一个事件来选择gridview 中的一行。

  private void radGridView_SelectionChanged(object sender, SelectionChangeEventArgs e)
    {
        try
        {
            RadGridView grv = sender as RadGridView;                       

            if (e.AddedItems.Count > 0)
            {
               var row = grv.SelectedItem as SomeClass;
               if(condition)
                  // Enable a button in ViewB.

我想要的是将row 传递给ViewModelB。另外,我想在 ViewB 中启用一个按钮。最后我想从ViewModelA 传递几个整数到ViewModelB

怎么做?我想过构造函数注入,但仍然没有明确的想法。

【问题讨论】:

  • ViewModelParent 应该有对每个子虚拟机的引用,对吧?所以给 vmA 一个 SelectedRow 属性,带有PropertyChanged,并在 ViewA 中绑定它。给 vmA 一个 SelectedRowChanged 事件。选定的行更改时会提高它。 ViewModelParent 在创建 vmA 时为该事件设置处理程序,并在处理程序中设置 vmB 上的属性,如 bool CanDoWhateverCanDoWhatever 启用按钮绑定的命令,并看到该命令的 CanExecuteChanged 事件已引发。
  • @EdPlunkett,是的。 ViewModelParent 确实有对每个子虚拟机的引用。并且 VmA 已经有一个带有 PropertyChanged 的 SelectedItem 属性。我不确定我能在 VmB 中做的其他事情。
  • 使用您拥有的工具做任何事情。也许给 vmB 一个属性bool IsMyPuppyDogButtonEnabled { get; set; },它会引发 PropertyChanged。让父 vm 在 XAML IsEnabled="{Binding IsMyPuppyDogButtonEnabled}" 中的 Button 上适当地设置该属性。有一百万种方法可以做到这一点。底线:视图模型管理它们之间的状态。视图坐在那里观察其视图模型的属性,并响应这些属性的变化。
  • @EdPlunkett,我看到了关于绑定按钮属性的信息。对于 SelectedRow 属性,如何将其传递给 ViewModelB?使用构造函数?

标签: xaml mvvm viewmodel


【解决方案1】:

这里有很多输入,但没有困难的逻辑,也没有什么会变成错误并咬你。

  1. 确保ParentViewModel 有对ViewModelAViewModelB 的引用(据我了解,您已经在那里了)。

  2. ViewModelA一个SelectedRowChanged事件:

    public event EventHandler SelectedRowChanged;
    
  3. ViewModelB 一个IsMyButtonEnabled 属性(但命名它比这更好;您需要名称来表明它所指的哪个按钮)

    private bool _isMyButtonEnabled;
    public bool IsMyButtonEnabled {
        get { return _isMyButtonEnabled; }
        set { 
            _isMyButtonEnabled = value;
            OnPropertyChanged(nameof(IsMyButtonEnabled));
        }
    }
    
  4. ViewB 中,将按钮的IsEnabled 属性绑定到该属性:

    <Button
        ...
        IsEnabled="{Binding IsMyButtonEnabled}"
        ...
    
  5. ViewModelAViewModelB 一个SelectedRow 属性。

    private SomeClass _selectedRow;
    public SomeClass SelectedRow {
        get { return _selectedRow; }
        set { 
            _selectedRow = value;
            OnPropertyChanged(nameof(SelectedRow));
            /*
                DO ADDITIONAL STUFF HERE:
    
                VMA: 
                    SelectedRowChanged?.Invoke(this, EventArgs.Empty);
    
                VMB:
                    Set IsMyButtonEnabled to whatever is appropriate based on
                    the selected row. 
             */
        }
    }
    
  6. ParentViewModelViewModelA.SelectedRowChanged 设置一个处理程序,因为它引用了ViewModelA 的实例,所以它可以这样做。然后处理程序告诉ViewModelB 在 SelectedRow 更改时做任何需要做的事情。另一种方法是为ViewModelB 提供对ViewModelA 的引用,并让它处理ViewModelA.SelectedRowChanged。但通常,您希望您的子视图模型比这更松散耦合。您不希望 B 依赖 拥有 A 类型的兄弟姐妹。但是父母 已经 依赖于拥有这两个孩子。一分钱,一磅。你不能再湿了。

    ...
    //  Constructor or someplace
    this.VMA = new ViewModelA();
    this.VMA.SelectedRowChanged += ViewModelA_SelectedRowChanged;
    ...
    
    void ViewModelA_SelectedRowChanged(Object sender, EventArgs e)
    {
        //  VMB.SelectedItem's setter will enable the button appropriately
        VMB.SelectedItem = VMA.SelectedItem;
    }
    

您真的“应该”使用命令来执行按钮操作,并启用命令而不是拥有Is*ButtonEnabled 属性。这是一种更通用、更强大的做事方式。但是我们可以一步一步来。

【讨论】:

  • 在第 6 步中,是不是拼写错误? VMB.SelectedItem = VMB.SelectedItem;。除了两个地方的 SelectedItem 外,我了解其中的大多数。
  • @Bigeyes 当然是一个错字。谢谢。修复。 SelectedItem 属性 匹配 - 有一部分不同,我将其放在注释块中(“DO ADDITIONAL STUFF HERE”)解释两个 A/B vm 类中的每一个如何添加其自己的特殊代码。
  • 问题是 ViewB 中的按钮仍然被禁用,即使我在 SelectedItem 属性块(ViewB)的设置器部分将其设置为 true。顺便说一句,我在 ViewA 的代码后面而不是 ViewModelA.cs 中调用行更改事件。不确定是否是原因。我看到您将 selectedItem 更改事件放在 ViewModelA 的 setter 部分。但我必须把它放在类后面的代码中。
  • 我的错,对不起。我发现错误。在委托命令CanExecuteTrue 中,我将其设置为假。我没有注意它。现在它成功了。 ;-)
猜你喜欢
  • 2022-11-25
  • 1970-01-01
  • 2021-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
相关资源
最近更新 更多