2009-09-19 15 views
19

Quiero crear una propiedad adjunta que se puede utilizar con esta sintaxis:propiedad adjunta lista tipo

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

Este es mi intento de hacerlo:

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

Esto, sin embargo, es causando una excepción en tiempo de análisis - System.ArgumentException: TabItem no es un valor válido para la propiedad 'DisplayFilter'. Entonces, ¿cómo configuro mi propiedad adjunta para poder usar la sintaxis XAML deseada?

Respuesta

33

Recuerde que XAML es básicamente una forma abreviada de creación de objetos. Por lo tanto, para crear una colección/lista como el valor de la propiedad adjunta DisplayFilter, debe encerrar esos TabItems dentro de otra etiqueta de colección. Si no quiere hacer eso, lo que es comprensible, debe inicializar la colección la primera vez que se accede a la propiedad.

Solo hay un problema con esto: El método de obtención se omite por el lector XAML como una optimización. Puede evitar este comportamiento mediante la elección de un nombre diferente para el nombre de argumento para la llamada RegisterAttached:

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

A continuación, se llamará la propiedad de captador y se puede comprobar si hay null. Puede leer más sobre eso en this blog post.

Editar: Parece que la publicación de blog vinculada no está tan clara. Cambia única el nombre de la cadena que se pasa a RegisterAttached, no el nombre de los métodos get/set estáticas:

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

Usted tiene que inicializar la colección en el GetDisplayFilter método:

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

Parece que solo agrega TabItem elementos a esa colección. Luego puede hacer que la colección sea segura para el tipo, pero usar IList<T> no funciona, ya que el analizador XAML no puede invocar el método genérico Add(T). Collection<T> y List<T> también implementan la interfaz no genérica IList y se pueden usar en este caso. Yo sugeriría para crear un nuevo tipo de colección en caso de que quiera hacer algunos cambios en la colección en el futuro:

public class TabItemCollection : Collection<TabItem> 
{ 
} 

Si no se preocupan por el establecimiento de la colección de forma explícita como esto:

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

puede eliminar el método SetDisplayFilter.

En resumen:

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

Se clarificó mi respuesta, HTH! – gix

+0

Entonces debe haber algo más incorrecto porque el código publicado funciona bien. Vea http://nopaste.org/p/adqfm5EPi para un ejemplo corto y completo. – gix

+0

Parece que no puede usar recursos de esta manera. Si no usa recursos o una colección explícita, parece que funciona. – gix

Cuestiones relacionadas