多选模式下,如何获取Windows.UI.Xaml.Controls.TreeView选中节点
问题解决指南
一、先修复WinUI TreeView的"No such Interface supported"错误
这个错误90%的概率是因为你在DataTemplate里用了系统自带的<TreeViewItem>,而非WinUI命名空间下的<muxc:TreeViewItem>。WinUI的TreeView必须搭配同框架的TreeViewItem使用,否则会出现组件兼容性问题。
修正后的XAML代码
<!-- 确保页面顶部已声明WinUI命名空间:xmlns:muxc="using:Microsoft.UI.Xaml.Controls" --> <muxc:TreeView SelectionMode="Multiple" Width="300" x:Name="CategoriesTree" ItemsSource="{x:Bind _vm.Categories, Mode=OneWay}" SelectionChanged="CategoriesTree_SelectionChanged"> <muxc:TreeView.ItemTemplate> <DataTemplate x:DataType="local1:CategoriesInfo"> <!-- 替换为WinUI的TreeViewItem --> <muxc:TreeViewItem ItemsSource="{x:Bind SubCategories}" Content="{x:Bind Name}" /> </DataTemplate> </muxc:TreeView.ItemTemplate> </muxc:TreeView>
额外检查项
- 确认项目已安装Microsoft.UI.Xaml NuGet包(建议选稳定版,比如2.8.0)
- 项目目标最低Windows版本需≥Windows 10 1809(10.0.17763.0),WinUI 2对低版本系统支持有限
二、实现多选选中项的双向绑定
WinUI的TreeView自带的SelectedItems是只读集合,无法直接双向绑定到ViewModel属性,推荐两种解决方案:
方案1:通过SelectionChanged事件同步选中项
在后台代码中监听事件,手动同步到ViewModel的集合:
private void CategoriesTree_SelectionChanged(muxc.TreeView sender, muxc.TreeViewSelectionChangedEventArgs args) { // 清空ViewModel中的选中集合 _vm.SelectedCategories.Clear(); // 遍历选中项并添加到ViewModel foreach (var item in sender.SelectedItems) { if (item is CategoriesInfo category) { _vm.SelectedCategories.Add(category); } } }
如果需要反向同步(ViewModel更新时同步TreeView选中状态),可以监听集合变更:
// 假设ViewModel的SelectedCategories是ObservableCollection<CategoriesInfo> _vm.SelectedCategories.CollectionChanged += (s, e) => { // 先取消所有选中 CategoriesTree.DeselectAll(); // 选中集合内的项 foreach (var category in _vm.SelectedCategories) { var container = CategoriesTree.ContainerFromItem(category) as muxc.TreeViewItem; container?.IsSelected = true; } };
方案2:自定义附加属性实现双向绑定
封装一个附加属性,让XAML可以直接绑定:
public static class TreeViewHelper { public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.RegisterAttached("SelectedItems", typeof(IList), typeof(TreeViewHelper), new PropertyMetadata(null, OnSelectedItemsChanged)); public static IList GetSelectedItems(DependencyObject obj) { return (IList)obj.GetValue(SelectedItemsProperty); } public static void SetSelectedItems(DependencyObject obj, IList value) { obj.SetValue(SelectedItemsProperty, value); } private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is muxc.TreeView treeView) { treeView.SelectionChanged -= OnTreeViewSelectionChanged; if (e.NewValue is IList newList) { treeView.SelectionChanged += OnTreeViewSelectionChanged; SyncTreeViewSelection(treeView, newList); } } } private static void OnTreeViewSelectionChanged(muxc.TreeView sender, muxc.TreeViewSelectionChangedEventArgs args) { var selectedItems = GetSelectedItems(sender); if (selectedItems == null) return; selectedItems.Clear(); foreach (var item in sender.SelectedItems) { selectedItems.Add(item); } } private static void SyncTreeViewSelection(muxc.TreeView treeView, IList selectedItems) { treeView.DeselectAll(); foreach (var item in selectedItems) { var container = treeView.ContainerFromItem(item) as muxc.TreeViewItem; container?.IsSelected = true; } } }
然后在XAML中直接绑定:
<muxc:TreeView SelectionMode="Multiple" Width="300" x:Name="CategoriesTree" ItemsSource="{x:Bind _vm.Categories, Mode=OneWay}" local:TreeViewHelper.SelectedItems="{x:Bind _vm.SelectedCategories, Mode=TwoWay}"> <muxc:TreeView.ItemTemplate> <DataTemplate x:DataType="local1:CategoriesInfo"> <muxc:TreeViewItem ItemsSource="{x:Bind SubCategories}" Content="{x:Bind Name}" /> </DataTemplate> </muxc:TreeView.ItemTemplate> </muxc:TreeView>
注意:ViewModel中的SelectedCategories需为ObservableCollection<CategoriesInfo>类型,才能支持双向同步。
内容的提问来源于stack exchange,提问作者Sayansen
相关产品推荐
相关产品推荐

