ItemsCollection をデータバインドしたいのですが、コレクション アイテムをレンダリングする代わりに、コレクション アイテムのプロパティを介して到達したサブオブジェクトをレンダリングしたいと考えています。
より具体的に言うと、これはゲームの 2D マップ ビューアーになります (ただし、現在の状態ではまだ 2D ではありません)。ItemsControl を ObservableCollection<Square> にデータバインドします。Square には Terrain (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
}
また、以下を含む MapView と呼ばれる UserControl:
<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 です。しかし、私は不必要なオーバーヘッドでそれを取得します。
私の具体的な懸念は、Square の DataTemplate にあります。
<DataTemplate DataType="{x:Type TerrainDataModels:Square}">
<ContentControl Content="{Binding Path=Terrain}"/>
</DataTemplate>
私が本当に言いたいのは、「いいえ、わざわざ Square 自体をレンダリングするのではなく、Terrain プロパティを代わりにレンダリングすることです」ということです。これはそれに近いものですが、これにより、すべての Square のビジュアル ツリーに 2 つのコントロールが追加されます。上記の XAML で明示的にコード化された ContentControl と、その ContentPresenter です。ここでは特に ContentControl は必要ありません。Terrain プロパティの DataTemplate を短絡してコントロール ツリーに直接挿入したいのです。
しかし、collectionitem をレンダリングする (そして Square オブジェクトの DataTemplate を探す) のではなく、collectionitem.Terrain をレンダリングする (Terrain オブジェクトの上記の DataTemplates の 1 つを検索する) ように ItemsControl に指示するにはどうすればよいでしょうか?
地形には DataTemplates を使用したいのですが、必ずしも広場には必要ありません。これは、適切に機能することがわかった最初のアプローチでした。実際、私が本当にやりたいことは、まったく別のことです。実際には、ItemsControl の DisplayMemberPath を「Terrain」に設定したいと考えています。これにより、追加の ContentControl または ContentPresenter を追加することなく、適切なオブジェクト (Dirt または SteelPlate オブジェクト) が直接レンダリングされます。残念ながら、DisplayMemberPath は常に文字列をレンダリングし、地形の DataTemplates を無視します。それは正しい考えですが、私には役に立ちません。
このすべてが時期尚早の最適化かもしれません。欲しいものを手に入れる簡単な方法がない場合は、手に入れたもので生きていきます。しかし、コレクション項目全体ではなくプロパティにバインドする方法についてまだ知らない「WPF の方法」があれば、WPF の理解が深まります。