WPF - Советы по использованию структуры меню в виде дерева - PullRequest
0 голосов
/ 29 января 2019

Я новичок в WPF.Я перекладываю приложение Win Forms на WPF, которое требует от меня много знаний.

В WinForms я бы создал подкласс общих элементов управления (MyLabel: Label, MyDataGrid: DataGrid и т. Д.)Это позволило бы мне установить все необходимые атрибуты и стили, и они были бы согласованы для любого элемента управления, который я тогда использовал.Кроме того, я мог бы реализовать функциональность этих элементов управления, которая была бы доступна для всех моих элементов управления.

Я с треском провалился в возможности сделать это с TreeView / TreeViewItem в WPF.Я создал рабочий пример с обычным TreeView, а затем просто заменил MyTreeView в MainPage.Я получаю: System.InvalidOperationException: 'Коллекция элементов должна быть пустой перед использованием ItemsSource.'

Надеемся, вы можете скачать проект по этой ссылке: https://app.box.com/s/9ofyuwfgk2cobqhokezgkknvtnmzmeq7

Часть изменения дизайна заключается вреализовать меню в виде дерева в левой части экрана.Это будет иметь около 60 вариантов.

Я потратил немного времени и заполнил TreeView.Тем не менее, я считаю, что здесь можно использовать меню и оформить его в виде дерева.Это правильно?Если это так, может кто-нибудь указать мне пример, так как я не смог найти его в Google.Похоже, Google считает, что мне нужно контекстное меню для TreeView.

Отредактировано для добавления кода:

TreeView xaml (TreeViewItem в основном идентичен)

    <TreeView x:Class="WpfApp1.Controls.MyTreeView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:local="clr-namespace:WpfApp1.Controls"
         mc:Ignorable="d"
         d:DesignHeight="450" d:DesignWidth="800">
        <Grid>
        </Grid>
    </TreeView>

TreeView cs

    using System.Windows;
    using System.Windows.Controls;

    namespace WpfApp1.Controls
    {
        /// <summary>
        /// Interaction logic for MyTreeView.xaml
        /// </summary>
        public partial class MyTreeView : TreeView
        {
            public MyTreeView()
            {
                InitializeComponent();
            }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new MyTreeView();
        }

        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is MyTreeView;
        }
    }

MainWindow

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        xmlns:Controls="clr-namespace:WpfApp1.Controls"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <XmlDataProvider x:Key="treeViewStructure" Source="Data/treeViewStructure.xml" XPath="./*/Category"/>

        <HierarchicalDataTemplate DataType="Category" ItemsSource="{Binding XPath=*}">
            <TextBlock Text="{Binding XPath=@Name}"/>
        </HierarchicalDataTemplate>

        <HierarchicalDataTemplate DataType="SubCategory" ItemsSource="{Binding XPath=*}">
            <TextBlock Text="{Binding XPath=@Name}"/>
        </HierarchicalDataTemplate>
    </Window.Resources>
    <Grid>
        <Controls:MyTreeView x:Name="mainTreeViewMenu"
                      Grid.Column="0"
                      BorderThickness="0"
                      ItemsSource="{Binding Mode=OneWay, Source={StaticResource treeViewStructure}}" DataContext="{DynamicResource treeViewStructure}"/>
    </Grid>
</Window>

Изменение элементов управления: MyTreeView для простого TreeView позволит приложению нормально работать

ETA2: XML для Брэдли:

  <?xml version="1.0" encoding="utf-8" ?>
  <Categories>
    <Category Name="1">
      <SubCategory Name="A"/>
      <SubCategory Name="B"/>
    </Category>
    <Category Name="2">
      <SubCategory Name="C"/>
      <SubCategory Name="D"/>
      <SubCategory Name="E"/>
      <SubCategory Name="F"/>
      <SubCategory Name="G"/>
      <SubCategory Name="H"/>
    </Category>
    <Category Name="3">
      <SubCategory Name="I"/>
      <SubCategory Name="J"/>
    </Category>
    <Category Name="4">
      <SubCategory Name="K"/>
      <SubCategory Name="L"/>
    </Category>
  </Categories>

1 Ответ

0 голосов
/ 30 января 2019

Несколько ошибок в вашем коде, но вы близки.Следует иметь в виду, что такие вещи, как DataType, используются, когда вы сериализовали свои XML-данные в определенный тип класса.Вы не получаете преимуществ от этого, когда используете XmlDataProvider, все данные сериализуются в универсальные классы данных XML, поэтому вам придется действовать немного иначе, чем в большинстве примеров кода TreeView, который вы найдете в сети.

В вашем случае вам нужно специально привязать все корневые элементы к ресурсу HierarchicalDataTemplate, который вы объявляете с помощью ключа, а затем снова связать его со списком детей через XPath.Это должно сделать этот трюк:

<Window.Resources>

    <XmlDataProvider x:Key="treeViewStructure" Source="Data/treeViewStructure.xml" />

    <HierarchicalDataTemplate x:Key="SubCategory">
        <TextBlock Text="{Binding XPath=@Name}" />
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate x:Key="Category" ItemsSource="{Binding XPath=SubCategory}" ItemTemplate="{StaticResource SubCategory}">
        <TextBlock Text="{Binding XPath=@Name}" />
    </HierarchicalDataTemplate>

    <!-- force all treeviewitems to be initially expanded -->
    <Style TargetType="{x:Type TreeViewItem}">
        <Setter Property="IsExpanded" Value="True" />
    </Style>

</Window.Resources>

<TreeView
    ItemsSource="{Binding Source={StaticResource treeViewStructure}, XPath=/Categories/Category}"
    ItemTemplate="{StaticResource Category}" />

Результат:

enter image description here

Также, если вам явно не нужны разные шаблоны для каждогозатем, используя узел, WPF выяснит, что ваши дети сами не имеют детей:

<HierarchicalDataTemplate x:Key="Category" ItemsSource="{Binding XPath=SubCategory}" >
    <TextBlock Text="{Binding XPath=@Name}" />
</HierarchicalDataTemplate>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...