将数据从代码隐藏和 ViewModel 传递到另一个 ViewModel

Pass data from code behind and ViewModel to another ViewModel

我有一个视图,上面有 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 的代码后面,我有一个事件要 select 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

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

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

  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。但通常,您希望 child 视图模型比这更松散耦合。您不希望 B depend 拥有 A 类型的兄弟姐妹。但是 parent already 取决于拥有这两个child仁。一分钱,一英镑。你不能再弄湿了。

    ...
    //  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;
    }
    

您确实 "should" 使用命令执行按钮操作,并启用命令而不是使用 Is*ButtonEnabled 属性。这是一种更通用、更强大的做事方式。但我们可以一步一个脚印。