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

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

<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?

3 ответа

Решение

Первоначально я смотрел на это с помощью 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, - это добавление возможности "отключать" рассмотрение определенных элементов (например, вашего слайдера). Это может быть сделано как дополнительное прикрепленное свойство.

Другие вопросы по тегам