Синхронизация ширины элементов управления WPF в WrapPanel

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

Вопрос

У меня есть этот случай

<WrapPanel>
    <CheckBox>Really long name</CheckBox>
    <CheckBox>Short</CheckBox>
    <CheckBox>Longer again</CheckBox>
    <CheckBox>Foo</CheckBox>
    <Slider MinWidth="200" />
</WrapPanel>

Я хочу, чтобы все флажки внутри WrapPanel были одинаковой ширины.

Добавление следующего почти достигнет желаемого эффекта

<WrapPanel.Resources>
    <Style TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
        <Setter Property="MinWidth" Value="75" />
    </Style>
</WrapPanel.Resources>

Однако я не хочу жестко задавать конкретную ширину, а позволить самому большому CheckBox установить ширину (вышеприведенное также не работает, если есть ширина > 75).

Ползунок является независимым и должен быть больше, чем CheckBoxes.

Я не хочу использовать Grid (с IsSharedSizeScope), поскольку мне не нужно жестко закодированное количество столбцов.

В этой статье представлено интересное решение, но было бы неплохо решить проблему, не создавая пользовательский элемент управления или не используя код C #.

Каков наилучший способ сделать это, желательно только в XAML?

Это было полезно?

Решение

Первоначально я смотрел на это с помощью IsSharedSizeGroup, но столкнулся с препятствиями, заставив его динамически применять к вещам вместо явной упаковки элементов. В этом случае создание AttachedProperty в коде или другом решении, основанном на коде, в конечном итоге может оказаться лучше, чем подход, основанный только на XAML. Однако для создания чисто решения XAML мы можем использовать SharedSizeGroup в ColumnDefinition, чтобы поделиться размерами каждого элемента, а затем использовать установить IsSharedSizeScope в WrapPanel. В результате все содержимое в WrapPanel с одной и той же SharedSizeGroup будет иметь общую ширину для столбцов и высоту для строк. Чтобы обернуть ComboBox и, возможно, ComboBox, которые в данный момент отсутствуют в XAML, но будут добавлены в WrapPanel, мы можем создать стиль и повторно создать шаблон ComboBox, чтобы в основном обернуть его сеткой.

<WrapPanel Grid.IsSharedSizeScope="True">
  <WrapPanel.Resources>
    <Style TargetType="{x:Type CheckBox}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type CheckBox}">
            <Grid Background="LightBlue">
              <Grid.ColumnDefinitions>
                <ColumnDefinition SharedSizeGroup="WrapPannelGroup" />
              </Grid.ColumnDefinitions>
              <CheckBox Style="{x:Null}"
                        IsChecked="{TemplateBinding IsChecked}">
                <!--Other TemplateBindings-->
                <CheckBox.Content>
                  <ContentPresenter />
                </CheckBox.Content>
              </CheckBox>
            </Grid>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

  </WrapPanel.Resources>
  <CheckBox>Really long name</CheckBox>
  <CheckBox>Short</CheckBox>
  <CheckBox IsChecked="True">Longer again</CheckBox>
  <CheckBox>Foo</CheckBox>
  <Slider MinWidth="200" />
</WrapPanel>

Здесь мы повторно шаблонируем все CheckBox-ы без стиля внутри WrapPannel, чтобы вместо этого быть CheckBoxes, окруженными Grid. Однако из-за этого нам нужно повторно связать все свойства CheckBoxes, которые мы хотим сохранить. Хотя это может стать обременительным, оно также допускает чистый подход XAML.

Другие советы

Вы можете добавить свойство или конвертер, который выполняет необходимую работу, а затем привязать к нему ширину каждого столбца. Свойство или конвертер могут получить доступ ко всему списку элементов, найти самый широкий и вернуть нужную ширину для всех элементов.

Лучший способ сделать это - использовать CustomControl как статью, которую вы опубликовали.

Любое решение, с которым вы столкнетесь, будет вынуждено перебирать список элементов и находить максимальную ширину на этапе измерения.

Любой вид ответа только на XAML должен быть предоставлен OOTB (например, IsSharedSizeScope) или использовать некий вид мультисвязывания, чтобы связать элементы вместе. Таким образом, любой ответ XAML будет полон разметки, что делает его более многословным (и менее элегантным).

Единственное изменение, которое я вижу в опубликованной вами статье CodeProject, - это добавление возможности "выключить". рассмотрение определенных элементов (например, вашего слайдера). Это можно сделать как дополнительное прикрепленное свойство.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top