WPF HiercharchicalDataTemplate.DataType: как реагировать на интерфейсы?

Проблема

У меня есть коллекция IThing, и я хочу создать HierarchicalDataTemplate для TreeView. Прямой DataType={x:Type local:IThing}, конечно, не работает, вероятно, потому, что создатели WPF не хотели обрабатывать возможные двусмысленности.

Поскольку это должно одновременно обрабатывать IThing из разных источников, ссылка на реализующий класс не может быть и речи.

Текущее решение

На данный момент я использую ViewModel, который проксирует IThing через конкретную реализацию:

public interface IThing {
    string SomeString { get; }
    ObservableCollection<IThing> SomeThings { get; }
    // many more stuff
}

public class IThingViewModel
{
     public IThing Thing { get; }
     public IThingViewModel(IThing it) { this.Thing = it; }
}

<!-- is never applied -->
<HierarchicalDataTemplate DataType="{x:Type local:IThing}">

<!-- is applied, but looks strange -->
<HierarchicalDataTemplate
    DataType="{x:Type local:IThingViewModel}"
    ItemsSource="{Binding Thing.SomeThings}">
    <TextBox Text="{Binding Thing.SomeString}"/>
</HierarchicalDataTemplate>

Вопрос

Есть ли лучший способ (то есть без прокси)?


person David Schmitt    schedule 03.11.2008    source источник


Ответы (3)


Причина этого в том, что селектор шаблонов по умолчанию поддерживает только конкретные типы, а не интерфейсы. Вам нужно создать собственный DataTemplateSelector и применить его к свойству ItemTemplateSelector TreeView. Я не могу найти URL-адрес, где я нашел его пример, но, надеюсь, с этой информацией вы сможете найти ее в Google.

person Community    schedule 16.12.2008
comment
Я думаю, вы имеете в виду msdn.microsoft.com/en- мы/библиотека/ ? Это, наверное, хорошая идея! - person David Schmitt; 16.12.2008
comment
@Richard: это не обязательно должен быть конкретный тип. Даже абстрактные типы работают нормально. У меня была аналогичная проблема, и я заменил интерфейс IThing абстрактным классом AbstractThing. - person chikak; 12.12.2010

Другая альтернатива (аналогичная решению jing): если у вас есть только один тип элемента, вы можете напрямую установить ItemTemplate. Тогда вам не нужно устанавливать ключ или тип данных.

В вашей ViewModel:

public ObservableCollection<IThing> Thingies { get; private set; }

В представлении:

<TreeView ItemsSource="{Binding Thingies}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding SomeThings}">
            <TextBox Text="{Binding SomeString}" />    
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>
person Daniel Rose    schedule 21.03.2012

Другое решение: вы даете ключ HierarchicalDataTemplate и помещаете его в Windows.Resources, а затем вручную ссылаетесь на него в TreeView. <TreeView ItemDataTemplate={StaticResource templateKey}/>

Но это ограничивает автоматический выбор шаблона данных в соответствии с типом данных, который предоставляется WPF TreeView.

person jing boxian    schedule 02.04.2010