在WPF中,不论是ListBox,ListView或者DataGrid,在使用中都会经常用到SelectedItems,但是在Xaml中却发现SelectedItems没有办法Binding。这是因为SelectedItems是一个只读属性,且不是一个DependencyProperty,所以没法Binding。不过我们却可以通过以下几种方法来实现这个功能:

【方案一】

使用后台代码,读取这个控件的SelectedItems属性。例如
XAML:

1
2
<ListView ItemsSource="{Binding}" x:Name="lvTest">
</ListView>

那么后台就可以

1
2
3
4
foreach(XX item in lvTest.SelectedItems)
{
//Operation
}

如果列表控件是作为ControlTemplate的内容,那么就在后台获取ControlTemplate下的这个控件

1
var lvTest= XX.Template.FindName("lvTest", XX);

【方案二】

可以通过修改SelectionChanged事件来通知后台该控件选择的项。MSDN中提供了这一解决方案。

XAML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<Window x:Class="ListViewSelectedItemsBinding.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ListViewSelectedItemsBinding"
xmlns:w="clr-namespace:System.Windows.Workarounds"
x:Name="root" Width="500" Height="700">
<Window.Resources>
<local:MyConverter x:Key="myConverter"/>
</Window.Resources>
<StackPanel>
<ListView x:Name="listView" ItemsSource="{Binding}" SelectionMode="Extended"
SelectionChanged="listView_SelectionChanged"
w:ListView.HasBindableSelectedItems="True">
<ListView.View>
<GridView>
<GridViewColumn Header="Artist" DisplayMemberBinding="{Binding Path=Artist}" />
<GridViewColumn Header="Title" DisplayMemberBinding="{Binding Path=Title}" />
<GridViewColumn Header="Genre" DisplayMemberBinding="{Binding Path=Genre}" />
</GridView>
</ListView.View>
</ListView>
<StackPanel Background="LightGreen">
<DockPanel>
<Label DockPanel.Dock="Left" Content="SelectedItems.Count = " />
<TextBox Text="{Binding ElementName=listView, Path=SelectedItems.Count, Mode=OneWay}" IsReadOnly="True" />
</DockPanel>
<DockPanel>
<Label DockPanel.Dock="Left" Content="SelectedItems = " />
<TextBox Text="{Binding ElementName=listView, Path=SelectedItems, Mode=OneWay,
Converter={StaticResource myConverter}, ConverterParameter='Artist'}" IsReadOnly="True" />
</DockPanel>
</StackPanel>
<StackPanel Background="LightBlue">
<DockPanel>
<Label DockPanel.Dock="Left" Content="Selection.Count = " />
<TextBox Text="{Binding ElementName=root, Path=Selection.Count, Mode=OneWay}" IsReadOnly="True" />
</DockPanel>
<DockPanel>
<Label DockPanel.Dock="Left" Content="Selection = " />
<TextBox Text="{Binding ElementName=root, Path=Selection, Mode=OneWay,
Converter={StaticResource myConverter}, ConverterParameter='Artist'}" IsReadOnly="True" />
</DockPanel>
</StackPanel>
<local:PropertiesPanel x:Name="propertiesPanel1" Background="LightGreen"
Subjects="{Binding ElementName=listView, Path=SelectedItems, Mode=OneWay}" />
<local:PropertiesPanel x:Name="propertiesPanel2" Background="LightBlue"
Subjects="{Binding ElementName=root, Path=Selection, Mode=OneWay}" />
<local:PropertiesPanel x:Name="propertiesPanel3" Background="LightPink"
Subjects="{Binding ElementName=listView, Path=BindableSelectedItems}" />
</StackPanel>
</Window>

后台

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
using System;
using System.Collections;
using System.Windows.Data;
using System.Windows.Controls;
namespace System.Windows.Workarounds
{
public static class ListView
{
public static readonly DependencyProperty HasBindableSelectedItemsProperty;
public static readonly DependencyProperty BindableSelectedItemsProperty;
static DependencyProperty SelectionChangedHandlerProperty;
static ListView()
{
BindableSelectedItemsProperty = DependencyProperty.Register("BindableSelectedItems", typeof(IList), typeof(System.Windows.Controls.ListView));
HasBindableSelectedItemsProperty = DependencyProperty.RegisterAttached("HasBindableSelectedItems", typeof(bool), typeof(System.Windows.Controls.ListView), new PropertyMetadata(false));
SelectionChangedHandlerProperty = DependencyProperty.RegisterAttached("SelectionChangedHandler", typeof(SelectionChangedHandler), typeof(System.Windows.Controls.ListView));
}
public static void SetHasBindableSelectedItems(System.Windows.Controls.ListView source, bool value)
{
SelectionChangedHandler Handler = (SelectionChangedHandler)source.GetValue(SelectionChangedHandlerProperty);
if (value && Handler == null)
{
Handler = new SelectionChangedHandler(source);
source.SetValue(SelectionChangedHandlerProperty, Handler);
}
else if (!value && Handler != null)
{
source.ClearValue(SelectionChangedHandlerProperty);
}
}
}
internal class SelectionChangedHandler
{
Binding Binding;
internal SelectionChangedHandler(System.Windows.Controls.ListView owner)
{
Binding = new Binding("SelectedItems");
Binding.Source = owner;
owner.SetBinding(ListView.BindableSelectedItemsProperty, Binding);
owner.SelectionChanged += new SelectionChangedEventHandler(Owner_SelectionChanged);
}
void Owner_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
System.Windows.Controls.ListView Owner = (System.Windows.Controls.ListView)sender;
BindingOperations.ClearBinding(Owner, ListView.BindableSelectedItemsProperty);
Owner.SetBinding(ListView.BindableSelectedItemsProperty, Binding);
}
}
}

【方案三】

可以重写SelectedItems实现Binding,方案可以参考这里