Растягивание элементов управления для заполнения ItemsControl
-
13-09-2019 - |
Вопрос
Я пытаюсь написать простой учебный проект WPF, который создает набор кнопок внутри главного окна с изменяемым размером.Должен быть один Button
для каждой записи в коллекции, и содержимое этой коллекции может меняться во время выполнения.Я хочу, чтобы кнопки заполняли все окно (например.1 кнопка @ ширина 100 %, 2 кнопки @ ширина 50 %, 3 кнопки @ ширина 33 % и т. д.все на высоте 100%).Упрощенная версия того, что я написал до сих пор:
<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;
Это приводит к следующему:
Мне не удалось растянуть кнопки по ширине, и мои попытки использовать Grid
вместо StackPanel
были бесплодны.
Затем, в качестве дополнительного улучшения, я был бы признателен за предложения о том, как настроить его так, чтобы, если кнопок так много, что они не могут правильно разместиться на строке или они уже порогового значения, они переносились на новую строку (тем самым уменьшая вдвое высоту кнопок при переходе от 1 к 2 строкам).
Я хотел бы подчеркнуть, что мне хотелось бы знать, как это сделать, WPF-способ.Я понимаю, что могу использовать сообщения об изменении размера окна и явно изменять размер элементов управления, и именно так я бы сделал это с MFC или WinForms, но из того, что я прочитал, это не то, как такие вещи следует делать с WPF.
Решение
Замените панель элемента управления на UniformGrid, это изменит размер всех дочерних элементов, чтобы все подходило точно:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Другие советы
Я смог использовать ответ Нира, чтобы выполнить свой дополнительный критерий, позволяющий растягивать несколько строк под управлением WPF.
Сначала вы должны иметь возможность изменять свойства шаблона. UniformGrid.Для этого вам нужно сохранить ссылку на него.Есть несколько методов для этого.Я решил справиться с Загружено мероприятие для UniformGrid и сохраните ссылку в это время.
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" Loaded="UniformGrid_Loaded" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
И в коде позади:
UniformGrid uniformgridButtons;
private void UniformGrid_Loaded(object sender, RoutedEventArgs e)
{
uniformgridButtons = sender as UniformGrid;
}
Затем обработайте РазмерИзменен событие и настройте параметр строк в соответствии с любыми критериями.
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));
}
}
Таким образом, это позволяет WPF управлять растяжением, как в ответе Нира, но позволяет явно регулировать количество строк.Приведенный выше код дает такой результат:
(Анимированный образец здесь)
Обновление 28.08.2009:
Я адаптировал свое учебное приложение так, чтобы ItemsControl
был в DataTemplate
в отдельном ResourceDictionary
.Однако такие события, как Loaded
не может быть обработан во внешнем ResourceDictionary
XAML-файл, поскольку он не имеет кода программной части (обычно).Поэтому мне нужно было кэшировать ссылку на UniformGrid
используя другую технику.
вместо этого я использовал Алана Хэя FindItemsPanel
метод (10-й ответ).Сначала я заменил ItemsControl
с :
<ContentPresenter x:Name="contentpresenterButtons" Content="{Binding obscolButtons}" />
Тогда в моем ResourceDictionary
, я положил ItemsControl
в DataTemplate
:
<DataTemplate DataType="{x:Type local:Buttons}">
<ItemsControl ...
</DataTemplate>
Наконец, я сохранил ссылку на шаблон UniformGrid
вот так:
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
}
Это работает так же, как и мое предыдущее решение, но без необходимости использования обработчика событий в ResourceDictionary
.
<!-- 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;
}
}