欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-12-15 08:10:54
介绍 我有一种情况,我希望能够将项目添加到列表中,并在列表中移动项目,这似乎是使用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执行动作,在这种情况下是将所选项目向上移动一个位置。对于这个动作的代码需要有机会获得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开发为按钮提供添加,删除和重新排列ListBox内容的功能

问题

行为存在一些限制,其中一些可以使用其他代码进行处理。
其中一个问题是行为预期绑定到该类型selector的类型的ilist,这意味着这两个listobservablecollection可使用,但array type不能。这可以编码,但需要array每次重新创建

另一个限制是add只有type在它ilist是一个类时才有效,并且有一个默认的构造函数。

当然另一个限制是它只处理从控件派生的selector控件。

结论

这是一个非常好的小行为,因为它允许更改列表的顺序,并通过仅将行为添加button到实现该功能的每个项目来添加或删除项目viewmodel中无需任何操作即可提供此功能。