WPF开发为按钮提供添加,删除和从新排列ListBox内容的功能

介绍

我有一种状况,我但愿可以将项目添加到列表中,并在列表中移动项目,这彷佛是使用a的最简单方法ListBox我马上想到了如何以通用的方式作到这一点,而后,也许,可使用行为来作到这一点。这彷佛是一个很是有用的想法。我决定以一种简单的方式为我正在开发的应用程序作这件事,但我想我会建立一个演示项目来探索这个想法。这是结果。git

概观

该行为实际上有四个独立的部分,能够在一个类中执行不一样的功能:ide

  • 添加项目
  • 将所选项目向上移动一个位置
  • 将所选项目向下移动一个位置
  • 删除所选项目。

每一个函数的代码结构很是类似,只有一些细节不一样。函数

将要检查的代码是Move Up函数的代码网站

首先是如下定义DependencyPropertyui

public static readonly DependencyProperty MoveItemUpProperty = DependencyProperty.RegisterAttached("MoveItemUp", typeof(Selector), typeof(ListHelperBehavior), new PropertyMetadata(null, OnMoveItemUpChanged)); public static Selector GetMoveItemUp(UIElement uiElement) { return (Selector)uiElement.GetValue(MoveItemUpProperty); } public static void SetMoveItemUp(UIElement uiElement, Selector value) { uiElement.SetValue(MoveItemUpProperty, value); } 

这用于为包含列表Selector(或ListBox)控件提供绑定它用于Button执行动做,在这种状况下是将所选项目向上移动一个位置。对于这个动做的代码须要有机会得到ItemsSourceSelectedIndexSelector控制,首先要真正可以作到移动,第二知道要移动的项目。编码

对于全部操做,此代码几乎相同,只是Add Item不须要监视SelectionChanged事件Selector,而且Button永远不会禁用。spa

当此DependencyProperty更改时,将OnMoveUpItemChanged执行事件处理程序此事件处理程序在DependencyPropertyRegisterAttached方法的FrameworkMetadata参数中指定code

private static void OnMoveItemUpChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (e.OldValue is Selector Selector1) { Selector1.SelectionChanged -= SetMoveItemUpButtonIsEnabled; } if (e.NewValue is Selector Selector) { var Button = CheckForButtonBase(d); Button.Click -= MoveItemUpEvent; Button.Click += MoveItemUpEvent; Selector.SetValue(MoveUpButton, Button); Selector.SelectionChanged += SetMoveItemUpButtonIsEnabled; SetMoveItemUpButtonIsEnabled(Selector, null); } } 

此代码将事件处理程序附加到ButtonClick事件和Selector SelectionChanged事件。为了确保Button在订阅事件以前没有双重订阅Click事件,而且删除SelectionChanged事件的事件处理程序Selector(若是存在)。此外,Button它保存在附件DependencyProperty中,Selector以即可以找到它以供SelectionChanged事件处理程序使用最后,Button经过使用SelectionChanged事件处理程序调整IsEnabled值blog

为的保存代码ButtonSelector被下面的私人DependencyProperty从而使Button被启用和禁用,能够发现:事件

private static readonly DependencyProperty MoveUpButton = DependencyProperty.RegisterAttached("MoveUpButton", typeof(ButtonBase), typeof(ListHelperBehavior), new PropertyMetadata(null)); 

Add Item代码不须要监视SelectionChanged事件,由于Button从不由用它。
的Click事件Button下移功能以下:

private static void MoveItemUpEvent(object sender, RoutedEventArgs e) { Debug.Assert(sender is ButtonBase); var Button = (ButtonBase)sender; var Selector = GetMoveItemUp(Button); var IList = CheckForIList(Selector); var itemNumber = Selector.SelectedIndex; var item = IList[itemNumber]; IList.RemoveAt(itemNumber); var type = IList.GetType().GetGenericArguments().Single(); var castInstance = Convert.ChangeType(item, type); IList.Insert(itemNumber - 1, castInstance); if (itemNumber == 1) Button.IsEnabled = false; Selector.SelectedIndex = itemNumber - 1; } 

