Stretching Kontrollen zu füllen Items
-
13-09-2019 - |
Frage
Ich versuche, ein einfaches WPF Lernprojekt zu schreiben, die eine Reihe von Schaltflächen in einem resizeable Hauptfenster erzeugt. Es gibt eine Button
pro Eintrag in einer Sammlung sein, und der Inhalt dieser Sammlung während der Laufzeit kann variieren. Ich will die Tasten, um das gesamte Fenster (beispielsweise 1-Taste @ 100% Breite, 2 Tasten @ 50% Breite, 3 Tasten @ 33% Breite, etc. Alle auf 100% Höhe) zu füllen. Eine vereinfachte Version von dem, was ich geschrieben habe, so weit ist:
<ItemsControl x:Name="itemscontrolButtons" ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Tag="{Binding}">
<TextBlock Text="{Binding}" />
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
...
List<string> listButtonTexts = new List<string>() { "Button1", "Button2" };
...
itemscontrolButtons.DataContext = listButtonTexts;
Daraus ergibt sich folgendermaßen aus:
Ich habe nicht in der Lage gewesen, die Tasten machen strecken die Breite und meine Versuche, passen ein Grid
statt StackPanel
waren ergebnislos zu verwenden.
Dann, als eine optionale Verbesserung, würde ich Vorschläge zu schätzen weiß, wie es so einstellen, dass, wenn es so viele Tasten sind, dass sie nicht richtig auf einer Linie passen oder schmaler sind als ein Schwellenwert ist, es auf eine neue Zeile umgebrochen wird ( wodurch die Taste Höhen zu halbieren, wenn 1 bis 2 Reihen zu gehen).
Ich möchte betonen, dass ich wissen möchte, wie dies die tun WPF Weg . Ich weiß, ich kann verbrauchen Fenster Meldungen der Größe und die Steuerelemente explizit die Größe, und das ist, wie ich es mit MFC oder WinForms getan haben würde, aber von dem, was ich gelesen habe, das ist nicht, wie solche Dinge sollen mit WPF erfolgen.
Lösung
Ersetzen der Panels Artikel Steuerung mit einem Uniform, wird diese Größe alle Kinder so alles paßt genau:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Andere Tipps
ich in der Lage war, auf Nir Antwort zu bauen mein optional Kriterium zu erfüllen, so dass für WPF-Managed mit mehreren Reihen Stretching.
Zuerst müssen Sie in der Lage sein, die Eigenschaften der Vorlage Uniform zu ändern. Dazu müssen Sie einen Verweis auf sie speichern müssen. Es gibt mehrere Methoden zur Durchführung diese . Ich entschied mich für die Loaded Ereignis für die Uniform und speichern eine Referenz zu diesem Zeitpunkt zu behandeln.
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" Loaded="UniformGrid_Loaded" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Und in der Code-behind:
UniformGrid uniformgridButtons;
private void UniformGrid_Loaded(object sender, RoutedEventArgs e)
{
uniformgridButtons = sender as UniformGrid;
}
Dann behandeln Sie die Sizechanged Ereignis und stellen Sie die Zeilen Parameter nach, was auch immer Kriterien, die Sie wünschen.
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
if ((uniformgridButtons != null) && (this.Width > 0))
{
// Set row count according to your requirements
uniformgridButtons.Rows = (int)(1 + ((this.MinWidth * iButtonCount) / this.Width));
}
}
So ermöglicht diese WPF das Strecken wie in Nir Antwort zu verwalten, sondern ermöglicht es Ihnen, explizit die Anzahl der Zeilen anpassen. Der obige Code gibt dieses Ergebnis:
(Animierte Probe hier )
Update 2009.08.28:
Ich hatte meine Einstellung Lernanwendung, so dass der ItemsControl
in einem DataTemplate
in einem separaten ResourceDictionary
war. Allerdings Ereignisse wie Loaded
nicht in einer externen ResourceDictionary
XAML-Datei behandelt werden, da es keinen Code-Behind (in der Regel) hat. Daher musste ich den Verweis auf die UniformGrid
mit einer anderen Technik cachen.
Ich benutzte stattdessen Alan Haighs FindItemsPanel
Methode (10 antworten) . Zuerst habe ich ersetzt die ItemsControl
mit:
<ContentPresenter x:Name="contentpresenterButtons" Content="{Binding obscolButtons}" />
Da ist in meinem ResourceDictionary
, habe ich die ItemsControl
im DataTemplate
:
<DataTemplate DataType="{x:Type local:Buttons}">
<ItemsControl ...
</DataTemplate>
Schließlich habe ich den Verweis auf den Templat-UniformGrid
als so gespeichert:
private void Window_Loaded(object sender, RoutedEventArgs e) {
uniformgridButtons = FindItemsPanel<UniformGrid>(contentpresenterButtons);
// Also call the code in Window_SizeChanged which I put in another method
}
Dies ist nur das gleiche wie meine frühere Lösung funktioniert, aber ein Event-Handler in den ResourceDictionary
ohne zu erfordern.
<!-- width must be explicitly set for this example -->
<StackPanel
Name="MyStack"
Orientation="Horizontal"
Width="250"
Load="Window_Loaded">
<Button/>
<Button/>
<Button/>
</StackPanel>
public void Window_Loaded(object sender, RoutedEventArgs e)
{
UIElementCollection elements = MyStack.Children;
int count = elements.Count;
foreach (UIElement element in elements)
{
if (element is Button)
((Button)element).Width = MyStack.Width / count;
}
}