GridSplitter
Der GridSplitter liegt in einem Grid und verschiebt die Grenze zwischen den Spuren neben ihm. Pixel- und Stern-Spuren folgen den Regeln von WPF, MinWidth und MaxWidth gelten. Ziehen Sie mit der Maus oder fokussieren Sie einen Teiler und nutzen Sie die Pfeiltasten (Esc bricht ein Ziehen ab). Mit ShowsPreview folgt dem Zeiger eine Leiste, und die Spuren ändern sich erst beim Loslassen.


KXAML
GridSplitterSeite.kxaml
<StackPanel xmlns="https://ui.kuonen.org/kxaml"
xmlns:x="https://ui.kuonen.org/kxaml/x"
x:Class="Kuonen.UI.Galerie.Seiten.GridSplitterVorfuehrung"
Spacing="8">
<TextBlock Text="Spalten: Pixel, Stern und Grenzen" FontWeight="SemiBold" />
<!-- Pixel (60 bis 200) | Teiler | 1* | Teiler | 2* (mindestens 80). -->
<Grid x:Name="Spalten" Width="420" Height="80" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" MinWidth="60" MaxWidth="200" />
<ColumnDefinition Width="6" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="6" />
<ColumnDefinition Width="2*" MinWidth="80" />
</Grid.ColumnDefinitions>
<Border CornerRadius="4" Background="#CCE4F7" Grid.Column="0">
<TextBlock Text="Pixel 60 bis 200" Foreground="#1B1B1B" Margin="8,0,8,0" VerticalAlignment="Center" />
</Border>
<GridSplitter HorizontalAlignment="Stretch" x:Name="Teiler1" Grid.Column="1" DragDelta="Teiler_Bewegt" DragCompleted="Teiler_Fertig" KeyDown="Teiler_Taste" />
<Border CornerRadius="4" Background="#FDE7C5" Grid.Column="2">
<TextBlock Text="1*" Foreground="#1B1B1B" Margin="8,0,8,0" VerticalAlignment="Center" />
</Border>
<GridSplitter HorizontalAlignment="Stretch" x:Name="Teiler2" Grid.Column="3" DragDelta="Teiler_Bewegt" DragCompleted="Teiler_Fertig" KeyDown="Teiler_Taste" />
<Border CornerRadius="4" Background="#D3F0D4" Grid.Column="4">
<TextBlock Text="2*, mindestens 80" Foreground="#1B1B1B" Margin="8,0,8,0" VerticalAlignment="Center" />
</Border>
</Grid>
<TextBlock Text="Zeilen" FontWeight="SemiBold" />
<Grid x:Name="Zeilen" Width="420" Height="150" HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="6" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border CornerRadius="4" Background="#F5D0E0">
<TextBlock Text="Oben" Foreground="#1B1B1B" Margin="8,0,8,0" VerticalAlignment="Center" />
</Border>
<GridSplitter HorizontalAlignment="Stretch" x:Name="ZeilenTeiler" Grid.Row="1" DragDelta="Teiler_Bewegt" DragCompleted="Teiler_Fertig" KeyDown="Teiler_Taste" />
<Border CornerRadius="4" Background="#E2D9F3" Grid.Row="2">
<TextBlock Text="Unten" Foreground="#1B1B1B" Margin="8,0,8,0" VerticalAlignment="Center" />
</Border>
</Grid>
<TextBlock x:Name="Stand" Text="Ziehen Sie einen Teiler oder drücken Sie eine Pfeiltaste." />
<StackPanel Orientation="Horizontal" Spacing="16">
<CheckBox x:Name="Vorschau" Content="ShowsPreview" Click="Vorschau_Click" />
<CheckBox x:Name="Raster" Content="DragIncrement 10" Click="Raster_Click" />
</StackPanel>
</StackPanel>GridSplitterSeite.kxaml.cs
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Eingabe;
using Kuonen.UI.Ereignisse;
using Kuonen.UI.Media;
namespace Kuonen.UI.Galerie.Seiten;
public sealed partial class GridSplitterSeite
{
protected override Func<UIElement>? KxamlFabrik => () => new GridSplitterVorfuehrung();
}
/// <summary>KXAML-Fassung der GridSplitter-Seite: der Baum steht in GridSplitterSeite.kxaml, hier nur das Verhalten.</summary>
public sealed partial class GridSplitterVorfuehrung
{
public GridSplitterVorfuehrung() => InitializeComponent();
private void Zeige()
{
var s = Spalten.ColumnDefinitions;
var z = Zeilen.RowDefinitions;
Stand.Text = $"Spalten: {Math.Round(s[0].ActualWidth)} | {Math.Round(s[2].ActualWidth)} | {Math.Round(s[4].ActualWidth)} Zeilen: {Math.Round(z[0].ActualHeight)} | {Math.Round(z[2].ActualHeight)}";
}
private void Teiler_Bewegt(object sender, ZiehArgs e) => Zeige();
private void Teiler_Fertig(object sender, ZiehArgs e) => Zeige();
private void Teiler_Taste(object sender, KeyEventArgs e) => Zeige();
private void Vorschau_Click(object sender, RoutedEventArgs e)
{
foreach (var t in new[] { Teiler1, Teiler2, ZeilenTeiler }) t.ShowsPreview = Vorschau.IsChecked == true;
}
private void Raster_Click(object sender, RoutedEventArgs e)
{
foreach (var t in new[] { Teiler1, Teiler2, ZeilenTeiler }) t.DragIncrement = Raster.IsChecked == true ? 10 : 1;
}
}C#
GridSplitterSeite.cs
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Layout;
using Kuonen.UI.Media;
namespace Kuonen.UI.Galerie.Seiten;
/// <summary>Galerie-Seite: <see cref="GridSplitter"/>.</summary>
public sealed partial class GridSplitterSeite : GalerieSeite
{
public override string Titel => "GridSplitter";
public override string Beschreibung =>
"Der GridSplitter liegt in einem Grid und verschiebt die Grenze zwischen den Spuren neben ihm. Pixel- und Stern-Spuren "
+ "folgen den Regeln von WPF, MinWidth und MaxWidth gelten. Ziehen Sie mit der Maus oder fokussieren Sie einen Teiler und "
+ "nutzen Sie die Pfeiltasten (Esc bricht ein Ziehen ab). Mit ShowsPreview folgt dem Zeiger eine Leiste, und die Spuren "
+ "ändern sich erst beim Loslassen.";
public override string Stichworte => "GridSplitter Teiler Splitter ResizeDirection ResizeBehavior ShowsPreview DragIncrement KeyboardIncrement Spalten Zeilen Grössen ziehen";
public override string Datei => nameof(GridSplitterSeite);
private static readonly SolidColorBrush Schwarz = new(Color.FromRgb(0x1B, 0x1B, 0x1B));
private static Border Feld(string text, uint farbe) => new()
{
CornerRadius = new CornerRadius(4),
Background = new SolidColorBrush(Color.FromRgb((byte)(farbe >> 16), (byte)(farbe >> 8), (byte)farbe)),
Child = new TextBlock { Text = text, Foreground = Schwarz, Margin = new Thickness(8, 0, 8, 0), VerticalAlignment = VerticalAlignment.Center },
};
public override UIElement Baue()
{
// Spalten: Pixel (60 bis 200) | Teiler | 1* | Teiler | 2* (mindestens 80). Jeder Teiler verschiebt die Spuren neben sich.
var spalten = new Grid { Width = 420, Height = 80, HorizontalAlignment = HorizontalAlignment.Left };
spalten.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Pixel(120), MinWidth = 60, MaxWidth = 200 });
spalten.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Pixel(6) });
spalten.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star(1) });
spalten.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Pixel(6) });
spalten.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star(2), MinWidth = 80 });
var teiler1 = new GridSplitter { HorizontalAlignment = HorizontalAlignment.Stretch };
var teiler2 = new GridSplitter { HorizontalAlignment = HorizontalAlignment.Stretch };
var zeilenTeiler = new GridSplitter { HorizontalAlignment = HorizontalAlignment.Stretch };
(UIElement Element, int Spalte)[] inhalt =
[
(Feld("Pixel 60 bis 200", 0xCCE4F7), 0), (teiler1, 1), (Feld("1*", 0xFDE7C5), 2), (teiler2, 3), (Feld("2*, mindestens 80", 0xD3F0D4), 4),
];
foreach (var (element, spalte) in inhalt)
{
Grid.SetColumn(element, spalte);
spalten.Children.Add(element);
}
// Zeilen: oben und unten Stern, dazwischen ein Teiler (die Richtung erkennt er an seiner Form).
var zeilen = new Grid { Width = 420, Height = 150, HorizontalAlignment = HorizontalAlignment.Left };
zeilen.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star(1) });
zeilen.RowDefinitions.Add(new RowDefinition { Height = GridLength.Pixel(6) });
zeilen.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star(1) });
var oben = Feld("Oben", 0xF5D0E0);
var unten = Feld("Unten", 0xE2D9F3);
Grid.SetRow(zeilenTeiler, 1);
Grid.SetRow(unten, 2);
zeilen.Children.Add(oben);
zeilen.Children.Add(zeilenTeiler);
zeilen.Children.Add(unten);
var stand = new TextBlock { Text = "Ziehen Sie einen Teiler oder drücken Sie eine Pfeiltaste." };
void Zeige()
{
var s = spalten.ColumnDefinitions;
var z = zeilen.RowDefinitions;
stand.Text = $"Spalten: {Math.Round(s[0].ActualWidth)} | {Math.Round(s[2].ActualWidth)} | {Math.Round(s[4].ActualWidth)} Zeilen: {Math.Round(z[0].ActualHeight)} | {Math.Round(z[2].ActualHeight)}";
}
var alle = new[] { teiler1, teiler2, zeilenTeiler };
foreach (var t in alle)
{
t.DragDelta += (_, _) => Zeige();
t.DragCompleted += (_, _) => Zeige();
t.KeyDown += (_, _) => Zeige();
}
var vorschau = new CheckBox { Content = "ShowsPreview" };
vorschau.Click += (_, _) =>
{
foreach (var t in alle) t.ShowsPreview = vorschau.IsChecked == true;
};
var raster = new CheckBox { Content = "DragIncrement 10" };
raster.Click += (_, _) =>
{
foreach (var t in alle) t.DragIncrement = raster.IsChecked == true ? 10 : 1;
};
var seite = new StackPanel { Spacing = 8 };
seite.Children.Add(new TextBlock { Text = "Spalten: Pixel, Stern und Grenzen", FontWeight = 600 });
seite.Children.Add(spalten);
seite.Children.Add(new TextBlock { Text = "Zeilen", FontWeight = 600 });
seite.Children.Add(zeilen);
seite.Children.Add(stand);
seite.Children.Add(new StackPanel { Orientation = Orientation.Horizontal, Spacing = 16, Children = { vorschau, raster } });
return seite;
}
}