2009-09-19 11 views
19

Voglio creare una proprietà associata che può essere utilizzato con questa sintassi:Attached proprietà di elenco di tipo

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

Questo è il mio tentativo di fare così:

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

Questo, tuttavia, è causando un'eccezione in fase di analisi - System.ArgumentException: TabItem non è un valore valido per la proprietà 'DisplayFilter'. Quindi, come posso configurare la mia proprietà associata in modo da poter utilizzare la sintassi XAML desiderata?

risposta

33

Ricorda che XAML è fondamentalmente solo una forma abbreviata di creazione di oggetti. Pertanto, per creare una raccolta/un elenco come valore per la proprietà DisplayFilter allegata, è necessario racchiudere tali TabItems all'interno di un altro tag di raccolta. Se non si desidera farlo, il che è comprensibile, è necessario inizializzare la raccolta la prima volta che si accede alla proprietà.

C'è solo un problema: il metodo getter viene saltato dal lettore XAML come ottimizzazione. È possibile evitare questo comportamento scegliendo un nome diverso per la nome argomento per la chiamata RegisterAttached:

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

Poi sarà chiamato il getter proprietà e si può verificare la presenza di null. Puoi leggere ulteriori informazioni al riguardo nel numero this blog post.

Modifica: Sembra che il post del blog collegato non sia chiaro. Si cambia solo il nome della stringa passata a RegisterAttached, non il nome dei metodi get/set statici:

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) 
{ ... } 

È necessario inizializzare la raccolta nel metodo 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; 
} 

Sembra che tu aggiunga solo gli elementi TabItem a quella raccolta. Quindi è possibile rendere sicura la raccolta, ma l'utilizzo di IList<T> non funziona poiché il parser XAML non può richiamare il metodo generico Add(T). Collection<T> e List<T> implementano anche l'interfaccia non generica IList e possono essere utilizzati in questo caso. Vorrei suggerire di creare un nuovo tipo di raccolta nel caso in cui si desidera fare alcune modifiche alla raccolta in futuro:

public class TabItemCollection : Collection<TabItem> 
{ 
} 

Se non vi interessa su come impostare la raccolta in modo esplicito in questo modo:

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

è possibile rimuovere il metodo SetDisplayFilter.

In sintesi:

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

chiarito la mia risposta, HTH! – gix

+0

Quindi ci deve essere qualcos'altro che non va perché il codice postato funziona bene. Vedi http://nopaste.org/p/adqfm5EPi per un esempio breve e completo. – gix

+0

Sembra che tu non possa usare le risorse in questo modo. Se non si utilizzano risorse o una raccolta esplicita, sembra che funzioni. – gix

Problemi correlati