【问题标题】:How to bind to event in parent viewmodel from child viewmodel如何从子视图模型绑定到父视图模型中的事件
【发布时间】:2015-04-13 23:42:58
【问题描述】:

我目前正在关注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 中)我会得到答案。

【问题讨论】:

  • 如果你想为你使用的样式和模板添加你的代码,或者避免在你给出的代码中使用它们,通过在一个更简单的、更少“设计”的代码中创建这个场景,它可以帮助我们理解它是什么您是否正在尝试完成并提出解决方案

标签: c# wpf xaml mvvm treeview


【解决方案1】:

有很多方法可以实现这一点。一种是某种 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>

数据上下文

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

这为您提供以下...

...并在按顺序单击时将其吐出到控制台。

我的项目被点击
MySubItem1 调用的操作
MySubItem2 状态为 False

当然,在您的情况下,您可能希望将具体方法传递给委托。

【讨论】:

    【解决方案2】:

    尝试在模型的设置器中添加“OnPropertyEventChanged”方法调用,这是我的意思的示例:

    https://msdn.microsoft.com/en-us/library/ms743695%28v=vs.110%29.aspx

    【讨论】:

    • 我有,但由于我只能订阅顶部节点的 propertychange 事件,而不是检查子节点时,它不能解决我的问题。
    猜你喜欢
    • 2017-05-04
    • 1970-01-01
    • 2018-06-24
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多