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中無需任何操做便可提供此功能。

相關文章
相關標籤/搜索