Растягивание элементов управления для заполнения ItemsControl

StackOverflow https://stackoverflow.com/questions/1270078

  •  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;

Это приводит к следующему:

alt text

Мне не удалось растянуть кнопки по ширине, и мои попытки использовать 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 управлять растяжением, как в ответе Нира, но позволяет явно регулировать количество строк.Приведенный выше код дает такой результат:

alt text

(Анимированный образец здесь)


Обновление 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;
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top