【问题标题】:UWP Get selected nodes from TreeView controlUWP 从 TreeView 控件中获取选定的节点
【发布时间】:2019-11-08 01:03:31
【问题描述】:

如何从TreeView 控件中获取当前突出显示/选定的节点?根据文档here,应该可以遍历控件的SelectedNodes 属性,但它始终为空。


编辑:这原来是 XAML 的一个实际错误,跟踪 here。在修复之前,接受的答案可以作为解决方法。


上下文:我正在开发一个简单的演示应用程序来探索TreeView 控件。我正在尝试添加键盘快捷键来删除当前活动/选定的节点。我在实现ICommand 的 RelayCommand 类中有删除功能。我已经通过TreeViewItemDataTemplate 将其作为按钮和弹出菜单工作。我看不到在键盘快捷键中重用 ICommand 的干净方法。

突出显示最后点击项目的应用图像;我需要在代码隐藏中访问此 TreeViewItem,以便在 TreeView 具有焦点并按下“删除”键时将其删除。

我在TreeView 控件上有一个事件处理程序:

<controls:TreeView x:Name="TreeDataBound"
    ItemsSource="{Binding Path=TreeSource, Mode=TwoWay}"
    ItemTemplateSelector="{StaticResource TreeItemTemplateSelector}"
    SelectionMode="Single"
    KeyDown="Tree_KeyDown">

事件处理程序应该循环通过选定的节点,尽管我认为SelectionMode="Single" 可枚举应该只有一项。

private void Tree_KeyDown(object sender, KeyRoutedEventArgs e)
{
    if (e.Key == Windows.System.VirtualKey.Delete)
    {
        foreach (var element in TreeDataBound.SelectedNodes)
        {
            // Delete the item 
        }
    }
}

SelectedNodes 似乎始终为空,即使其中一个 TreeView iem 被突出显示。在调试器中SelectedNodes 显示为System.__ComObject 的类型,没有可访问的属性,所以我无法进一步检查它。

对更好的方法有什么想法或建议吗?

【问题讨论】:

  • 因此,使用 TreeView SelectionMode="Multiple",可以按预期工作。模式为“Single”时一定有办法获取选中项。
  • 是的,我能够调整这个答案。谢谢!

标签: .net xaml uwp


【解决方案1】:

UWP 从 TreeView 控件中获取选定节点

对于单选模式。 TreeViewItem 包含IsSelected 属性,您可以使用IsSelected 创建模型类并绑定它。选择项目后IsSelected 值将被更改,因此您可以 foreach 项目源然后删除所选项目。请参考以下步骤。

背后的代码

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        DataSource = GetData();
    }
    private ObservableCollection<ExplorerItem> DataSource;
    private ObservableCollection<ExplorerItem> GetData()
    {
        var list = new ObservableCollection<ExplorerItem>();
        ExplorerItem folder1 = new ExplorerItem()
        {
            Name = "Work Documents",
            Type = ExplorerItem.ExplorerItemType.Folder,
            Children =
            {
                new ExplorerItem()
                {
                    Name = "Functional Specifications",
                    Type = ExplorerItem.ExplorerItemType.Folder,
                    Children =
                    {
                        new ExplorerItem()
                        {
                            Name = "TreeView spec",
                            Type = ExplorerItem.ExplorerItemType.File,
                          }
                    }
                },
                new ExplorerItem()
                {
                    Name = "Feature Schedule",
                    Type = ExplorerItem.ExplorerItemType.File,
                },
                new ExplorerItem()
                {
                    Name = "Overall Project Plan",
                    Type = ExplorerItem.ExplorerItemType.File,
                },
                new ExplorerItem()
                {
                    Name = "Feature Resources Allocation",
                    Type = ExplorerItem.ExplorerItemType.File,
                }
            }
        };
        ExplorerItem folder2 = new ExplorerItem()
        {
            Name = "Personal Folder",
            Type = ExplorerItem.ExplorerItemType.Folder,
            Children =
                    {
                        new ExplorerItem()
                        {
                            Name = "Home Remodel Folder",
                            Type = ExplorerItem.ExplorerItemType.Folder,
                            Children =
                            {
                                new ExplorerItem()
                                {
                                    Name = "Contractor Contact Info",
                                    Type = ExplorerItem.ExplorerItemType.File,
                                },
                                new ExplorerItem()
                                {
                                    Name = "Paint Color Scheme",
                                    Type = ExplorerItem.ExplorerItemType.File,
                                },
                                new ExplorerItem()
                                {
                                    Name = "Flooring Woodgrain type",
                                    Type = ExplorerItem.ExplorerItemType.File,
                                },
                                new ExplorerItem()
                                {
                                    Name = "Kitchen Cabinet Style",
                                    Type = ExplorerItem.ExplorerItemType.File,
                                }
                            }
                        }
                    }
        };

        list.Add(folder1);
        list.Add(folder2);
        return list;
    }

    private void Tree_KeyDown(object sender, KeyRoutedEventArgs e)
    {
        if (e.Key == Windows.System.VirtualKey.Delete)
        {
             DeleteSelectItem(DataSource);
        }

    }
    private ExplorerItem DeleteSelectItem(ObservableCollection<ExplorerItem> DataSource)
    {
        foreach (var item in DataSource)
        {
            if (item.IsSelected == true)
            {
                DataSource.Remove(item);
                return item;
            }

            var FindResult = DeleteSelectItem(item.Children);
            if (FindResult != null)
                return FindResult;
        }

        return null;
    }
}
public class ExplorerItem : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public enum ExplorerItemType { Folder, File };
    public String Name { get; set; }
    public ExplorerItemType Type { get; set; }
    private ObservableCollection<ExplorerItem> m_children;
    public ObservableCollection<ExplorerItem> Children
    {
        get
        {
            if (m_children == null)
            {
                m_children = new ObservableCollection<ExplorerItem>();
            }
            return m_children;
        }
        set
        {
            m_children = value;
        }
    }

    private bool m_isExpanded;
    public bool IsExpanded
    {
        get { return m_isExpanded; }
        set
        {
            if (m_isExpanded != value)
            {
                m_isExpanded = value;
                NotifyPropertyChanged("IsExpanded");
            }
        }
    }

    private bool m_isSelected;
    public bool IsSelected
    {
        get { return m_isSelected; }

        set
        {
            if (m_isSelected != value)
            {
                m_isSelected = value;
                NotifyPropertyChanged("IsSelected");
            }
        }

    }

    private void NotifyPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

class ExplorerItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate FolderTemplate { get; set; }
    public DataTemplate FileTemplate { get; set; }

    protected override DataTemplate SelectTemplateCore(object item)
    {
        var explorerItem = (ExplorerItem)item;
        return explorerItem.Type == ExplorerItem.ExplorerItemType.Folder ? FolderTemplate : FileTemplate;
    }
}

Xaml

<Page.Resources>
    <DataTemplate x:Key="FolderTemplate" x:DataType="local:ExplorerItem">
        <TreeViewItem
            AutomationProperties.Name="{x:Bind Name}"
            IsExpanded="{x:Bind IsExpanded,Mode=TwoWay}"
            IsSelected="{x:Bind IsSelected,Mode=TwoWay}"
            ItemsSource="{x:Bind Children}"
            >

            <StackPanel Orientation="Horizontal">
                <Image Width="20" Source="../Assets/folder.png" />
                <TextBlock Margin="0,0,10,0" />
                <TextBlock Text="{x:Bind Name}" />
            </StackPanel>
        </TreeViewItem>
    </DataTemplate>

    <DataTemplate x:Key="FileTemplate" x:DataType="local:ExplorerItem">
        <TreeViewItem AutomationProperties.Name="{x:Bind Name}" IsSelected="{x:Bind IsSelected,Mode=TwoWay}">

            <StackPanel Orientation="Horizontal">
                <Image Width="20" Source="../Assets/file.png" />
                <TextBlock Margin="0,0,10,0" />
                <TextBlock Text="{x:Bind Name}" />
            </StackPanel>
        </TreeViewItem>
    </DataTemplate>

    <local:ExplorerItemTemplateSelector
        x:Key="ExpolrerItemTemplateSelector"
        FileTemplate="{StaticResource FileTemplate}"
        FolderTemplate="{StaticResource FolderTemplate}"
        />
</Page.Resources>
<Grid>
    <TreeView
        x:Name="TreeDataBound"
        HorizontalAlignment="Center"
        VerticalAlignment="Top"
        ItemTemplateSelector="{StaticResource ExpolrerItemTemplateSelector}"
        ItemsSource="{x:Bind DataSource,Mode=OneWay}"
        KeyDown="Tree_KeyDown"
        SelectionMode="Single"
        />
</Grid>

完整的代码示例请参考link

【讨论】:

  • 我希望通过管理单选来做同样的事情。我转到上面提供的链接并下载了代码,但在代码示例中找不到上面的数据绑定示例。链接是否不正确或过时?
【解决方案2】:

这个问题已经解决了,但是当你像往常一样创建一个 uwp 应用程序时它没有被“启用”。

您需要修改一些代码行以启用较新版本的 xaml。

首先,请按照此页面上的说明进行操作:https://docs.microsoft.com/en-us/windows/apps/winui/winui2/getting-started .获取项目中安装的最新包。

然后将xmlns:muxc="using:Microsoft.UI.Xaml.Controls"using muxc = Microsoft.UI.Xaml.Controls; 添加到要使用最新包中的新控件的任何Xaml/CS 文件中。 示例可以在 :https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/tree-view 上找到。 一言以蔽之,将muxc: 添加到每个&lt;TreeView&gt;,使它们成为&lt;muxc:TreeView&gt;(因此添加到除数据模板之外的每个子项)。 然后在后面的cs代码中,使用muxc.TreeViewxxx代替默认命名空间。

我不是 C# 或 VS 方面的专家,这个答案可以改进或有不必要的说明,但它现在对我有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多