2009-09-19 12 views
19

Chcę utworzyć załączony właściwość, że może być używany z tej składni:Dołączone własnością liście Typ

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

To moja próba robi tak:

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); 
    } 
} 

ten jest jednak powodujące wyjątek w czasie parseowania - System.ArgumentException: TabItem nie jest poprawną wartością dla właściwości "DisplayFilter". Jak skonfigurować przypisaną właściwość, aby móc używać żądanej składni XAML?

Odpowiedz

33

Pamiętaj, że XAML to po prostu skrótowa forma tworzenia obiektu. Aby utworzyć kolekcję/listę jako wartość dla dołączonej właściwości DisplayFilter, musisz zamknąć te TabItems wewnątrz innego znacznika kolekcji. Jeśli nie chcesz tego zrobić, co jest zrozumiałe, musisz zainicjować kolekcję przy pierwszym dostępie do właściwości.

Jest tylko jeden problem: metoda getter jest pomijana przez czytnik XAML jako optymalizacja. Można temu zapobiec poprzez wybranie innej nazwy dla nazwa argument do wywołania RegisterAttached:

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

Następnie getter właściwość zostanie wywołana i można sprawdzić null. Możesz przeczytać więcej na ten temat w this blog post.

Edytuj: Wygląda na to, że powiązany wpis na blogu nie jest taki jasny. Zmienić tylko nazwa ciąg przekazany do RegisterAttached, nie nazwę statycznych metod 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) 
{ ... } 

Trzeba zainicjować kolekcję w sposobie 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; 
} 

Wygląda na to, że dodajesz tylko elementy TabItem do tej kolekcji. Następnie możesz sprawić, że kolekcja będzie bezpieczna, ale używanie IList<T> nie działa, ponieważ analizator składni XAML nie może wywołać ogólnej metody Add(T). Collection<T> i List<T> również implementują nietypowy interfejs IList i mogą być używane w tym przypadku. Proponuję, aby utworzyć nowy typ kolekcji w przypadku, gdy chcesz zrobić pewne zmiany w kolekcji w przyszłości:

public class TabItemCollection : Collection<TabItem> 
{ 
} 

Jeśli nie dbają o ustawienie kolekcji wyraźnie tak:

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

można usunąć metodę SetDisplayFilter.

Podsumowując:

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

sklarowane moją odpowiedź, HTH! – gix

+0

Następnie musi być coś jeszcze nie tak, ponieważ napisany kod działa bez zarzutu. Zobacz http://nopaste.org/p/adqfm5EPi krótki i pełny przykład. – gix

+0

Wygląda na to, że nie możesz korzystać z zasobów w ten sposób. Jeśli nie korzystasz z zasobów lub kolekcji jawnej, wydaje się, że działa. – gix

Powiązane problemy