TreeDataGrid
Ein DataGrid mit Baumzeilen: die erste Spalte rückt nach der Tiefe ein und zeigt das Aufklappzeichen. Auf- und Zuklappen fügt nur die Nachkommen ein; ein Klick auf einen Spaltenkopf sortiert Geschwister. Tasten wie im Explorer: Rechts und Links, Plus, Minus und Stern.


KXAML
TreeDataGridSeite.kxaml
<StackPanel xmlns="https://ui.kuonen.org/kxaml"
xmlns:x="https://ui.kuonen.org/kxaml/x"
xmlns:local="using:Kuonen.UI.Galerie.Seiten"
x:Class="Kuonen.UI.Galerie.Seiten.TreeDataGridVorfuehrung"
Spacing="12">
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Content="Alles aufklappen" Click="Alle_Click" />
<Button Content="Alles zuklappen" Click="Keine_Click" />
</StackPanel>
<!-- Wurzeln und Baumdaten kommen aus dem Code-Behind; die Baumspalte umhüllt eine Textspalte. -->
<TreeDataGrid x:Name="Gitter" Width="440" Height="260">
<DataGridExpanderColumn Header="Name" Width="220">
<DataGridTextColumn x:DataType="local:Ablage" Binding="{Binding Name, Mode=OneWay}" />
</DataGridExpanderColumn>
<DataGridTextColumn x:DataType="local:Ablage" Header="Typ" Width="80" Binding="{Binding Typ, Mode=OneWay}" />
<DataGridTextColumn x:DataType="local:Ablage" Header="Grösse" Width="80" Binding="{Binding Groesse, Mode=OneWay}" />
</TreeDataGrid>
</StackPanel>TreeDataGridSeite.kxaml.cs
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Ereignisse;
namespace Kuonen.UI.Galerie.Seiten;
public sealed partial class TreeDataGridSeite
{
protected override Func<UIElement>? KxamlFabrik => () => new TreeDataGridVorfuehrung();
}
/// <summary>KXAML-Fassung der TreeDataGrid-Seite: der Baum steht in TreeDataGridSeite.kxaml, hier Wurzeln, Baumdaten und die Knöpfe.</summary>
public sealed partial class TreeDataGridVorfuehrung
{
public TreeDataGridVorfuehrung()
{
InitializeComponent();
Gitter.Roots = TreeDataGridSeite.Wurzeln();
Gitter.Baum = new Baumdaten<Ablage>(a => a.Kinder);
}
private void Alle_Click(object sender, RoutedEventArgs e) => Gitter.ExpandAll();
private void Keine_Click(object sender, RoutedEventArgs e) => Gitter.CollapseAll();
}C#
TreeDataGridSeite.cs
using Kuonen.UI;
using Kuonen.UI.Bindung;
using Kuonen.UI.Controls;
using Kuonen.UI.Layout;
namespace Kuonen.UI.Galerie.Seiten;
/// <summary>Galerie-Seite: <see cref="TreeDataGrid"/>, Baumzeilen im DataGrid.</summary>
public sealed partial class TreeDataGridSeite : GalerieSeite
{
public override string Titel => "TreeDataGrid";
public override string Beschreibung =>
"Ein DataGrid mit Baumzeilen: die erste Spalte rückt nach der Tiefe ein und zeigt das Aufklappzeichen. Auf- und Zuklappen fügt nur die "
+ "Nachkommen ein; ein Klick auf einen Spaltenkopf sortiert Geschwister. Tasten wie im Explorer: Rechts und Links, Plus, Minus und Stern.";
public override string Stichworte => "Baum Tabelle Grid Ordner Explorer DataGridExpanderColumn Baumdaten aufklappen einrücken TreeListView";
public override string Datei => nameof(TreeDataGridSeite);
/// <summary>Ein kleiner Dateibaum: drei Ordner mit Unterordnern und Dateien.</summary>
public static Ablage[] Wurzeln()
{
var wurzeln = new List<Ablage>();
foreach (var ordner in new[] { "Bilder", "Dokumente", "Musik" })
{
var oben = new Ablage(ordner, "Ordner", 0);
for (int u = 1; u <= 3; u++)
{
var unter = new Ablage($"{ordner} {u}", "Ordner", 0);
for (int d = 1; d <= 4; d++) unter.Kinder.Add(new Ablage($"Datei {u}.{d}", "Datei", (d * 137 % 900) + (u * 10)));
oben.Kinder.Add(unter);
}
wurzeln.Add(oben);
}
return [.. wurzeln];
}
public override UIElement Baue()
{
var grid = new TreeDataGrid { Width = 440, Height = 260, Roots = Wurzeln(), Baum = new Baumdaten<Ablage>(a => a.Kinder) };
grid.Columns.Add(new DataGridExpanderColumn(new DataGridTextColumn { Binding = Zellbindung.Aus(BindingPath.Stufe<Ablage, string>("Name", a => a.Name), schreibbar: false) })
{
Header = "Name",
Width = GridLength.Pixel(220),
});
grid.Columns.Add(new DataGridTextColumn { Header = "Typ", Width = GridLength.Pixel(80), Binding = Zellbindung.Aus(BindingPath.Stufe<Ablage, string>("Typ", a => a.Typ), schreibbar: false) });
grid.Columns.Add(new DataGridTextColumn { Header = "Grösse", Width = GridLength.Pixel(80), Binding = Zellbindung.Aus(BindingPath.Stufe<Ablage, int>("Groesse", a => a.Groesse), schreibbar: false) });
var alle = new Button { Content = "Alles aufklappen" };
alle.Click += (_, _) => grid.ExpandAll();
var keine = new Button { Content = "Alles zuklappen" };
keine.Click += (_, _) => grid.CollapseAll();
var knoepfe = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8 };
knoepfe.Children.Add(alle);
knoepfe.Children.Add(keine);
var seite = new StackPanel { Spacing = 12 };
seite.Children.Add(knoepfe);
seite.Children.Add(grid);
return seite;
}
}
/// <summary>Ein Ordner oder eine Datei der Vorführung.</summary>
public sealed class Ablage(string name, string typ, int groesse)
{
public string Name { get; } = name;
public string Typ { get; } = typ;
public int Groesse { get; } = groesse;
public List<Ablage> Kinder { get; } = [];
}