#wpf #xaml #listview #styles #controltemplate
#wpf #xaml #listview #стили #controltemplate
Вопрос:
Хорошо, вот моя довольно простая проблема.
У меня есть ListView
, который я оформил так, чтобы он выглядел как проводник Windows.
Теперь я хотел бы сгруппировать элементы внутри. Поэтому я определил a GroupStyle
с помощью Expander
, чтобы сгруппировать его. Теперь группировка выполнена нормально.
Что мне не нравится, так это то, что теперь my ListView
отображает каждую группу в отдельной строке, в то время как я хотел бы иметь некоторую оболочку расширения, чтобы отображать много групп в одной строке.
Изображение лучше, чем какой-либо текст, я думаю.
Вот что у меня есть:
Вот что я хочу:
Я не могу найти, какое свойство мне следует стилизовать, чтобы GroupItems
поместиться в WrapPanel, точно так же, как я сделал для элементов.
Вот мой стиль ListView:
<ResourceDictionary>
<!-- Explorer-style layout-->
<DataTemplate x:Key="ExplorerView">
<StackPanel Orientation="Horizontal" Height="Auto" Width="150">
<Image Source="{Binding Path=Value.AppConfig.Appli.AppType, Converter={StaticResource TypeToIconConverter}}" Margin="5"
Height="50" Width="50"/>
<StackPanel VerticalAlignment="Center" Width="90">
<TextBlock Text="{Binding Path=Value.AppConfig.Appli.AppName}"
FontSize="13" HorizontalAlignment="Left" TextWrapping="WrapWithOverflow"
Margin="0,0,0,1" />
<TextBlock Text="{Binding Path=Value.AppConfig.Appli.AppType}" FontSize="9"
HorizontalAlignment="Left" Margin="0,0,0,1" />
</StackPanel>
</StackPanel>
</DataTemplate>
<!-- Group header style-->
<Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Width="310"
BorderBrush="CornflowerBlue">
<Expander.Header>
<DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="CornflowerBlue" x:Name="expContent"
Width="{Binding RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType={x:Type Expander}},
Path=Width}"
Height="{Binding RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType={x:Type ToggleButton}},
Path=ActualHeight}">
<CheckBox IsChecked="False" DockPanel.Dock="Right"/>
<TextBlock Text="{Binding Path=Name}" Foreground="White"
FontWeight="Bold" HorizontalAlignment="Center" />
</DockPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
<!-- (...) -->
<ListView ItemsSource="{Binding GroupedConfig, Mode=TwoWay}"
ItemTemplate="{StaticResource ExplorerView}">
<ListView.ItemsPanel>
<ItemsPanelTemplate >
<WrapPanel Width="{Binding (FrameworkElement.ActualWidth),
RelativeSource={RelativeSource
AncestorType=Expander}}"
ItemWidth="{Binding (ListView.View).ItemWidth,
RelativeSource={RelativeSource AncestorType=ListView}}"
ItemHeight="{Binding (ListView.View).ItemHeight,
RelativeSource={RelativeSource AncestorType=ListView}}" />
<!--MinWidth="{Binding ItemWidth,
RelativeSource={RelativeSource Self}}"-->
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}" />
</ListView.GroupStyle>
</ListView>
Есть идеи?
Я пытаюсь вставить что-нибудь подходящее Setter
в стиле, определенном для GroupItem
, но я начинаю думать, что это неправильный способ сделать.
Спасибо!
Ответ №1:
Я, наконец, нашел нужное свойство для редактирования после многих попыток.
Я думаю, было бы полезно опубликовать это здесь, если кому-нибудь понадобится что-то сделать с таким же поведением:
Итак, у нас действительно есть свойство Panel
в GroupStyle
, в которое мы можем добавить это так необходимое WrapPanel
:
<ListView.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<WrapPanel Width="800" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</ListView.GroupStyle>
Комментарии:
1. В .NET 4.5 больше нет необходимости добавлять GroupStyle. Панель, просто устанавливаю ListBox. ItemsPanel достаточно. Это может быть довольно неприятно, если вы разработали приложение под управлением .NET 4.5, а затем видите, что все испорчено на клиентах, которые только что запустили 4.0. MS добавила довольно много подводных камней с обновлением 4.5 на месте…
Ответ №2:
На случай, если кто-нибудь здесь, как я пытаюсь обернуть элементы списка, но на основе неизвестного количества элементов, поэтому вы не можете установить ширину, подобную приведенному выше ответу, вот как я это сделал.
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" MaxHeight="{Binding Converter={StaticResource ListBoxHeightToItemsPanelHeightConverter}, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}, Path=ActualHeight}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
В моем конвертере я просто вычитаю 30, чтобы учесть высоту заголовка.
Вот полный код:
<ListBox.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Margin="8" FontSize="18" TextAlignment="Center" FontWeight="Bold" Foreground="White" >
<TextBlock.Text>
<Binding Path="Name"/>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</ListBox.GroupStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" MaxHeight="{Binding Converter={StaticResource ListBoxHeightToGroupStyleHeightConverter}, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}, Path=ActualHeight}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Template>
<ControlTemplate>
<!-- Your template here. -->
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemTemplate>
<DataTemplate >
<!-- Your template here. -->
</DataTemplate>
</ListBox.ItemTemplate>
Надеюсь, это поможет кому-то сэкономить время!