【问题标题】:Multiple ListBox/Collection Items Selected for MVVM为 MVVM 选择了多个列表框/集合项
【发布时间】:2013-01-23 16:45:07
【问题描述】:

我有一个绑定到名称的 ObservableCollection 的列表框。列表中的某些项目将有一个复选框,可以打开/关闭,表明该项目已被选中。

如何根据 Master-Details 概念从第一个列表框的选定项目创建 ObservableCollection?

(我计划使用我的 MasterViewModel 作为我的 DetailsView 的 DataContext,它显示所选项目集合。)

提前致谢!

【问题讨论】:

    标签: c# wpf mvvm observablecollection multipleselection


    【解决方案1】:

    是的,我以前也遇到过。 ListBoxes 等具有称为“SelectedItem”的依赖属性,但“SelectedItems”(带有“s”)属性没有作为一个实现。

    我发现的最简洁的解决方案就是对列表框进行子类化,并创建我自己的名为“SelectedItems”的依赖属性。不好玩,但这是我认为最好的解决方案。

    更新

    首先是我们的 ViewModel:

    class ViewModel : INotifyPropertyChanged
    {
        // Set up our collection to be read from the View
        public ObservableCollection<String> Collection { get; private set; }
    
        // This collection will maintain the selected items
        public ObservableCollection<String> SelectedItems { get; private set; }
    
        public ViewModel()
        {
            // Instantiate
            this.Collection = new ObservableCollection<String>();
            this.SelectedItems = new ObservableCollection<String>();
    
            // Now let's monitor when this.SelectdItems changes
            this.SelectedItems.CollectionChanged += SelectedItems_CollectionChanged;
    
            // Fill our collection with some strings (1 to 10).
            // (1) Generate the numbers 1 - 10
            // (2) Convert each number to a string
            // (3) Cast into a list so we can use foreach 
            // (4) Add each item to the collection.
            Enumerable.Range(1, 10)
                .Select(number => number.ToString())   
                .ToList()                              
                .ForEach(this.Collection.Add);
    
            // Remember! Never reset the ObservableCollection.
            // That is, never say this.Collection = new... (or you'll break the binding).
            // instead use this.Collection.Clear(), and then add the items you want to add
        }
    
        void SelectedItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                foreach (String str in this.SelectedItems)
                    System.Diagnostics.Debug.WriteLine("New item added {0}", str);
    
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    }
    

    然后是我们扩展的 ListBoxEx:

    class ListBoxEx : ListBox
    {
        // Use the 'new' keyword so that we 'hide' the base property.
        // This means that binding will go to this version of SelectedItems
        // rather than whatever the base class uses. To reach the base 'SelectedItems' property
        // We just need to use base.SelectedItems instead of this.SelectedItems
        // Note that we register as an observable collection.
        new DependencyProperty SelectedItemsProperty = 
            DependencyProperty.Register("SelectedItems", typeof(ObservableCollection<String>), typeof(ListBoxEx));
    
        // Accessor. Again, note the 'new'.
        new public ObservableCollection<String> SelectedItems
        {
            get { return (ObservableCollection<String>) GetValue(SelectedItemsProperty); }
            set { SetValue(SelectedItemsProperty, value); }
        }
    
        protected override void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            // Guard against ViewModel being null
            if (this.SelectedItems != null)
            {
                // Clear the list
                this.SelectedItems.Clear();
    
                // (1) On selection changed. Get the new base.SelectedItems
                // (2) Cast each item to a String ("Make a string collection")
                // (3) Cast to list, and use foreach to add each item to 
                // this.SelectedItems (note this is different from the original base.SelectedItems)
                base.SelectedItems.Cast<String>()
                    .ToList()
                    .ForEach(this.SelectedItems.Add);
            }
        }
    }
    

    最后是我们的视图:

    <Window.DataContext>
        <lol:ViewModel />
    </Window.DataContext>
    <Grid>
        <lol:ListBoxEx ItemsSource="{Binding Collection}" SelectedItems="{Binding SelectedItems}"
                       SelectionMode="Multiple"/>
    </Grid>
    

    【讨论】:

    • 我更多地考虑向视图模型添加一个“isSelected”布尔值,然后在一个新的“细节”视图模型上创建一个 ObservableCollection,如果这是真的。我不确定这会如何解决。至于你的“列表框中的多项选择”评论——我觉得这可以通过设置 SelectionMode="Multiple" 或 SelectionMode="Extended"
    • 向对象本身添加一个 isSelected 布尔值会起作用。但是“isSelected”是一个视图属性,而不是模型/视图模型属性 - 所以虽然它有效,但它在技术上是不正确的。此外,在您的原始帖子中,听起来您想要填充由所选项目组成的集合。问题是,要将这些项目放到 vm 中,您必须有一个依赖属性,但不存在这样的东西 - 不幸的是,您必须自己制作一个。
    • 哦,不是对象,而是 viewmodel 对象。有人在另一个问题中向我指出,乔什·史密斯在他的博客中这样做了。
    • 如何为选中的项目引发 PropertyChanged 事件,并将其添加到 ObservableCollection of Selections?
    • 那确实有道理。只需有一个专门用于视图的可观察集合。是的,听起来不错。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-03
    相关资源
    最近更新 更多