WPF HierarchicalDataTemplate с множеством ItemsSource и пользовательским форматированием в TreeView - PullRequest
0 голосов
/ 20 октября 2019

В классе есть несколько наборов данных (элементы в коллекции имеют подэлементы). Вопрос состоит из двух частей.

Вопрос

Во-первых, как объединить несколько коллекций под одним элементом дерева? Во-вторых, как создать заголовок для коллекции?

Данные должны быть представлены следующим образом:

MasterItem
-SubItemsT1GeneratedHeader
--SubItem1
---SubVal
---SubVal
--SubItem1
---SubVal
---SubVal
-SubItem2
-SubItem2

Объекты

public class MasterItem : BaseItem {
    public ObservableCollection<SubItem1> subItem1s { get; set; }
    public ObservableCollection<SubItem2> subItem2s { get; set; } }
public class SubItem2 : BaseItem { }
public class SubItem1 : BaseItem {
    public ObservableCollection<SubVal> subVals { get; set; } }
public class SubVal : BaseItem { }
public class BaseItem : INotifyPropertyChanged {
    public BaseItem() { IsExpanded = true; }
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
    public string Name => this.GetType().Name;
    public bool _isExpanded;
    public bool IsExpanded {
        get { return this._isExpanded; }
        set {
            if (value != this._isExpanded){
                this._isExpanded = value;
                NotifyPropertyChanged();
            } }
    }
}

Код позади

InitializeComponent();
var mItem1 = new MasterItem()
{
    //needs to have label Type1SubItems
    subItem1s = new ObservableCollection<SubItem1>() {
        new SubItem1() {
            subVals = new ObservableCollection<SubVal>() { new SubVal(), new SubVal() } },
        new SubItem1() {
            subVals = new ObservableCollection<SubVal>() { new SubVal(), new SubVal() } } },
    //needs to have just name
    subItem2s = new ObservableCollection<SubItem2>() {
        new SubItem2(), new SubItem2() } };
var items = new ObservableCollection<MasterItem>() { mItem1 };
tree1.ItemsSource = items;

XAML (вывод не по желанию)

<TreeView Name="tree1">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:MasterItem}" ItemsSource="{Binding subItem1s}">
            <TextBlock Text="{Binding Name}"/>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:SubItem1}" ItemsSource="{Binding subVals}">
            <TextBlock Text="{Binding Name}"/>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

Одним из возможных решений было бы добавление промежуточного класса ксодержит коллекцию коллекций SubItem1 (т.е. subItems1). Затем MasterItem будет содержать коллекцию промежуточных классов (фактически только с одним элементом). Свойство Name промежуточного класса будет «SubItemsT1GeneratedHeader». Коллекция промежуточных классов и subItems2s может быть помещена в CompositeCollection, чтобы обеспечить только один ItemsSource для HierarchicalDataTemplate. Тогда я мог бы использовать предоставленное решение здесь . Но как можно дольше я бы хотел избежать изменений в структуре данных.

Другое возможное решение описано здесь . Это выглядит так, как я хочу, но мне нужно добавить контекстное меню и свойства к сгенерированному заголовку в xaml.

Еще одно ограничение решения состоит в том, что все элементы (включая заголовок) должны бытьвозможно расширение из кода с помощью свойства IsExpanded.

...