Я хочу привязать данные к ItemCollection, но вместо рендеринга элементов коллекции я хочу отобразить подобъекты, к которым можно получить доступ через свойство элемента коллекции.
Точнее, это будет просмотрщик 2D-карт для игры (хотя в его текущем состоянии это еще не 2D). Я связываю ItemsControl с ObservableCollection , где у Square есть свойство с именем Terrain (типа Terrain). Ландшафт является базовым классом и имеет различных потомков.
Я хочу, чтобы ItemsControl отображал свойство Terrain из каждого элемента коллекции, а не из самого элемента коллекции.
Я уже могу сделать эту работу, но с некоторыми ненужными издержками. Я хочу знать, есть ли хороший способ удалить ненужные накладные расходы.
В настоящее время у меня есть следующие классы (упрощенно):
public class Terrain {}
public class Dirt : Terrain {}
public class SteelPlate : Terrain {}
public class Square
{
public Square(Terrain terrain)
{
Terrain = terrain;
}
public Terrain Terrain { get; private set; }
// additional properties not relevant here
}
И UserControl под названием MapView, содержащий следующее:
<UserControl.Resources>
<DataTemplate DataType="{x:Type TerrainDataModels:Square}">
<ContentControl Content="{Binding Path=Terrain}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type TerrainDataModels:Dirt}">
<Canvas Width="40" Height="40" Background="Tan"/>
</DataTemplate>
<DataTemplate DataType="{x:Type TerrainDataModels:SteelPlate}">
<Canvas Width="40" Height="40" Background="Silver"/>
</DataTemplate>
</UserControl.Resources>
<ItemsControl ItemsSource="{Binding}"/>
Учитывая этот код, если я делаю:
mapView.DataContext = new ObservableCollection<Square> {
new Square(new Dirt()),
new Square(new SteelPlate())
};
Я получаю нечто, похожее на то, что я ожидаю: StackPanel, содержащую солярий (для грязи) и серебряную коробку (для стали). Но я получаю это с ненужными накладными расходами.
Моя особая проблема связана с моим DataTemplate для Square:
<DataTemplate DataType="{x:Type TerrainDataModels:Square}">
<ContentControl Content="{Binding Path=Terrain}"/>
</DataTemplate>
Что я действительно хочу сказать, так это «нет, не пытайтесь отображать сам Квадрат, вместо этого отображайте его свойство Terrain». Это близко к этому, но добавляет два визуальных элемента управления к визуальному дереву для каждого Square: ContentControl, как явно указано в приведенном выше XAML, и его ContentPresenter. Я не особо хочу ContentControl здесь; Я действительно хочу замкнуть накоротко и вставить DataTemplate свойства Terrain непосредственно в дерево элементов управления.
Но как мне сказать ItemsControl визуализировать collectionitem.Terrain (ища один из приведенных выше шаблонов DataTemplates для объекта Terrain) вместо рендеринга collectionitem (и искать DataTemplate для объекта Square)?
Я хочу использовать DataTemplates для ландшафтов, но совсем не обязательно для Square - это был только первый подход, который я нашел, который работал адекватно. На самом деле, я действительно хочу сделать что-то совершенно другое - я действительно хочу установить DisplayMemberPath ItemsControl в «Terrain». Это визуализирует нужный объект (объект Dirt или SteelPlate) напрямую, без добавления дополнительного ContentControl или ContentPresenter. К сожалению, DisplayMemberPath всегда отображает строку, игнорируя шаблоны данных для terrains. Так что у него правильная идея, но она бесполезна для меня.
Все это может быть преждевременной оптимизацией, и если нет простого способа получить то, что я хочу, я буду жить с тем, что у меня есть. Но если есть «путь WPF», о котором я пока не знаю, связать его со свойством, а не с целым элементом коллекции, это улучшит мое понимание WPF, и это именно то, чего я добиваюсь.