【WPF】自定义一个自删除的多功能ListBox

原文地址 https://www.cnblogs.com/younShieh/p/17008534.html

❤如果本文对你有所帮助,不妨点个关注和推荐呀,这是对笔者最大的支持~❤

我需要一个ListBox,他在界面上分为几列,每列对应一系列的数据。第一行是各数据的标题,支持横向滚动,竖向只支持数据源滚动,标题不随之滚动。视觉上与ListView类似。支持等比拉伸,支持多选,支持从界面去更改内部数据源,支持子项从ListBox中删除自己。为了实现这些功能,我决定自定义一个特殊的列表,当然他还是继承自ListBox。

  1. 首先他支持等比拉伸,且数据分列显示。首先想到Grid的ColumnDefinitions可以满足。
<Grid.ColumnDefinitions>     <ColumnDefinition Width="74*" />     <ColumnDefinition Width="179*" />     <ColumnDefinition Width="157*" /> </Grid.ColumnDefinitions> 
  1. 支持从界面去更改内部数据源,支持子项从ListBox中删除自己。
    为了从界面上满足功能,需要重写ItemContainerStyle样式,绘制出该子项Style。在Style中为了处理事件响应,可以通过在数据源子项中增加Command来对对应事件进行处理。但是处理逻辑可能有点繁杂,而且单从数据处理而言,子项无法从父项中删除自己,只能通过视觉树获取父ListBox,实现该功能。这样写的话代码耦合性会有点高,且数据处理时会调取界面处理。我希望数据源内部只是在处理数据,只能通过界面自上而下的访问数据源,而不是数据源和界面都有循环调用。
    第二种方法,我直接重写一个控件继承自ListBoxItem,将之前重写ItemContainerStyle样式复制到该控件前台,并在后台代码中对相应事件进行处理。代码如下:
public partial class TestItem : ListBoxItem {     public TestItem()     {         InitializeComponent();     }      private void Delete_Click(object sender, RoutedEventArgs e)     {     } } 

因为我是继承自ListBoxItem的,所以可以通过

ItemsControl.ItemsControlFromItemContainer(this) is ListBox listBox 

获取到父listbox的对象,获取到父对象后,就可以从ListBox中删除自己。或是更改ListBox中绑定的数据源。

  1. 我们还需要把这个自定义的ListBoxItem放到我们自定义的ListBox中,让所有子项都应用这个自定义的ListboxItem,而不是默认的ListboxItem。代码如下:
internal class TestListBox : ListBox {     protected override DependencyObject GetContainerForItemOverride()     {         return new TestItem();     } } 
  1. 为了实现数据与标题分离的滚动效果,我单独将标题拿到外部,对标题进行单独显示,Listbox只显示数据。外部滑动条支持整体横向滑动,Listbox内部滑动条支持内部竖向滑动。给两个滑动条都加上最小宽度。
<ScrollViewer             Grid.Row="1"             Margin="0,20,0,0"             HorizontalScrollBarVisibility="Auto"             VerticalScrollBarVisibility="Disabled">             <Border                 MinWidth="{Binding MinWidth, ElementName=listbox}"                 BorderBrush="#DFDFDF"                 BorderThickness="1">                 <Grid>                     <Grid.RowDefinitions>                         <RowDefinition Height="52" />                         <RowDefinition />                     </Grid.RowDefinitions>                     <Grid.ColumnDefinitions>                         <ColumnDefinition Width="79*" />                         <ColumnDefinition Width="104*" />                         <ColumnDefinition Width="80*" />                     </Grid.ColumnDefinitions>                     <Border Grid.ColumnSpan="20" Background="#F2F2F2" />                     <TextBlock Text="ID" />                     <TextBlock Grid.Column="1" Text="编号" />                     <TextBlock Grid.Column="2" Text="操作" />                     <controls:TestListBox                         x:Name="listbox"                         Grid.Row="1"                         Grid.ColumnSpan="3"                         MinWidth="1100"                         ItemsSource="{Binding ItemsSourceData}"                         Style="{StaticResource BaseListBoxStyle.WithOutHorizontalScrollViewer}" />                 </Grid>             </Border>         </ScrollViewer> 

在Listbox的样式中取消了横向滑动条的显示。

 <Style x:Key="BaseListBoxStyle.WithOutScrollViewer" TargetType="ListBox">         <Setter Property="BorderThickness" Value="0" />         <Setter Property="Background" Value="Transparent" />         <Setter Property="FocusVisualStyle" Value="{x:Null}" />         <Setter Property="ScrollViewer.CanContentScroll" Value="False" />         <Setter Property="ScrollViewer.PanningMode" Value="Both" />         <Setter Property="Stylus.IsFlicksEnabled" Value="False" />         <Setter Property="VerticalContentAlignment" Value="Center" />         <Setter Property="Template">             <Setter.Value>                 <ControlTemplate TargetType="ListBox">                     <Border                         x:Name="Bd"                         Background="{TemplateBinding Background}"                         BorderBrush="{TemplateBinding BorderBrush}"                         BorderThickness="{TemplateBinding BorderThickness}"                         SnapsToDevicePixels="true">                         <ScrollViewer                             Focusable="false"                             HorizontalScrollBarVisibility="Disabled"                             VerticalScrollBarVisibility="Auto">                             <ItemsPresenter Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />                         </ScrollViewer>                     </Border>                 </ControlTemplate>             </Setter.Value>         </Setter>     </Style> 

发表评论

相关文章