sender参数必须强制转换为ButtonBase类型,而后用于获取Selector做为ButtonBase中附加属性保存控件的值而后使用它来获取IList绑定到Selector ItemsSource DependencyPropertySelectedItemSelectorIList而后复制所选项目,转换为正确的类型(使用Type类的Reflection GetGenericArgument方法获取类型,而后使用Convert.ChangeType方法将其强制转换),而后从IList(RemoveAt方法)中删除IList)。而后使用该Selector Insert方法插入删除的项目

接下来检查是否如今是第一个项目,禁用Button它是否为,而且Selector SelectedIndex设置为仍然指向同一个项目。

码几乎是相同的,则删除要简单得多,由于它没有保存已删除的项目,而后将其放回IList

最后,有适当的代码启用或禁用Button取决因而否存在SelectedItemSelectedItem是第一个(用于上)或最后一个项目IList(用于下移)。这是SelectedItemSelector触发事件时调用的事件处理程序

private static void SetMoveItemUpButtonIsEnabled(object sender, RoutedEventArgs e) { <code> Debug.Assert(sender is Selector); var Selector = (Selector)sender; var IList = CheckForIList(Selector); var itemNumber = Selector.SelectedIndex; var Button = (ButtonBase) Selector.GetValue(MoveUpButton); Button.IsEnabled = (itemNumber >= 1 && itemNumber < IList.Count); }</code> 

对于这种须要IList绑定到ItemsSourceSelectedIndex,并须要获得Button保存为一个附加属性在此功能Selector对于Remove函数,只须要知道if SelectedIndex是否等于-1,这样简单得多。

使用行为

要使用此行为,只须要一个从Selector控件派生的列表控件,Name为此控件关联一个值,并Button为每一个应该实现的函数定义一个网站源码。在每个Button XAML只包括ListHelperBahaviorDependencyProperty它有关联BindingSelector

<Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <ListBox Name="TheList"              ItemsSource="{Binding List}"              HorizontalAlignment="Stretch"              VerticalAlignment="Stretch"  > <ListBox.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="30"/> <ColumnDefinition Width="200"/> </Grid.ColumnDefinitions> <TextBlock Text="{Binding ItemNumber}"/> <TextBlock Grid.Column="1"                                Text="{Binding TimeCreated}"/> </Grid> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <StackPanel Grid.Row="2"                 Margin="-5 5"                 Orientation="Horizontal"                 HorizontalAlignment="Right"> <Button Content="Add"                 Width="70"                 Margin="5"                 local:ListHelperBehavior.AddToList="{Binding ElementName=TheList}"/> <Button Content="Remove"                 Width="70"                 Margin="5"                 local:ListHelperBehavior.RemoveFromList="{Binding ElementName=TheList}"/> <Button Content="Move Up"                 Width="70"                 Margin="5"                 local:ListHelperBehavior.MoveItemUp="{Binding ElementName=TheList}"/> <Button Content="Move Down"                 Width="70"                 Margin="5"          local:ListHelperBehavior.MoveItemDown="{Binding ElementName=TheList}"/> </StackPanel> 

WPF行为的图像2为按钮提供了添加,删除和从新排列ListBox内容的功能

问题

行为存在一些限制,其中一些可使用其余代码进行处理。
其中一个问题是行为预期绑定到该类型Selector的类型的IList,这意味着这两个ListObservableCollection可以使用,但Array Type不能。这能够编码,但须要Array每次从新建立

另外一个限制是Add只有Type在它IList是一个类时才有效,而且有一个默认的构造函数。

固然另外一个限制是它只处理从控件派生的Selector控件。

结论

这是一个很是好的小行为,由于它容许更改列表的顺序,并经过仅将行为添加Button到实现该功能的每一个项目来添加或删除项目ViewModel中无需任何操做便可提供此功能。

相关文章
相关标签/搜索