WPF 使用附加属性来绑定ListBox的SelectedItems

 

ListBox的SelectedItems属性是只读属性,没法直接绑定。

一般的处理方式是在命令中通过命令参数传递到ViewModel里面。

现在通过附加属性来解决这个问题

效果

 

后台代码

  1 using Microsoft.Toolkit.Mvvm.ComponentModel;
  2 using Microsoft.Toolkit.Mvvm.Input;
  3 using System;
  4 using System.Collections;
  5 using System.Collections.Generic;
  6 using System.Collections.ObjectModel;
  7 using System.Linq;
  8 using System.Text;
  9 using System.Threading.Tasks;
 10 using System.Windows;
 11 using System.Windows.Controls;
 12 using System.Windows.Controls.Primitives;
 13 using System.Windows.Input;
 14 
 15 namespace MvvmToolkit学习
 16 {
 17     public class DataItem
 18     {
 19         public ObservableCollection<string> Data { get; set; }
 20 
 21         public string Name { get; set; }
 22 
 23         public DataItem()
 24         {
 25             Data = new ObservableCollection<string>();
 26             Data.Add("Sun");
 27             Data.Add("Moon");
 28             Data.Add("Star");
 29         }
 30     }
 31 
 32     public class ListBoxHelper
 33     {
 34         // Using a DependencyProperty as the backing store for SelectedItems.  This enables animation, styling, binding, etc...
 35         public static readonly DependencyProperty SelectedItemsProperty =
 36             DependencyProperty.RegisterAttached("SelectedItems",
 37                 typeof(IList),
 38                 typeof(ListBoxHelper),
 39                 new FrameworkPropertyMetadata(default(IList),
 40                     FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
 41                     OnSelectedItemsChanged));
 42 
 43         public static IList GetSelectedItems(DependencyObject obj)
 44         {
 45             return (IList)obj.GetValue(SelectedItemsProperty);
 46         }
 47 
 48         public static void SetSelectedItems(DependencyObject obj, IList value)
 49         {
 50             obj.SetValue(SelectedItemsProperty, value);
 51         }
 52 
 53         private static void OnlistBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
 54         {
 55             IList dataSource = GetSelectedItems(sender as DependencyObject);
 56             //添加用户选中的当前项.
 57             foreach (var item in e.AddedItems)
 58             {
 59                 dataSource.Add(item);
 60             }
 61             //删除用户取消选中的当前项
 62             foreach (var item in e.RemovedItems)
 63             {
 64                 dataSource.Remove(item);
 65             }
 66         }
 67 
 68         private static void OnSelectedItemsChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
 69         {
 70             var listBox = target as ListBox;
 71             if ((listBox != null) && (listBox.SelectionMode == SelectionMode.Multiple))
 72             {
 73                 if (e.OldValue != null)
 74                 {
 75                     listBox.SelectionChanged -= OnlistBoxSelectionChanged;
 76                 }
 77                 IList collection = e.NewValue as IList;
 78                 listBox.SelectedItems.Clear();
 79                 if (collection != null)
 80                 {
 81                     foreach (var item in collection)
 82                     {
 83                         listBox.SelectedItems.Add(item);
 84                     }
 85                     listBox.SelectionChanged += OnlistBoxSelectionChanged;
 86                 }
 87             }
 88         }
 89     }
 90 
 91     internal class Test1ViewModel : ObservableObject
 92     {
 93         private RelayCommand addCmd;
 94 
 95         public ICommand AddCmd
 96         {
 97             get
 98             {
 99                 if (addCmd == null)
100                 {
101                     addCmd = new RelayCommand(PerformAddCmd);
102                 }
103 
104                 return addCmd;
105             }
106         }
107 
108         public ObservableCollection<DataItem> DataItems { get; set; }
109         public List<DataItem> SelectedItems { get; set; }
110         public double Size { get; set; }
111 
112         public Test1ViewModel()
113         {


//因为默认值是null所以不会进回调
//给附加属性一个非null值就可以了
//只有附加属性值改变的时候才会触发PropertyChanged,默认属性值是null,VM的值也是null,所以不触发

114             SelectedItems = new List<DataItem>();//此处属性必须赋值,不可为null。。绕了很久的弯路
115             DataItems = new ObservableCollection<DataItem>();
116             DataItems.Add(new DataItem() { Name = "A" });
117             DataItems.Add(new DataItem() { Name = "B" });
118         }
119 
120         private void PerformAddCmd()
121         {
122             MessageBox.Show(string.Join("", SelectedItems.Select(s => s.Name)));
123         }
124     }
125 }

xaml

 1 <Window
 2     x:Class="MvvmToolkit学习.Test1"
 3     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 4     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 5     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 6     xmlns:local="clr-namespace:MvvmToolkit学习"
 7     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 8     xmlns:pu="clr-namespace:Panuon.UI.Silver;assembly=Panuon.UI.Silver"
 9     Title="Test1"
10     Width="800"
11     Height="450"
12     d:DataContext="{d:DesignInstance Type={x:Type local:Test1ViewModel}}"
13     mc:Ignorable="d">
14     <Grid>
15         <StackPanel Orientation="Vertical">
16             <ListBox
17                 Width="200"
18                 Height="100"
19                 local:ListBoxHelper.SelectedItems="{Binding SelectedItems}"
20                 ItemsSource="{Binding DataItems}"
21                 SelectionMode="Multiple">
22                 <ListBox.ItemTemplate>
23                     <DataTemplate DataType="{x:Type local:DataItem}">
24                         <StackPanel Orientation="Horizontal">
25                             <CheckBox IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}"/>
26                             <ContentControl Content="{Binding}"/>
27                         </StackPanel>
28                     </DataTemplate>
29                 </ListBox.ItemTemplate>
30             </ListBox>
31 
32             <Button
33                 Width="200"
34                 Height="35"
35                 Command="{Binding AddCmd}"/>
36             <DataGrid pu:DataGridHelper.SelectedItems="{Binding DataItems}"/>
37         </StackPanel>
38     </Grid>
39 </Window>

 

posted @ 2022-04-21 20:24  只吃肉不喝酒  阅读(2421)  评论(0编辑  收藏  举报