2012-02-25 19 views
10

¿Hay alguna manera de agregar una SortedList o un diccionario a ResourceDictionary y usar (y vincular) a un control a través de XAML?Agregar SortedList o Dictionary <int, string> a ResourceDictionary

He intentado esto, pero no podía encontrar la manera de hacerlo:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:sys="clr-namespace:System;assembly=mscorlib" 
    xmlns:coll="clr-namespace:System.Collections.Generic;assembly=mscorlib"> 

    <x:Array x:Key="test" 
      Type="sys:Object"> 
     <coll:KeyValuePair>***</coll:KeyValuePair> 
    </x:Array> 
+0

'x: Array' estaría bien si se agregan los valores * * con el fin, sólo agregaría el primer' ' y sería obtener el índice' 0' y así sucesivamente, entonces la unión podría apunte al indexador usando '[0]'. –

+0

@SeToY, por favor haga la pregunta como respondida. – Shimmy

+0

@Shimmy Era la mitad de la noche aquí y me fui a dormir ;-) – SeToY

Respuesta

16

SortedList es fácil, ya que no es genérico.

Si una clase implementa IDictionary puede agregar valores definiéndolos como los nodos secundarios usando x:Key para establecer la clave por la cual se deben agregar al diccionario.

xmlns:col="clr-namespace:System.Collections;assembly=mscorlib" 
<col:SortedList x:Key="list"> 
    <sys:String x:Key="0">Lorem</sys:String> 
    <sys:String x:Key="1">Ipsum</sys:String> 
    <sys:String x:Key="2">Dolor</sys:String> 
    <sys:String x:Key="3">Sit</sys:String> 
</col:SortedList> 
<!-- Usage: --> 
<ContentControl Content="{Binding [0], Source={StaticResource list}}" /> 

Las claves de elementos son cadenas aquí, para obtener enteros reales que podría utilizar una extensión de marcado costumbre que analiza la cadena a int, o mediante la definición de las teclas como primer recurso :

<sys:Int32 x:Key="key1">0</sys:Int32> 
<sys:Int32 x:Key="key2">1</sys:Int32> 
<sys:Int32 x:Key="key3">2</sys:Int32> 
<sys:Int32 x:Key="key4">3</sys:Int32> 

<col:SortedList x:Key="list"> 
    <sys:String x:Key="{StaticResource key1}">Lorem</sys:String> 
    <sys:String x:Key="{StaticResource key2}">Ipsum</sys:String> 
    <sys:String x:Key="{StaticResource key3}">Dolor</sys:String> 
    <sys:String x:Key="{StaticResource key4}">Sit</sys:String> 
</col:SortedList> 

El enlace se vuelve más complejo ya que el valor del indexador debe convertirse a int explícitamente ya que de lo contrario se interpretaría como una cadena.

<ContentControl Content="{Binding Path=[(sys:Int32)0], 
            Source={StaticResource list}}"/> 

Usted no puede omitir el Path= debido a una implementation detail.


Los diccionarios no son tan fáciles, ya que son genéricas y no hay (actualmente) no es una sencilla manera integrada para crear objetos genéricos en XAML. Sin embargo, al usar extensiones de marcado puede crear objetos genéricos a través de la reflexión.

La implementación de IDictionary en una extensión de este tipo también le permite completar esa instancia recién creada. Aquí está una muy mediocre ejemplo:

public class DictionaryFactoryExtension : MarkupExtension, IDictionary 
{ 
    public Type KeyType { get; set; } 
    public Type ValueType { get; set; } 

    private IDictionary _dictionary; 
    private IDictionary Dictionary 
    { 
     get 
     { 
      if (_dictionary == null) 
      { 
       var type = typeof(Dictionary<,>); 
       var dictType = type.MakeGenericType(KeyType, ValueType); 
       _dictionary = (IDictionary)Activator.CreateInstance(dictType); 
      } 
      return _dictionary; 
     } 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     return Dictionary; 
    } 

    public void Add(object key, object value) 
    { 
     if (!KeyType.IsAssignableFrom(key.GetType())) 
      key = TypeDescriptor.GetConverter(KeyType).ConvertFrom(key); 
     Dictionary.Add(key, value); 
    } 

    #region Other Interface Members 
    public void Clear() 
    { 
     throw new NotSupportedException(); 
    } 
    public bool Contains(object key) 
    { 
     throw new NotSupportedException(); 
    } 
    // <Many more members that do not matter one bit...> 
    #endregion 
} 
<me:DictionaryFactory x:Key="dict" KeyType="sys:Int32" ValueType="sys:String"> 
    <sys:String x:Key="0">Lorem</sys:String> 
    <sys:String x:Key="1">Ipsum</sys:String> 
    <sys:String x:Key="2">Dolor</sys:String> 
    <sys:String x:Key="3">Sit</sys:String> 
</me:DictionaryFactory> 

Como pasa en una instancia de mecanografiado como clave es un poco de un dolor que elegimos para hacer la conversión en IDictionary.Add antes de añadir el valor a la diccionario interno en su lugar (esto puede causar problemas con ciertos tipos).

Dado que el diccionario en sí está escrito, el enlace debe no requiere un modelo.

<ContentControl Content="{Binding [0], Source={StaticResource dict}}" /> 
+0

Gracias por esta increíble respuesta, esto me ha ayudado mucho :) – SeToY

+0

@SeToY: De nada, pensé que era una pregunta interesante. –

+0

@ H.B. por cierto: felicidades por el 40k –

Cuestiones relacionadas