Я хочу привязать элемент ItemsCollection, но вместо рендеринга элементов коллекции я хочу отобразить под-объекты, полученные через свойство в элементе коллекции.
Чтобы быть более конкретным: это будет просмотрщик 2D-карт для игры (хотя в его текущем состоянии это еще не 2D). Я привязываю элемент ItemsControl к ObservableCollection <Square> , где Square имеет свойство Terrain (типа Terrain). Ландшафт является базовым классом и имеет различные потомки.
Я хочу, чтобы ItemControl отображал свойство 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, содержащий ящик для загара (для Dirt) и серебряную коробку (для SteelPlate). Но я получаю это с ненужными накладными расходами.
Моя особая проблема связана с моей DataTemplate для Square:
<DataTemplate DataType="{x:Type TerrainDataModels:Square}">
<ContentControl Content="{Binding Path=Terrain}"/>
</DataTemplate>
То, что я действительно хочу сказать, - "нет, не мешайте рендерингу самого Квадрата, вместо этого возвращайте его свойство Terrain". Это приближается к этому, но это добавляет дополнительные два элемента управления к визуальному дереву для каждой площади: ContentControl, как явно закодировано в вышеупомянутом XAML, и его ContentPresenter. Я не особо хочу здесь ContentControl; Я действительно хочу закоротить и вставить свойство Terrain DataTemplate непосредственно в дерево управления.
Но как я могу показать ItemsControl для рендеринга collectionitem.Terrain(таким образом, глядя на один из вышеперечисленных DataTemplates для объекта Terrain), а не на рендеринг collectionitem (и ищет DataTemplate для объекта Square)?
Я хочу использовать DataTemplates для ландшафтов, но вовсе не обязательно для Square - это был только первый подход, который я нашел, который работал адекватно. Фактически, я действительно хочу сделать что-то совершенно другое - я действительно хочу, чтобы ItemControl DisplayMemberPath был "Terrain". Это делает правый объект (объект Dirt или SteelPlate) напрямую, без добавления дополнительного ContentControl или ContentPresenter. К сожалению, DisplayMemberPath всегда отображает строку, игнорируя DataTemplates для ландшафтов. Поэтому у него появилась правильная идея, но это бесполезно для меня.
Все это может быть преждевременной оптимизацией, и если нет простого способа получить то, что я хочу, я буду жить с тем, что у меня есть. Но если есть "способ WPF", который я еще не знаю о привязке к свойству, а не ко всему элементу коллекции, он добавит мне понимание WPF, и это действительно то, что мне нужно.