如何从子视图模型绑定到父视图模型中的事件
How to bind to event in parent viewmodel from child viewmodel
我目前正在按照 this 指南设置带复选框的 TreeView。在我的代码中,树 "FooViewModel" 在我的 MainViewModel 中启动并作为 ItemsSource 绑定到 TreeView。我希望能够订阅 MainViewModel 中的某个事件,该事件将在选中或取消选中某些内容时触发。这样我就可以遍历 "FooViewModel" 并检查哪些节点具有 IsChecked = True。如何创建此事件绑定?
这是我的代码:
<Style x:Key="TreeViewItemStyle" TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="False" />
<Setter Property="IsSelected" Value="{Binding IsInitiallySelected, Mode=OneTime}" />
<Setter Property="KeyboardNavigation.AcceptsReturn" Value="True" />
<Setter Property="xn:VirtualToggleButton.IsVirtualToggleButton" Value="True" />
<Setter Property="xn:VirtualToggleButton.IsChecked" Value="{Binding IsChecked}" />
<Setter Property="Focusable" Value="False" />
</Style>
<xn:TreeView ItemsSource="{Binding CollectionFooViewModel}" ItemContainerStyle="{StaticResource TreeViewItemStyle}">
<xn:TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children, Mode=OneTime}">
<StackPanel Orientation="Horizontal">
<CheckBox Focusable="False" IsChecked="{Binding IsChecked}" VerticalAlignment="Center"/>
<ContentPresenter Content="{Binding Name, Mode=OneTime}" Margin="2,0"/>
</StackPanel>
</HierarchicalDataTemplate>
</xn:TreeView.ItemTemplate>
</xn:TreeView>
我想如果有办法将 "IsChecked" 绑定到两个属性(一个在 FooViewModel 中,另一个在 MainViewModel 中)我会得到我的答案。
尝试在 setter 中为您的模型添加 "OnPropertyEventChanged" 方法调用,这里是我的意思的示例:
https://msdn.microsoft.com/en-us/library/ms743695%28v=vs.110%29.aspx
有很多方法可以实现。一个是某种 pub/sub(消息传递)实现,或者可能只是一堆 Action
代表?像...
主窗口
<Window x:Class="WpfApplication1.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="300"
Width="250">
<TreeView ItemsSource="{Binding CollectionFooViewModel}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children, Mode=OneTime}">
<StackPanel Orientation="Horizontal">
<CheckBox Focusable="False"
IsChecked="{Binding IsChecked}"
VerticalAlignment="Center"/>
<ContentPresenter Content="{Binding Name, Mode=OneTime}"
Margin="2,0"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Window>
DataContext
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
Action<MyItem> action = item => Console.WriteLine(@"MyItem was clicked");
CollectionFooViewModel = new ObservableCollection<MyItem>()
{
new MyItem()
{
Name = "MyItem1",
Children = new List<MyItem>()
{
new MyItem()
{
Name = "MySubItem1",
IsChecked = false,
Action = item => Console.WriteLine(@"{0} invoked action", item.Name)
},
new MyItem()
{
Name = "MySubItem2",
IsChecked = true,
Action = item => Console.WriteLine(@"{0} state is {1} ", item.Name, item.IsChecked)
},
},
Action = action
}
};
}
public ObservableCollection<MyItem> CollectionFooViewModel { get; set; }
}
public class MyItem : ViewModelBase
{
private bool _isChecked;
public string Name { get; set; }
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
if (Action != null)
Action.BeginInvoke(this, null, null);
}
}
public IEnumerable<MyItem> Children { get; set; }
public Action<MyItem> Action { get; set; }
}
这给你以下...
...并在按顺序单击时将其吐出到控制台。
MyItem was clicked
MySubItem1 invoked action
MySubItem2 state is False
当然,在您的情况下,您可能希望将具体方法传递给委托。
我目前正在按照 this 指南设置带复选框的 TreeView。在我的代码中,树 "FooViewModel" 在我的 MainViewModel 中启动并作为 ItemsSource 绑定到 TreeView。我希望能够订阅 MainViewModel 中的某个事件,该事件将在选中或取消选中某些内容时触发。这样我就可以遍历 "FooViewModel" 并检查哪些节点具有 IsChecked = True。如何创建此事件绑定?
这是我的代码:
<Style x:Key="TreeViewItemStyle" TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="False" />
<Setter Property="IsSelected" Value="{Binding IsInitiallySelected, Mode=OneTime}" />
<Setter Property="KeyboardNavigation.AcceptsReturn" Value="True" />
<Setter Property="xn:VirtualToggleButton.IsVirtualToggleButton" Value="True" />
<Setter Property="xn:VirtualToggleButton.IsChecked" Value="{Binding IsChecked}" />
<Setter Property="Focusable" Value="False" />
</Style>
<xn:TreeView ItemsSource="{Binding CollectionFooViewModel}" ItemContainerStyle="{StaticResource TreeViewItemStyle}">
<xn:TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children, Mode=OneTime}">
<StackPanel Orientation="Horizontal">
<CheckBox Focusable="False" IsChecked="{Binding IsChecked}" VerticalAlignment="Center"/>
<ContentPresenter Content="{Binding Name, Mode=OneTime}" Margin="2,0"/>
</StackPanel>
</HierarchicalDataTemplate>
</xn:TreeView.ItemTemplate>
</xn:TreeView>
我想如果有办法将 "IsChecked" 绑定到两个属性(一个在 FooViewModel 中,另一个在 MainViewModel 中)我会得到我的答案。
尝试在 setter 中为您的模型添加 "OnPropertyEventChanged" 方法调用,这里是我的意思的示例:
https://msdn.microsoft.com/en-us/library/ms743695%28v=vs.110%29.aspx
有很多方法可以实现。一个是某种 pub/sub(消息传递)实现,或者可能只是一堆 Action
代表?像...
主窗口
<Window x:Class="WpfApplication1.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="300"
Width="250">
<TreeView ItemsSource="{Binding CollectionFooViewModel}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children, Mode=OneTime}">
<StackPanel Orientation="Horizontal">
<CheckBox Focusable="False"
IsChecked="{Binding IsChecked}"
VerticalAlignment="Center"/>
<ContentPresenter Content="{Binding Name, Mode=OneTime}"
Margin="2,0"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Window>
DataContext
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
Action<MyItem> action = item => Console.WriteLine(@"MyItem was clicked");
CollectionFooViewModel = new ObservableCollection<MyItem>()
{
new MyItem()
{
Name = "MyItem1",
Children = new List<MyItem>()
{
new MyItem()
{
Name = "MySubItem1",
IsChecked = false,
Action = item => Console.WriteLine(@"{0} invoked action", item.Name)
},
new MyItem()
{
Name = "MySubItem2",
IsChecked = true,
Action = item => Console.WriteLine(@"{0} state is {1} ", item.Name, item.IsChecked)
},
},
Action = action
}
};
}
public ObservableCollection<MyItem> CollectionFooViewModel { get; set; }
}
public class MyItem : ViewModelBase
{
private bool _isChecked;
public string Name { get; set; }
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
if (Action != null)
Action.BeginInvoke(this, null, null);
}
}
public IEnumerable<MyItem> Children { get; set; }
public Action<MyItem> Action { get; set; }
}
这给你以下...
...并在按顺序单击时将其吐出到控制台。
MyItem was clicked
MySubItem1 invoked action
MySubItem2 state is False
当然,在您的情况下,您可能希望将具体方法传递给委托。