Silverlight DataGrid - привязка к коллекции коллекций объектов - PullRequest
0 голосов
/ 08 января 2010

Проблема: данные, которые я пытаюсь отобразить, по сути являются коллекцией коллекций какого-либо объекта. Таким образом, строки могут быть любым числом, нормальным для сетки данных, а столбцы также любым числом. Это не так нормально для сетки данных. Обычно у вас есть заданное количество столбцов, и ваши строки различаются. Ячейка таблицы данных будет либо строкой, либо значением, которое можно изменить с помощью комбинированного списка.

Попытка решения: я пытался динамически добавлять столбцы в сетку данных, и хотя это работало просто отлично (добавляя их в codebehind), реальная проблема, с которой я столкнулся, заключалась в том, как связать нижележащие объекты. Данные строятся динамически, и я попробовал несколько форматов. Я попробовал коллекцию массивов, а также ObservableCollection of ObservableCollections. Я мог связываться с объектами, но поскольку привязки в Silverlight должны связываться со свойствами, я не мог найти решение, представляющее данные таким образом.

В результате я решил отобразить данные более традиционным способом со списком и сеткой данных. Когда вы выбираете элемент в списке, он повторно заполняет данные в сетке данных для отображения объектов.

Вопрос: есть ли способ привязать ячейку таблицы данных к коллекции коллекций объектов?

Я нашел этот вопрос (WPF), который выглядит похоже, и он не помог никому. Я думаю, что это та же проблема. WPF DataGrid: привязка источника данных DataGridComboxBox к коллекции коллекций

Ответы [ 2 ]

1 голос
/ 08 января 2010

Одно из возможных решений - вместо использования простой коллекции в качестве внутреннего объекта, создать класс, производный от коллекции, и реализовать на нем ICustomTypeDescriptor. В реализации интерфейса перебираем элементы коллекции и соответственно заполняем коллекцию дескрипторов свойств. Как только вы это сделаете, вы сможете связать эти свойства из XAML.

Пример - объект данных, основанный на словаре, который вы можете привязать к его именам ключей (я сжал в одну строку все тривиальные реализации методов):

class DictionaryDataObject : Dictionary<string, object>, ICustomTypeDescriptor
{
    #region ICustomTypeDescriptor Members

    public AttributeCollection GetAttributes() { return AttributeCollection.Empty; }
    public string GetClassName() { return "DictionaryDataObject"; }
    public string GetComponentName() { return null; }
    public TypeConverter GetConverter() { return null; }
    public EventDescriptor GetDefaultEvent() { return null; }
    public PropertyDescriptor GetDefaultProperty() { return null; }
    public object GetEditor(Type editorBaseType) { return null; }
    public EventDescriptorCollection GetEvents(Attribute[] attributes) { return EventDescriptorCollection.Empty; }
    public EventDescriptorCollection GetEvents() { return EventDescriptorCollection.Empty; }
    public PropertyDescriptorCollection GetProperties() { return GetProperties(null); }
    public object GetPropertyOwner(PropertyDescriptor pd) { return this; }

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        var pds =
            this.Keys
            .Select(x => new DictionaryPropertyDescriptor(x))
            .ToArray();
        return new PropertyDescriptorCollection(pds);
    }

    #endregion
}

class DictionaryPropertyDescriptor : PropertyDescriptor
{
    public DictionaryPropertyDescriptor(string name) : base(name, null) { }
    public override bool CanResetValue(object component) { return false; }
    public override Type ComponentType { get { return null; } }
    public override bool IsReadOnly { get { return false; } }
    public override Type PropertyType { get { return typeof(object); } }
    public override void ResetValue(object component) { }
    public override bool ShouldSerializeValue(object component) { return false; }

    public override object GetValue(object component)
    {
        var dic = component as DictionaryDataObject;
        if (dic == null) return null;
        return dic[Name];
    }

    public override void SetValue(object component, object value)
    {
        var dic = component as DictionaryDataObject;
        if (dic == null) return;
        dic[Name] = value;
    }
}

Пример настройки объекта из кода:

DictionaryDataObject ddo = new DictionaryDataObject();

public Window4()
{
    ddo["propa"] = 1;
    ddo["propb"] = "foo";
    ddo["propc"] = "bar";
    ddo["propd"] = 4.5;
    InitializeComponent();
    DataContext = ddo;
}

Использование XAML:

<Window.Resources>
    <DataTemplate x:Key="template">
        <WrapPanel>
            <TextBlock Text="{Binding propa}" Margin="5"/>
            <TextBlock Text="{Binding propb}" Margin="5"/>
            <TextBlock Text="{Binding propc}" Margin="5"/>
            <TextBlock Text="{Binding propd}" Margin="5"/>
        </WrapPanel>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ContentControl Content="{Binding}" ContentTemplate="{StaticResource template}"/>
</Grid>

Если вы хотите адаптировать это решение к списку, а не к словарю, вы должны установить каждое имя свойства на основе какого-либо свойства элемента списка.

0 голосов
/ 09 марта 2010

Мне кажется, я понимаю, чего вы пытаетесь достичь, и у меня действительно есть более элегантное решение вашей проблемы, и оно не требует написания каких-либо пользовательских классов. Я написал сообщение в блоге по этому вопросу. Блог ориентирован на DataGrid из набора инструментов Silverlight, но вы можете легко изменить его для использования любой сетки.

Решение здесь.

Дайте мне знать, если это то, что вы искали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...