将数据从代码隐藏和 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
。
怎么做?我想过构造函数注入,但仍然没有明确的想法。
这里有很多输入,但没有困难的逻辑,也没有什么会变成错误并咬你的东西。
确保 ParentViewModel
有对 ViewModelA
和 ViewModelB
的引用(据我所知你已经在那里了)。
给ViewModelA
一个SelectedRowChanged
事件:
public event EventHandler SelectedRowChanged;
给ViewModelB
一个IsMyButtonEnabled
属性(但是起个比这更好的名字;你需要名字来表明哪个 按钮指的是)
private bool _isMyButtonEnabled;
public bool IsMyButtonEnabled {
get { return _isMyButtonEnabled; }
set {
_isMyButtonEnabled = value;
OnPropertyChanged(nameof(IsMyButtonEnabled));
}
}
在 ViewB
中,将按钮的 IsEnabled
属性 绑定到那个 属性:
<Button
...
IsEnabled="{Binding IsMyButtonEnabled}"
...
同时给ViewModelA
和ViewModelB
一个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.
*/
}
}
ParentViewModel
为 ViewModelA.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
属性。这是一种更通用、更强大的做事方式。但我们可以一步一个脚印。
我有一个视图,上面有 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
。
怎么做?我想过构造函数注入,但仍然没有明确的想法。
这里有很多输入,但没有困难的逻辑,也没有什么会变成错误并咬你的东西。
确保
ParentViewModel
有对ViewModelA
和ViewModelB
的引用(据我所知你已经在那里了)。给
ViewModelA
一个SelectedRowChanged
事件:public event EventHandler SelectedRowChanged;
给
ViewModelB
一个IsMyButtonEnabled
属性(但是起个比这更好的名字;你需要名字来表明哪个 按钮指的是)private bool _isMyButtonEnabled; public bool IsMyButtonEnabled { get { return _isMyButtonEnabled; } set { _isMyButtonEnabled = value; OnPropertyChanged(nameof(IsMyButtonEnabled)); } }
在
ViewB
中,将按钮的IsEnabled
属性 绑定到那个 属性:<Button ... IsEnabled="{Binding IsMyButtonEnabled}" ...
同时给
ViewModelA
和ViewModelB
一个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. */ } }
ParentViewModel
为ViewModelA.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
属性。这是一种更通用、更强大的做事方式。但我们可以一步一个脚印。