Добавление SortedList или Словарьв ResourceDictionary - PullRequest
10 голосов
/ 26 февраля 2012

Есть ли способ добавить SortedList или Dictionary в ResourceDictionary и использовать (и связать!) Его с элементом управления через XAML?

Я пробовал это, но не мог понятькак это сделать:

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

1 Ответ

18 голосов
/ 26 февраля 2012

SortedList легко, поскольку это не универсально.

Если класс реализует IDictionary, вы можете добавить значения, определив их как дочерние узлы, используя x:Key, чтобы задать ключ, по которому они должны быть добавлены в словарь.

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}}" />

Ключи элементов здесь являются строками, чтобы получить действительные числа, вы можете использовать пользовательское расширение разметки, которое разбирает строку на int, или сначала определив ключи как ресурс:

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

Привязка становится более сложной, так как значение индексатора необходимо явно преобразовать в int, иначе оно будет интерпретировано как строка.

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

Вы не можете опустить Path= из-за подробностей реализации .


Словари не так просты, потому что они являются общими, и в настоящее время нет простого встроенного способа создания универсальных объектов в XAML. Используя расширения разметки, вы можете создавать общие объекты с помощью отражения.

Реализация IDictionary на таком расширении также позволяет вам заполнить этот вновь созданный экземпляр. Вот очень схематичный пример :

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>

Поскольку передача в типизированном экземпляре в качестве ключа немного затруднительна, я решил выполнить преобразование в IDictionary.Add, прежде чем вместо этого добавить значение во внутренний словарь (это может вызвать проблемы с определенными типами).

Поскольку сам словарь набирается, привязка должна не требовать приведение.

<ContentControl Content="{Binding [0], Source={StaticResource dict}}" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...