需求

最近在做的一个小工具中用到了ListView来显示一些数据。但是ListView默认的样式不太符合个人的审美,于是想修改ListView子项的各种效果。

尝试过程

阶段1 自己摸索

按照以往对于控件样式修改的流程来说,应该是选择这个控件,然后创建它的模板,通过修改模板来达到效果。
例如ListBox中选择项的修改方式就是:
image.png

可是ListView的结构并不是这样的,虽然在XAML代码中设置了ListView.View属性,但是ListView内部并没有一个ListViewItem可以让我们来编辑模板。
image.png

阶段2 查找别人的解决方案

既然按照自己以往的处理方式并不能解决问题,那么就只好去搜索一下如何修改了。
在国内外的搜索引擎上都尝试过搜索了,能看到最常用的处理方式是:

  1. <ListView x:Name="listView2">
  2. <ListView.Resources>
  3. <Style TargetType="{x:Type ListViewItem}">
  4. <Style.Triggers>
  5. <Trigger Property="IsSelected" Value="true">
  6. <Setter Property="Background" Value="Orange" />
  7. <Setter Property="Foreground" Value="White" />
  8. <Setter Property="BorderBrush" Value="Blue" />
  9. <Setter Property="BorderThickness" Value="10"/>
  10. </Trigger>
  11. <Trigger Property="IsMouseOver" Value="True">
  12. <Setter Property="Background" Value="Pink" />
  13. <Setter Property="Foreground" Value="Black" />
  14. <Setter Property="BorderBrush" Value="Purple" />
  15. <Setter Property="BorderThickness" Value="5"/>
  16. </Trigger>
  17. </Style.Triggers>
  18. </Style>
  19. </ListView.Resources>
  20. <ListView.View>
  21. <GridView>
  22. <GridViewColumn Header="ColumnA" DisplayMemberBinding="{Binding Path=A}"/>
  23. <GridViewColumn Header="ColumnB" DisplayMemberBinding="{Binding Path=B}"/>
  24. <GridViewColumn Header="ColumnC" DisplayMemberBinding="{Binding Path=C}"/>
  25. <GridViewColumn Header="ColumnD" DisplayMemberBinding="{Binding Path=D}"/>
  26. </GridView>
  27. </ListView.View>
  28. </ListView>

(上述的Style也可以设置给ListView.ItemContainerStyle属性)

这样做虽然起效了,可是只能修改一部分内容的样式,其他部分(例如中间有一层渐变色)却无从修改:
image.png
因此这个方法并不能达到我的要求。

阶段3 再次摸索(解决问题)

在继续尝试对控件进行创建模板的时候,我突然发现一个选项:
image.png
点击后,会在ListView中添加一个ListViewItem,然后对着这个ListViewItem右键就可以创建模板了!
image.png
那这样不就可以修改模板到自己想要的样式,然后设置给ListView.ItemContainerStyle属性了吗?

  1. <ListView x:Name="listView3" ItemContainerStyle="{DynamicResource ListViewItemStyle1}">
  2. <ListView.View>
  3. <GridView>
  4. <GridViewColumn Header="ColumnA" DisplayMemberBinding="{Binding Path=A}"/>
  5. <GridViewColumn Header="ColumnB" DisplayMemberBinding="{Binding Path=B}"/>
  6. <GridViewColumn Header="ColumnC" DisplayMemberBinding="{Binding Path=C}"/>
  7. <GridViewColumn Header="ColumnD" DisplayMemberBinding="{Binding Path=D}"/>
  8. </GridView>
  9. </ListView.View>
  10. </ListView>

然而事情并没有那么顺利,最终程序显示的效果出现了问题:
image.png

每行的样式确实是变了,但每行显示的内容却出现了问题,与我们想要的表格是不一样的,只显示了一个内容。
这又是为什么呢?

于是只好再去搜索引擎上查找,看有没有能解决的方案。最终看到了这样一个帖子:

这样就明白了!ListViewItem内部应该使用GridViewRowPresenter组件,而并非是创建副本时给的ContentPresenter
只要在模板中把控件改变一下就好了!
原本是:

  1. <ControlTemplate TargetType="{x:Type ListViewItem}">
  2. <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
  3. <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
  4. </Border>
  5. </ControlTemplate>

修改为:

  1. <ControlTemplate TargetType="{x:Type ListViewItem}">
  2. <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
  3. <GridViewRowPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
  4. </Border>
  5. </ControlTemplate>

再次运行程序:
image.png
收工!