2009-09-19 3 views
19

Я хочу, чтобы создать вложенное свойство, которое может использоваться с этим синтаксисом:Attached свойства списка типа

<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?

ответ

33

Помните, что XAML - это просто сокращенная форма создания объекта. Поэтому для создания коллекции/списка в качестве значения для прикрепленного свойства DisplayFilter вам придется заключить те внутри другого тега коллекции. Если вы не хотите этого делать, что вполне понятно, вы должны инициализировать коллекцию при первом доступе к ресурсу.

Есть только одна проблема с этим: метод getter пропускается считывателем XAML в качестве оптимизации. Вы можете предотвратить это поведение, выбрав другое имя для имени аргумента RegisterAttached вызова:

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

Тогда геттер свойства будет называться, и вы можете проверить null. Вы можете узнать больше об этом в this blog post.

Редактировать: Похоже, что связанное сообщение в блоге не так понятно. Вы можете изменить только имя строки, переданной RegisterAttached, а не имя статических методов Get/Set:

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 метода:

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<T> не работает, поскольку анализатор XAML не может вызвать общий метод Add(T). Collection<T> и List<T> также реализуют не общий интерфейс IList и могут быть использованы в этом случае. Я хотел бы предложить, чтобы создать новый тип коллекции в случае, если вы хотите сделать некоторые изменения в коллекции в будущем:

public class TabItemCollection : Collection<TabItem> 
{ 
} 

Если вы не заботитесь о создании коллекции явно, как это:

<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); 
    //} 
} 
+0

осветленный мой ответ, HTH! – gix

+0

Тогда должно быть что-то еще не так, потому что код отправлен хорошо. См. Http://nopaste.org/p/adqfm5EPi для краткого и полного примера. – gix

+0

Кажется, вы не можете использовать ресурсы таким образом. Если вы либо не используете ресурсы, либо явные коллекции, похоже, работают. – gix

Смежные вопросы