• WPF Group分组对ListBox等列表样式的约束


      在做WPF主题支持时,出现一个分组引起的莫名错误,可是折腾了我一番。在没有使用样式时,列表分组很正常,使用了别人写的ListBox列表样式后,发现GroupItem分组区没有内容,是空的,本篇把这一问题的解决过程给大家说一下,做主题时可以注意分组对列表样式的限制了。

    ListBox增加分组

      WPF为ItemsControl提供很多的样式扩展,要想实现列表分组也很简单,只需要做以下几步就可以了:

    1. 给列表控件增加分组样式
      代码
      <Style x:Key="GroupContainerStyle" TargetType="{x:Type GroupItem}">
      <Setter Property="Template">
      <Setter.Value>
      <ControlTemplate TargetType="{x:Type GroupItem}">
      <Expander IsExpanded="True">
      <Expander.Header>
      <Grid>
      <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto"/>
      <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
      <RowDefinition/>
      </Grid.RowDefinitions>
      <StackPanel Orientation="Horizontal" Margin="0,0,10,0">
      <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" />
      <TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount, StringFormat=(共{0}条)}"/>
      </StackPanel>
      <Line Grid.Column="1" SnapsToDevicePixels="true" X1="0" X2="1" Stretch="Fill" StrokeThickness="1"/>
      </Grid>
      </Expander.Header>
      <ItemsPresenter />
      </Expander>
      </ControlTemplate>
      </Setter.Value>
      </Setter>
      </Style>

      GroupStyle gs = new GroupStyle();
      gs.ContainerStyle
      = Application.Current.TryFindResource("GroupContainerStyle") as Style;
      lbModule.GroupStyle.Add(gs);
    2. 给数据增加分组

      代码
      <UserControl.Resources>
      <CollectionViewSource Source="{x:Static oea:ApplicationModel.DefaultBusinessObjectInfos}" x:Key="cvs">
      <CollectionViewSource.GroupDescriptions>
      <PropertyGroupDescription PropertyName="Catalog" />
      </CollectionViewSource.GroupDescriptions>
      </CollectionViewSource>
      </UserControl.Resources>

    使用ListBox样式后

      用了别人的一个ListBox样式文件,样式如下:

    代码
    <Style TargetType="{x:Type ListBox}">
    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
    <Setter Property="BorderBrush">
    <Setter.Value>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="{DynamicResource PrimaryColor}" Offset="0" />
    <GradientStop Color="{DynamicResource SecondaryColor}" Offset="1" />
    </LinearGradientBrush>
    </Setter.Value>
    </Setter>
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
    <Setter Property="ScrollViewer.CanContentScroll" Value="true" />
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="Template">
    <Setter.Value>
    <ControlTemplate TargetType="{x:Type ListBox}">
    <Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="1" CornerRadius="4,4,4,4">
    <Grid>
    <ScrollViewer Padding="{TemplateBinding Padding}" Focusable="false" x:Name="scrollViewer">
    <StackPanel Margin="2" IsItemsHost="true"/>

    <!--<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />-->
    </ScrollViewer>
    <Border CornerRadius="4,4,4,4" Visibility="Collapsed" x:Name="border" Margin="-2,-2,-2,-2">
    <Border.Background>
    <SolidColorBrush Color="{DynamicResource DisabledColor}"/>
    </Border.Background>
    </Border>
    </Grid>
    </Border>
    <ControlTemplate.Triggers>
    <Trigger Property="IsEnabled" Value="false">
    <Setter Property="Visibility" TargetName="border" Value="Visible"/>
    </Trigger>
    <Trigger Property="IsGrouping" Value="true">
    <Setter Property="ScrollViewer.CanContentScroll" Value="false" />
    </Trigger>
    </ControlTemplate.Triggers>
    </ControlTemplate>
    </Setter.Value>
    </Setter>
    </Style>

    用完之后运行发现界面不对,点击分组标题后列表内容没有显示???

      

    查找原因

      自己想了一下,原因不明,无奈自己对WPF实现只了解一点,于是网上搜索ItemsPresenter empty,找到第一条网页ItemsPresenter + ItemsPanelTemplate vs Panel marked with IsItemsHost,进去后发现他提出了一个问题,就是在分组时如何取ItemsPresenter,发现Reflector工具可以看到以下代码:

    代码
    internal static ItemsPresenter FromGroupItem(GroupItem groupItem)
    {
    if (groupItem == null)
    {
    return null;
    }
    Visual parent
    = VisualTreeHelper.GetParent(groupItem) as Visual;
    if (parent == null)
    {
    return null;
    }
    return (VisualTreeHelper.GetParent(parent) as ItemsPresenter);
    }

     

    这个帖子上面也解释了为什么这么设计,我就不再重复了,原来在分组时对控件样式有要求,那就是控件样式必须存在ItemsPresenter。

    确认原因

    使用《WPF - Visual调试工具Snoop》工具查看一下,发现GroupItem下的ItemsPresenter是空的

    切换回不使用样式再看看,发现在GroupItem之上有一个ItemsPresenter,而应用上面样式之后就没有了,果然就是样式文件的控件模板缺少ItemsPresenter的原因。

    解决问题

    原因知道了,解决问题也就非常简单了,修改样式表,主要就是把

    <StackPanel Margin="2" IsItemsHost="true"/>

    该为

    <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"

    修改后再次运行,界面正确,如下:

     

    更多内容: 开源信息系统开发平台之OpenExpressApp框架.pdf

     

    欢迎转载,转载请注明:转载自周金根 [ http://zhoujg.cnblogs.com/ ]

  • 相关阅读:
    用C#编写获取远程IP,MAC的方法
    创建 TransactSQL 作业步骤
    S3C2440系统时钟
    C# 跟年月日判断星期几
    嵌入式系统启动例程
    使用HTML5和CSS3来创建幻灯片
    巧解Android时区加载过慢的问题
    HTML5之美
    C#如何取硬件标志
    S3C2440看门狗定时器(Watchdog)
  • 原文地址:https://www.cnblogs.com/zhoujg/p/1616713.html
Copyright © 2020-2023  润新知