【问题标题】:Nested Listbox how to set parent listbox selectedItem on child listbox mouse double click嵌套列表框如何在子列表框鼠标双击上设置父列表框 selectedItem
【发布时间】:2013-12-11 02:45:05
【问题描述】:

我有一个嵌套的ListBox。在内部列表框鼠标双击事件中,我需要根据一些逻辑打开一个新窗口,为此我需要内部列表框 SelectedItem 及其对应的外部 ListBox SelectedItem。如何以 MVVM 的方式得到这个?

<ListBox ItemsSource="{Binding OuterCollection}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding OuterProperty1}" />
                            <ListBox Width="200" ItemsSource="{Binding InnerCollection}">
                                <ListBox.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding InnerProperty1}" />
                                    </DataTemplate>
                                </ListBox.ItemTemplate>
                            </ListBox>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

要记住的事情:

1) 内部集合和外部集合项之间没有关系。

2) 我正在使用 MVVMLight Toolkit,作为临时解决方案,我只是将内部 ListBox 鼠标双击事件参数传递给 View 模型并遍历树以找到外部 ListBox 项。 我知道这违反了 MVVM 规则,那么我该如何以正确的 MVVM 方式来做呢?

【问题讨论】:

    标签: c# wpf mvvm listbox mvvm-light


    【解决方案1】:

    找到一种可能的解决方案

    您可以在ListBox 上使用SelectedItem 属性。

    这是我用来解决您的问题的代码。虽然我用的是 Cinch,但轻框架应该不是问题

    MainWindow.xaml

    <Window x:Class="TestWPF.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
            Title="MainWindow" Height="350" Width="525">
        <ListBox ItemsSource="{Binding OuterCollection}" SelectedItem="{Binding OuterListBoxSelectedItem}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding}" />
                        <ListBox Width="150" DataContext="{Binding DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
                                 ItemsSource="{Binding InnerCollection}"
                                 SelectedItem="{Binding InnerListBoxSelectedItem}">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="MouseDoubleClick">
                                    <i:InvokeCommandAction Command="{Binding TestCommand}"
                                                           CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}, AncestorLevel=2},Path=SelectedItem}"/>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <TextBlock Text="{Binding}" />
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Window>
    

    MainWindow.xaml.cs

    using System.Windows;
    
    namespace TestWPF
    {
    
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                this.DataContext = new ViewModel();
            }
        }
    }
    

    最后但并非最不重要的是我的模型

    using System.Collections.ObjectModel;
    using System.Windows.Input;
    using Cinch;
    
    namespace TestWPF
    {
        public class ViewModel : ViewModelBase
        {
            public ICommand TestCommand { get; private set; }
            public ObservableCollection<string> OuterCollection { get; private set; }
            public string OuterListBoxSelectedItem { get; set; }
            public ObservableCollection<string> InnerCollection { get; private set; }
            public string InnerListBoxSelectedItem { get; set; }
    
            public ViewModel()
            {
                OuterCollection = new ObservableCollection<string> { "Outer 1", "Outer 2", "Outer 3", "Outer 4" };
                InnerCollection = new ObservableCollection<string> { "Inner 1", "Inner 2", "Inner 3" };
                TestCommand = new SimpleCommand<object, object>(Test);
                NotifyPropertyChanged("OuterCollection");
                NotifyPropertyChanged("InnerCollection");
                NotifyPropertyChanged("TestCommand");
            }
            public void Test(object o)
            {
                var a = InnerListBoxSelectedItem;
                var b = OuterListBoxSelectedItem;
                "".ToString();
            }
        }
    }
    

    我还需要再添加一个对System.Windows.Interactivity的引用

    希望对你有帮助

    【讨论】:

    • "内部集合和外部集合项之间没有关系。"并不意味着它们是不同的集合。它是另一个集合中的集合。即每个 OuterCollection 记录都包含一个 InnerCollection 列表。另外,您是如何在内部列表框鼠标双击事件中选择外部列表框项目的?
    • 别介意我使用的不同系列。那只是为了说明。好的,在CommandParameter 中解决您的第二个疑问,您会发现我已使用RelativeSource 将其绑定到第一个ListBox。所以它的作用是查找 Visual 树并尝试找到满足AncestorLevel 标准的ListBox。如果它找到一个然后它绑定到它。顺便说一句,你执行了我的代码吗?它是否按要求的方式工作?
    • 假设我选择了外部列表框中的第一个项目并双击位于外部列表框中第三个项目内的内部列表框项目。然后你的祖先类型将只返回第一个列表框项目。不是第三个...
    • 是的,我知道这个问题。如果您的案例中的内部收藏是独一无二的,那么您很幸运。您可以做的是在双击内部集合后,您可以使用外部ListBoxSelectedItem 作为键添加一个验证,以查看内部选定项是否确实是外部选定项的一部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多