Как смешать связанные с данными и статические уровни в TreeView?

посмотрите на команду базового имени:

NAME=$(basename /foo/fizzbuzz.bar .bar)
12
задан psubsee2003 29 December 2014 в 11:05
поделиться

3 ответа

О боже, это невероятно неприятная задача. Я сам много раз пробовал это делать. У меня было очень похожее требование, когда у меня было что-то вроде класса Customer, который имеет как коллекцию Locations, так и коллекцию Orders. Я хотел, чтобы местоположения и заказы были «папками» в древовидной структуре. Как вы обнаружили, все примеры TreeView, которые показывают вам, как выполнить привязку к самореферентным типам, в значительной степени бесполезны.

Сначала я прибег к ручному построению дерева объектов FolderItemNode и ItemNode, которые я бы сгенерировал в ViewModel, но это побеждает цель привязки, потому что она не реагирует на базовые изменения коллекции.

Затем я придумал подход, который, кажется, работает довольно хорошо.

  • В описанной выше объектной модели, Я создал классы LocationCollection и OrderCollection. Оба они наследуют от ObservableCollection и переопределяют ToString () для возврата «Locations» и «Orders» соответственно.
  • Я создаю класс MultiCollectionConverter, который реализует IMultiValueConverter
  • Я создал класс FolderNode, у которого есть свойство Name и Items. Это объект-заполнитель, который будет представлять ваши «папки» в древовидном представлении.
  • Определите иерархические таблицы данных, которые используют MultiBinding везде, где вы хотите сгруппировать несколько дочерних коллекций в папки.

Результирующий XAML выглядит аналогично приведенному ниже коду и вы можете получить zip-файл со всеми классами и XAML в рабочем примере .

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">

    <Window.Resources>

        <!-- THIS IS YOUR FOLDER NODE -->
        <HierarchicalDataTemplate DataType="{x:Type Local:FolderNode}" ItemsSource="{Binding Items}">
            <Label FontWeight="Bold" Content="{Binding Name}" />
        </HierarchicalDataTemplate>

        <!-- THIS CUSTOMER HAS TWO FOLDERS, LOCATIONS AND ORDERS -->
        <HierarchicalDataTemplate DataType="{x:Type Local:Customer}">
            <HierarchicalDataTemplate.ItemsSource>
                <MultiBinding>
                    <MultiBinding.Converter>
                        <Local:MultiCollectionConverter />
                    </MultiBinding.Converter>
                    <Binding Path="Locations" />
                    <Binding Path="Orders" />
                </MultiBinding>
            </HierarchicalDataTemplate.ItemsSource>
            <Label Content="{Binding Name}" />
        </HierarchicalDataTemplate>

        <!-- OPTIONAL, YOU DON'T NEED SPECIFIC DATA TEMPLATES FOR THESE CLASSES -->
        <DataTemplate DataType="{x:Type Local:Location}">
            <Label Content="{Binding Title}" />
        </DataTemplate>
        <DataTemplate DataType="{x:Type Local:Order}">
            <Label Content="{Binding Title}" />
        </DataTemplate>

    </Window.Resources>

    <DockPanel>
        <TreeView Name="tree" Width="200" DockPanel.Dock="Left" />
        <Grid />
    </DockPanel>

</Window>

Folders in TreeView

12
ответ дан 2 December 2019 в 21:03
поделиться

Проблема в том, что TreeView не очень хорошо подходит для того, что вы хотите выполнить: он ожидает, что все подузлы будут одного типа. Поскольку ваш узел базы данных имеет узел типа Collection > и типа Collection >, вы не можете использовать HierarchicalDataTemplate. Лучше использовать вложенные экспандеры, содержащие ListBoxes.

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

<Window x:Class="TreeViewSelection.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:smo="clr-namespace:TreeViewSelection"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <Style TargetType="ListBox">
            <Setter Property="BorderThickness" Value="0"/>
        </Style>
        <DataTemplate DataType="{x:Type smo:Database}">
                <TreeViewItem Header="{Binding Name}">
                    <TreeViewItem Header="Schemas">
                        <ListBox ItemsSource="{Binding Schemas}"/>
                    </TreeViewItem>
                    <TreeViewItem Header="Users">
                    <ListBox ItemsSource="{Binding Users}"/>
                </TreeViewItem>
                </TreeViewItem> 
        </DataTemplate>
        <DataTemplate DataType="{x:Type smo:User}" >
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type smo:Schema}">
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <TreeViewItem ItemsSource="{Binding DataBases}" Header="All DataBases">
        </TreeViewItem>
    </StackPanel>
</Window>

using System.Collections.ObjectModel;
using System.Windows;

namespace TreeViewSelection
{
    public partial class Window1 : Window
    {
        public ObservableCollection<Database> DataBases { get; set; }
        public Window1()
        {
            InitializeComponent();
            DataBases = new ObservableCollection<Database>
                            {
                                new Database("Db1"),
                                new Database("Db2")
                            };
            DataContext = this;
        }
    }

    public class Database:DependencyObject
    {
        public string Name { get; set; }
        public ObservableCollection<Schema> Schemas { get; set; }
        public ObservableCollection<User> Users { get; set; }

        public Database(string name)
        {
            Name = name;
            Schemas=new ObservableCollection<Schema>
                        {
                            new Schema("Schema1"),
                            new Schema("Schema2")
                        };
            Users=new ObservableCollection<User>
                      {
                          new User("User1"),
                          new User("User2")
                      };
        }
    }

    public class Schema:DependencyObject
    {
        public string Name { get; set; }
        public Schema(string name)
        {
            Name = name;   
        }
    }

    public class User:DependencyObject
    {
        public string Name { get; set; }
        public User(string name)
        {
            Name = name;
        }
    }
}
2
ответ дан 2 December 2019 в 21:03
поделиться

You need to fill the properties you're using in your binding with data from your database. Currently you're using a new TreeViewItem, and using it as a datasource, so what you're saying about it seeing everything as a single node makes sense, as you've placed it in a single node.

You need to load your database data and attach it to the properties you've used in your WPF template as binding items.

0
ответ дан 2 December 2019 в 21:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: