ListBox组中的垂直分隔符

时间:2017-01-10 12:33:24

标签: c# wpf listbox

我有一个ListBox我根据这样的属性进行分组:

CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(listbox.ItemsSource);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("CurrentDate");
view.GroupDescriptions.Add(groupDescription);

分组后我想在组之间添加一个垂直分隔符,我写了一个这样的代码:

<ListBox.GroupStyle>
    <GroupStyle>
        <GroupStyle.HeaderTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
                    <TextBlock Text="{Binding Path=Name}"
                               FontWeight="Bold"/>
                </StackPanel>
            </DataTemplate>
        </GroupStyle.HeaderTemplate>
        <GroupStyle.Panel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </GroupStyle.Panel>
    </GroupStyle>
</ListBox.GroupStyle>

但它看起来像这样:

enter image description here

虽然我希望分隔符完全消失但是当我试图增加分隔符的高度时,项目会随之下降。

2 个答案:

答案 0 :(得分:6)

诊断

当您使用ListBox + CollectionViewGroupStyle中的项目进行分组时,ListBox会显示GroupItem个控件列表,每个控件代表一个组的项目。 GroupItem基本上由ContentPresenter(用于显示标题)和ItemsPresenter(用于展示分组的项目)组成StackPanel

当您指定GroupStyle.HeaderTemplate时,它将用作上述ContentTemplate的{​​{1}}。因此,如果你增加ContentPresenter的高度,它仍将包含在Separator中,导致它垂直增长,并且项目仍然会堆叠在它下面 - 因此你的结果。

解决方案

为实现目标,您需要做的是重新模板ContentPresenter,以便GroupItemSeparator一起显示ContentPresenter,然后连线它使用ItemsPresenter。为方便起见,我们将其放入GroupStyle.ContainerStyle词典:

ListBox.Resources

请注意,我从标题模板中删除了分隔符。

以下是您可能希望得到的结果(我在<ListBox (...)> <ListBox.Resources> <ControlTemplate x:Key="GroupItemTemplate" TargetType="{x:Type GroupItem}"> <DockPanel> <Separator DockPanel.Dock="Left" Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <StackPanel> <ContentPresenter /><!-- This will be automatically wired --> <ItemsPresenter Margin="5,0,0,0" /><!-- So will this --> </StackPanel> </DockPanel> </ControlTemplate> </ListBox.Resource> <ListBox.GroupStyle> <GroupStyle> <GroupStyle.HeaderTemplate> <DataTemplate> <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" /> </DataTemplate> </GroupStyle.HeaderTemplate> <GroupStyle.ContainerStyle> <Style TargetType="{x:Type GroupItem}"> <Setter Property="Template" Value="{StaticResource GroupItemTemplate}" /> </Style> </GroupStyle.ContainerStyle> (...) </GroupStyle> </ListBox.GroupStyle> (...) </ListBox> 周围加上蓝色边框以区分#3和#4):

enter image description here

我提供的代码摘录默认情况下会给你#1(所有分隔符在整个ListBox中垂直拉伸)。

要实现#2(分隔符仅向下延伸到相应组的最后一项),您应该将ListBox添加到<Setter Property="VerticalAlignment" Value="Top" />。或者,您可以将其放在GroupStyle.ContainerStyle模板内的DockPanel上。

要获得#3(分隔符伸展到最大组的高度),您应该将GroupItem添加到VerticalAlignment="Top"(您的情况下为GroupStyle.Panel)内的面板中。

最后,通过将VirtualizingStackPanel放在ListBox上,可以实现#4(VerticalAlignment="Top"本身限制为最大组的大小)。

答案 1 :(得分:2)

我无法想象这是一个开箱即用的解决方案,因为你正试图转移群组。我已经做了一个例子,但它无法调整列的大小。 itemsarea中的宽度但不使用Seperators的标题:

<强>代码隐藏

public partial class Window1  {

    public Window1() {
      InitializeComponent();

      this._items.Add(new Item { Name = "one", DateTime = DateTime.Today });
      this._items.Add(new Item { Name = "two", DateTime = DateTime.Today.Subtract(new TimeSpan(1, 0, 0, 0)) });
      this._items.Add(new Item { Name = "three", DateTime = DateTime.Today.Subtract(new TimeSpan(1, 0, 0, 0)) });
      this._items.Add(new Item { Name = "four", DateTime = DateTime.Today.Add(new TimeSpan(1, 0, 0, 0)) });
      this._items.Add(new Item { Name = "five", DateTime = DateTime.Today.Add(new TimeSpan(1, 0, 0, 0)) });
      this.DataContext = this;
    }

    private ObservableCollection<Item> _items = new ObservableCollection<Item>();

    public ObservableCollection<Item> Items => _items;

  }


  public abstract class ViewModelBase : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
      this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
  }

  public class Item : ViewModelBase {
    private string _name;
    private DateTime _dateTime;

    public string Name {
      get {
        return this._name;
      }
      set {
        if (value == this._name)
          return;
        this._name = value;
        this.OnPropertyChanged();
      }
    }

    public DateTime DateTime {
      get {
        return this._dateTime;
      }
      set {
        if (value.Equals(this._dateTime))
          return;
        this._dateTime = value;
        this.OnPropertyChanged();
      }
    }

  }

使用资源分组

 <Window.Resources>
        <CollectionViewSource x:Key="CollectionViewSource" Source="{Binding Items}">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="DateTime" />
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </Window.Resources>

<强>列表框

<ListBox ItemsSource="{Binding Source={StaticResource CollectionViewSource}}" Width="400" Height="200">
            <ListBox.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <GridViewColumnHeader Content="{Binding Name}"/>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                    <GroupStyle.Panel >
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel Orientation="Horizontal"/>
                        </ItemsPanelTemplate>
                    </GroupStyle.Panel>
                </GroupStyle>
            </ListBox.GroupStyle>
            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
                    <Setter Property="VerticalContentAlignment" Value="Stretch"></Setter>
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="DarkGray" BorderThickness="0,0,1,0" Margin="-6,-2,-6,-2">
                        <StackPanel Margin="6,2,6,2">
                            <TextBlock Text="{Binding Name}"/>
                        </StackPanel>
                    </Border>

                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

此解决方法的基础是使用GridViewColumnHeader作为GroupStyle的HeaderTemplate。

可能更好的解决方案可能是将ListBox更改为ListView并将ListView的View - 属性设置为GridView。这需要改变您的数据结构。

注意

ListBox的分组从未打算执行您尝试执行的任务。列表框和分组的默认方式是在ListBox的内容区域中使用扩展器,如here所述