介紹 我有一種情況,我希望能夠將項目添加到列表中,併在列表中移動項目,這似乎是使用a的最簡單方法ListBox。我立刻想到瞭如何以通用的方式做到這一點,然後,也許,可以使用行為來做到這一點。這似乎是一個非常有用的想法。我決定以一種簡單的方式為我正在開發的應用程式做這件事,但我想我會創建一個演示項目來 ...
介紹
我有一種情況,我希望能夠將項目添加到列表中,併在列表中移動項目,這似乎是使用a的最簡單方法ListBox
。我立刻想到瞭如何以通用的方式做到這一點,然後,也許,可以使用行為來做到這一點。這似乎是一個非常有用的想法。我決定以一種簡單的方式為我正在開發的應用程式做這件事,但我想我會創建一個演示項目來探索這個想法。這是結果。
概觀
該行為實際上有四個獨立的部分,可以在一個類中執行不同的功能:
- 添加項目
- 將所選項目向上移動一個位置
- 將所選項目向下移動一個位置
- 刪除所選項目。
每個函數的代碼結構非常相似,只有一些細節不同。
將要檢查的代碼是Move Up函數的代碼。
首先是以下定義DependencyProperty
:
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
執行動作,在這種情況下是將所選項目向上移動一個位置。對於這個動作的代碼需要有機會獲得ItemsSource
和SelectedIndex
的Selector
控制,首先要真正能夠做到移動,第二知道要移動的項目。
對於所有操作,此代碼幾乎相同,只是Add Item不需要監視SelectionChanged
事件Selector
,並且Button
永遠不會禁用。
當此DependencyProperty
更改時,將OnMoveUpItemChanged
執行事件處理程式。此事件處理程式在DependencyProperty
RegisterAttached方法的FrameworkMetadata參數中指定。
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);
}
}
此代碼將事件處理程式附加到Button
Click事件和Selector
SelectionChanged
事件。為了確保Button
在訂閱事件之前沒有雙重訂閱Click事件,並且刪除SelectionChanged
舊事件的事件處理程式Selector
(如果存在)。此外,Button
它保存在附件DependencyProperty
中,Selector
以便可以找到它以供SelectionChanged
事件處理程式使用。最後,Button
通過使用SelectionChanged
事件處理程式調整IsEnabled值。
為的保存代碼Button
在Selector
被下麵的私人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
DependencyProperty
的SelectedItem
值和值Selector
。IList
然後複製所選項目,轉換為正確的類型(使用Type類的Reflection GetGenericArgument方法獲取類型,然後使用Convert.ChangeType方法將其強制轉換),然後從IList
(RemoveAt方法)中刪除IList
)。然後使用該Selector
Insert
方法插入刪除的項目。
接下來檢查是否現在是第一個項目,禁用Button
它是否為,並且Selector
SelectedIndex
設置為仍然指向同一個項目。
該移碼幾乎是相同的,則刪除要簡單得多,因為它沒有保存已刪除的項目,然後將其放回IList
。
最後,有適當的代碼啟用或禁用Button
取決於是否存在SelectedItem
,SelectedItem
是第一個(用於上移)或最後一個項目IList
(用於下移)。這是SelectedItem
在Selector
觸發事件時調用的事件處理程式:
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
綁定到ItemsSource
的SelectedIndex
,並需要得到Button
保存為一個附加屬性在此功能Selector
。對於Remove函數,只需要知道if SelectedIndex
是否等於-1,這樣簡單得多。
使用行為
要使用此行為,只需要一個從Selector
控制項派生的列表控制項,Name
為此控制項關聯一個值,並Button
為每個應該實現的函數定義一個網站源碼。在每一個Button
XAML只包括ListHelperBahavior
與DependencyProperty
它有關聯Binding
的Selector
:
<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="