WPF实现自定义一个自删除的多功能ListBox
从南到北ss 人气:0我需要一个ListBox,他在界面上分为几列,每列对应一系列的数据。第一行是各数据的标题,支持横向滚动,竖向只支持数据源滚动,标题不随之滚动。视觉上与ListView类似。支持等比拉伸,支持多选,支持从界面去更改内部数据源,支持子项从ListBox中删除自己。为了实现这些功能,我决定自定义一个特殊的列表,当然他还是继承自ListBox。
1.首先他支持等比拉伸,且数据分列显示。首先想到Grid的ColumnDefinitions可以满足。
<Grid.ColumnDefinitions> <ColumnDefinition Width="74*" /> <ColumnDefinition Width="179*" /> <ColumnDefinition Width="157*" /> </Grid.ColumnDefinitions>
2.支持从界面去更改内部数据源,支持子项从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中绑定的数据源。
3.我们还需要把这个自定义的ListBoxItem放到我们自定义的ListBox中,让所有子项都应用这个自定义的ListboxItem,而不是默认的ListboxItem。代码如下:
internal class TestListBox : ListBox { protected override DependencyObject GetContainerForItemOverride() { return new TestItem(); } }
4.为了实现数据与标题分离的滚动效果,我单独将标题拿到外部,对标题进行单独显示,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>
加载全部内容