WPF: изменить стиль ViewBox в зависимости от объема данных - PullRequest
1 голос
/ 03 мая 2010

У меня есть приложение WPF, в котором есть ViewBox для отображения элементов в моей коллекции, с использованием сетки из 2 столбцов для моих результатов.

Что я хотел бы сделать, так это изменить количество столбцов в зависимости от количества предметов в моей коллекции. Например, если в списке <10 элементов, отобразите их всего в 1 столбце; Если в моем списке 10 пунктов, то покажите их в 2 столбцах; Если в моем списке 20 пунктов, тогда покажите 3 столбца. </p>

Вот что у меня есть на данный момент:

<Viewbox>
   <ItemsControl ItemsSource="{Binding myCollection}" Style="{DynamicResource myStyle}" />
</Viewbox>

Вот что в данный момент определяет myStyle:

<Style x:Key="myStyle" TargetType="{x:Type ItemsControl}">
   <Setter Property=ItemsControl.ItemsPanel">
      <Setter.Value>
         <ItemsPanelTemplate>
           <UniformGrid Columns="2" />
         </ItemsPanelTemplate>
      </Setter.Value>
   </Setter>
</Style>

Как я могу заставить этот код работать с вышеуказанным требованием? Спасибо.

Ответы [ 2 ]

2 голосов
/ 03 мая 2010

Вы можете привязать свойство Columns к количеству элементов и использовать соответствующий IValueConverter для определения количества столбцов, например:

<UniformGrid Columns="{Binding Items.Count, Converter={local:ItemsToColumnConverter}}" />

Обратите внимание, что вам может понадобиться добавить RelativeSource к этой привязке, чтобы она заработала.

И IValueConverter, подобный этому:

public class ItemsToColumnConverter : IValueConverter
{
    // ...
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int numItems = (int)value;
        if (numItems < 10)
            return 1;
        else if (numItems < 20)
            return 2;
        else if (numItems < 30)
            return 3;
        else
            return numItems / 10;
    }

    public object ConvertBack(...)
    {
        throw new NotSupportedException();
    }
}

Конечно, вы могли бы также заставить этот конвертер использовать другую математическую логику, которая избегает всех вещей if-elseif-else.

1 голос
/ 03 мая 2010

Как насчет использования DataTrigger для установки определенного стиля? Может быть выполнимо, если у вас есть небольшое количество кортежей «если размер, то столбцы».
Я вижу, что нет эквивалента ItemsPanelStyleSelector (аналогично ItemContainerStyleSelector).

Обновление: работает. Хотя я бы тоже взглянул на другой ответ. Используйте valueconverter, чтобы связать значение Columns со значением, возвращаемым ValueConverter.Convert (list.Count) - более чистый звук.

   public string[] Options { get; set;}

   public bool NeedsTwoColumns
   {
       get
       {
           return this.Options.Length > 4;
       }
   }

//Xaml
<ListBox ItemsSource="{Binding Options}">
            <ListBox.Style>
                <Style>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding NeedsTwoColumns}" Value="True">
                            <Setter Property="ItemsControl.ItemsPanel">
                                <Setter.Value>
                                    <ItemsPanelTemplate>
                                        <UniformGrid Columns="2"/>
                                    </ItemsPanelTemplate>
                                </Setter.Value>
                            </Setter>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ListBox.Style>
        </ListBox>
    <ListBox ItemsSource="{Binding Options}">
        <ListBox.Resources>
            <local:MyConverter x:Key="ListLengthToColumnCountConverter"/>
        </ListBox.Resources>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Columns="{Binding Options.Length, Converter={StaticResource ListLengthToColumnCountConverter}}"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>

//ValueConverter
public class MyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        int listSize = (int)value;
        return (int)(listSize / 3);
    } ...
...