• WPF开发为按钮提供添加,删除和重新排列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执行动作,在这种情况下是将所选项目向上移动一个位置。对于这个动作的代码需要有机会获得ItemsSourceSelectedIndexSelector控制,首先要真正能够做到移动,第二知道要移动的项目。

    对于所有操作,此代码几乎相同,只是Add Item不需要监视SelectionChanged事件Selector,并且Button永远不会禁用。

    当此DependencyProperty更改时,将OnMoveUpItemChanged执行事件处理程序此事件处理程序在DependencyPropertyRegisterAttached方法的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);
        }
    }
    

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

    为的保存代码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中无需任何操作即可提供此功能。

  • 相关阅读:
    SpringMVC源码阅读(一)
    Struts2技术内幕-----第七章
    1118 Lining Up
    1146 ID Codes
    1056 IMMEDIATE DECODABILITY
    1028 Web Navigation
    1045 Bode Plot
    1083 Moving Tables
    并查集路径压缩
    线段树
  • 原文地址:https://www.cnblogs.com/langda/p/10473467.html
Copyright © 2020-2023  润新知