WinUI 3中ListView选中项无法在其他列表显示的绑定问题
WinUI 3 ListView多选选中项绑定失效的解决方案
问题根源
WinUI 3 中 ListView.SelectedItems 并非依赖属性,直接通过 XAML 绑定无法监听其变化,这是你两种尝试都失效的核心原因——和数据源使用 IEnumerable 无关,哪怕换成 ObservableCollection,直接绑定 SelectedItems 依然无效。
解决方案
以下提供两种方案,尽量满足你「仅通过XAML实现只读展示」的需求:
方案一:纯XAML+转换器(无需修改ViewModel)
通过转换器将 SelectedItems 转为可枚举集合,实现绑定展示:
- 创建转换器类
using Microsoft.UI.Xaml.Data; using Microsoft.UI.Xaml.Controls; using System.Collections.Generic; using System.Linq; public class SelectedItemsConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { return value is IList<object> items ? items.ToList() : Enumerable.Empty<object>(); } public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } }
- 在XAML中引用并使用
<Page.Resources> <local:SelectedItemsConverter x:Key="SelectedItemsConverter"/> </Page.Resources> <!-- 原ListView --> <ListView x:Name="FlagsListView" SelectionMode="Multiple" ItemsSource="{x:Bind ViewModel.ValidationFlagsList, Mode=OneTime}" SelectedValuePath="Key" DisplayMemberPath="Value"> </ListView> <!-- 展示选中项的ItemsControl --> <ItemsControl ItemsSource="{Binding ElementName=FlagsListView, Path=SelectedItems, Converter={StaticResource SelectedItemsConverter}}"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Value}"/> </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl>
方案二:附加属性+MVVM(更贴合Template Studio架构)
通过附加属性将 SelectedItems 包装为可绑定的依赖属性,适配MVVM模式:
- 创建附加属性类
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using System.Collections.Generic; public static class ListViewExtensions { public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.RegisterAttached( "SelectedItems", typeof(IEnumerable<object>), typeof(ListViewExtensions), new PropertyMetadata(null, OnSelectedItemsChanged)); public static IEnumerable<object> GetSelectedItems(DependencyObject obj) { return (IEnumerable<object>)obj.GetValue(SelectedItemsProperty); } public static void SetSelectedItems(DependencyObject obj, IEnumerable<object> value) { obj.SetValue(SelectedItemsProperty, value); } private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is ListView listView) { listView.SelectionChanged -= ListView_SelectionChanged; if (e.NewValue != null) { listView.SelectionChanged += ListView_SelectionChanged; } } } private static void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (sender is ListView listView) { var selectedItems = new List<object>(); foreach (var item in listView.SelectedItems) { selectedItems.Add(item); } SetSelectedItems(listView, selectedItems); } } }
- ViewModel中添加绑定属性
private IEnumerable<KeyValuePair<string, string>> _selectedFlags; public IEnumerable<KeyValuePair<string, string>> SelectedFlags { get => _selectedFlags; set => SetProperty(ref _selectedFlags, value); }
- XAML中绑定使用
<ListView x:Name="FlagsListView" SelectionMode="Multiple" ItemsSource="{x:Bind ViewModel.ValidationFlagsList, Mode=OneTime}" SelectedValuePath="Key" DisplayMemberPath="Value" local:ListViewExtensions.SelectedItems="{x:Bind ViewModel.SelectedFlags, Mode=OneWayToSource}"> </ListView> <!-- 展示选中项 --> <ItemsControl ItemsSource="{x:Bind ViewModel.SelectedFlags, Mode=OneWay}"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Value}"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
关键说明
- 数据源用
IEnumerable完全没问题,你的场景是只读列表,OneTime绑定足够; - 两种方案都能实现选中项的只读展示,转换器方案更偏向纯XAML,附加属性方案更适配MVVM架构。
内容的提问来源于stack exchange,提问作者Mihai Socaciu
相关产品推荐
相关产品推荐

