类型列表的附加属性 [英] Attached property of type list

查看:27
本文介绍了类型列表的附加属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个可以与此语法一起使用的附加属性:

I want to create an attached property that can be used with this syntax:

<Button>
  <Image .../>
  <ui:ToolbarItem.DisplayFilter>
    <TabItem .../>
    <TabItem .../>
    <TabItem .../>
  </ui:ToolbarItem.DisplayFilter>
</Button> 

这是我的尝试:

public class ToolbarItem
{
  /// <summary>
  /// Identifies the DisplayFilter attached property. 
  /// </summary>
  public static readonly DependencyProperty DisplayFilterProperty =
    DependencyProperty.RegisterAttached(
     "DisplayFilter",
     typeof( IList ),
     typeof( ToolbarItem )
    );

  public static IList GetDisplayFilter( Control item ) {
    return (IList)item.GetValue( DisplayFilterProperty );
  }

  public static void SetDisplayFilter( Control item, IList value ) {
    item.SetValue( DisplayFilterProperty, value );
  }
}

然而,这会在解析时导致异常 -- System.ArgumentException: TabItem 不是属性DisplayFilter"的有效值.那么如何配置我的附加属性以便我可以使用所需的 XAML 语法?

This, however, is causing an exception at parse-time -- System.ArgumentException: TabItem is not a valid value for property 'DisplayFilter'. So how do I configure my attached property so that I can use the desired XAML syntax?

推荐答案

请记住,XAML 基本上只是对象创建的一种简写形式.因此,要创建一个集合/列表作为附加的 DisplayFilter 属性的值,您必须将这些 TabItems 包含在另一个集合标记中.如果你不想这样做,这是可以理解的,你必须在第一次访问属性时初始化集合.

Remember that XAML is basically just a shorthand form of object creation. So to create a collection/list as the value for the attached DisplayFilter property you would have to enclose those TabItems inside another collection tag. If you don't want to do that, which is understandable, you have to initialize the collection the first time the property is accessed.

这只有一个问题:作为优化,XAML 阅读器跳过了 getter 方法.您可以通过为 RegisterAttached 调用的 name 参数选择不同的名称来防止这种行为:

There is just one problem with this: The getter method is skipped by the XAML reader as an optimization. You can prevent this behavior by choosing a different name for the name argument to the RegisterAttached call:

DependencyProperty.RegisterAttached("DisplayFilterInternal", ...)

然后属性 getter 将被调用,您可以检查 null.您可以在 这篇博文.

Then the property getter will be called and you can check for null. You can read more about that in this blog post.

似乎链接的博客文章不是那么清楚.您更改传递给RegisterAttached 的字符串的名称,而不是静态获取/设置方法的名称:

Seems like the linked blog post isn't that clear. You change only the name of the string passed to RegisterAttached, not the name of the static get/set methods:

public static readonly DependencyProperty DisplayFilterProperty =
    DependencyProperty.RegisterAttached(
        "DisplayFilterInternal",
        typeof(IList),
        typeof(ToolbarItem));

public static TabItemCollection GetDisplayFilter(Control item)
{ ... }

public static void SetDisplayFilter(Control item, IList value)
{ ... }

您必须在 GetDisplayFilter 方法中初始化集合:

You have to initialize the collection in the GetDisplayFilter method:

public static TabItemCollection GetDisplayFilter(Control item)
{
    var collection = (IList)item.GetValue(DisplayFilterProperty);
    if (collection == null) {
        collection = new List<object>();
        item.SetValue(DisplayFilterProperty, collection);
    }
    return collection;
}

您似乎只向该集合添加了 TabItem 元素.然后,您可以使集合类型安全,但使用 IList 不起作用,因为 XAML 解析器无法调用通用方法 Add(T).CollectionList 也实现了非通用的 IList 接口,可以在这种情况下使用.我建议创建一个新的集合类型,以防您将来想对集合进行一些更改:

It seems that you only add TabItem elements to that collection. Then you can make the collection type-safe, but using IList<T> does not work since the XAML parser cannot invoke the generic method Add(T). Collection<T> and List<T> also implement the non-generic IList interface and can be used in this case. I would suggest to create a new collection type in case you want to do some changes to the collection in the future:

public class TabItemCollection : Collection<TabItem>
{
}

如果您不关心像这样显式设置集合:

If you don't care about setting the collection explicitly like this:

<ui:ToolbarItem.DisplayFilter>
    <ui:TabItemCollection>
        <TabItem/>
    </ui:TabItemCollection>
</ui:ToolbarItem.DisplayFilter>

您可以删除 SetDisplayFilter 方法.

总结:

public class TabItemCollection : Collection<TabItem>
{
}

public class ToolbarItem
{
    public static readonly DependencyProperty DisplayFilterProperty =
        DependencyProperty.RegisterAttached(
            "DisplayFilterInternal", // Shadow the name so the parser does not skip GetDisplayFilter
            typeof(TabItemCollection),
            typeof(ToolbarItem));

    public static TabItemCollection GetDisplayFilter(Control item)
    {
        var collection = (TabItemCollection)item.GetValue(DisplayFilterProperty);
        if (collection == null) {
            collection = new TabItemCollection();
            item.SetValue(DisplayFilterProperty, collection);
        }
        return collection;
    }

    // Optional, see above note
    //public static void SetDisplayFilter(Control item, TabItemCollection value)
    //{
    //    item.SetValue(DisplayFilterProperty, value);
    //}
}

这篇关于类型列表的附加属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