7

私は既知のインターフェイスのコレクションで初期化されたDataTemplateSelectorを作成しました。セレクタに渡された項目がこれらのインタフェースのいずれかを実装する場合、関連するデータテンプレートが返されます。DataTemplateがDataTemplateSelectorから明示的に返されたときに、DataTemplateをインターフェイスにバインドできないのはなぜですか?

まず、ここで問題になっているICategoryインタフェースは

が...

public interface ICategory 
{ 
    ICategory ParentCategory { get; set; } 
    string Name   { get; set; } 

    ICategoryCollection Subcategories { get; } 
} 

はここで、基本クラスやインターフェイスだけではなく、特定の具体的なクラスに基づいて一致DataTemplateSelectorだ...だ

[ContentProperty("BaseTypeMappings")] 
public class SubclassedTypeTemplateSelector : DataTemplateSelector 
{ 
    private delegate object TryFindResourceDelegate(object key); 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     var frameworkElement = container as FrameworkElement; 

     foreach(var baseTypeMapping in BaseTypeMappings) 
     { 
      // Check if the item is an instance of, a subclass of, 
      // or implements the interface specified in BaseType 
      if(baseTypeMapping.BaseType.IsInstanceOfType(item)) 
      { 
       // Create a key based on the BaseType, (not item.DataType as usual) 
       var resourceKey = new DataTemplateKey(baseTypeMapping.BaseType); 

       // Get TryFindResource method from either the FrameworkElement, 
       // or from the application 
       var tryFindResource = (frameworkElement != null) 
        ? (TryFindResourceDelegate)frameworkElement.TryFindResource 
        : Application.Current.TryFindResource; 

       // Use the TryFindResource delegate from above to try finding 
       // the resource based on the resource key 
       var dataTemplate = (DataTemplate)tryFindResource(resourceKey); 
       dataTemplate.DataType = item.GetType(); 
       if(dataTemplate != null) 
        return dataTemplate; 
      } 
     } 

     var defaultTemplate = DefaultDataTemplate ?? base.SelectTemplate(item, container); 
     return defaultTemplate; 
    } 

    public DataTemplate DefaultDataTemplate { get; set; } 

    public Collection<BaseTypeMapping> BaseTypeMappings { get; } = new Collection<BaseTypeMapping>(); 
} 

public class BaseTypeMapping 
{ 
    public Type BaseType { get; set; } 
} 

DataType = ICategoryを持つそれぞれのHierarchicalDataTemplateと共にリソースにどのようにセットアップされているのですか?

<HierarchicalDataTemplate DataType="{x:Type model:ICategory}" 
     ItemsSource="{Binding Subcategories}"> 

     <TextBlock Text="{Binding Name}" /> 

    </HierarchicalDataTemplate> 

    <is:SubclassedTypeTemplateSelector x:Key="SubclassedTypeTemplateSelector"> 
     <!--<is:BaseTypeMapping BaseType="{x:Type model:ICategory}" />--> 
    </is:SubclassedTypeTemplateSelector> 
両方のステップ実行、予想通り

そして最後に、ここでそれを使用してツリービューが...

<TreeView x:Name="MainTreeView" 
    ItemsSource="{Binding Categories}" 
    ItemTemplateSelector="{StaticResource SubclassedTypeTemplateSelector}" /> 

だ、私はそれをデバッグしてきましたし、が正しいデータテンプレートを確認することができ、ツリービューにを返されていますであるため、TreeViewは、ItemSourceバインディングとしてサブクエリを正しくロードしています。 HierarchicalDataTemplateにあります。これらはすべて期待通りに機能します。

テンプレートの内容自体は機能しません。ご覧のように、テンプレートは単にカテゴリの名前を表示することになっていますが、テンプレートなしでContentPresenterに直接配置されているかのようにオブジェクトをそのまま表示しているだけです。 UIで表示されるのはToStringの結果だけです。テンプレートの内容は完全に無視されます。

私が考えることができるのは、データ型用のインターフェイスを使用しているために機能しないことだけですが、子どものItemsSourceのバインディングが機能するため、ここでは困惑しています。

メモ:テストとして、コンクリートタイプ(カテゴリのみでなくカテゴリ)に基づいて2番目のDataTemplateを作成しました。これを実行すると、期待通りに機能しました。問題は、具体的な型がUIで参照されていないアセンブリにあることです。これが最初にインターフェイスを使用している理由のすべてです。

注:DataTypeプロパティを設定する代わりに、キーを使用してテンプレートを検索する方法も変更してみました。その場合、前と同じセレクタが同じリソースを見つけますが、まだ動作しません。

皮肉なことしかし、私は同じ鍵が、結合StaticResource経由で直接TreeViewコントロールのItemTemplateに設定することを使用する場合、それない仕事、私はセレクタからテンプレートを返すときにのみ動作していないという意味といは、DataTypeが設定されているかどうかに関係なく表示されます。*

+0

短い答え:それはそのように設計されているためです。おそらく、あなたは単一のクラスに対して複数の一致を得ることができるからです。 [MSDNの公式回答](https://social.msdn.microsoft.com/Forums/vstudio/en-US/1e774a24-0deb-4acd-a719-32abd847041d/data-templates-and-interfaces?forum=wpf) –

+0

あなたのMSDNリンクを見れば、あなたは、私が上でやっているDataTemplateSelectorを使うことができると具体的に言われます。あなたの主張と、彼らが決定したことは、インタフェース自体にマッチさせようとしていることです。これは私がここで達成しようとしているものではありません。 – MarqueIV

+0

元の質問は「なぜDataTemplateをインターフェイスにバインドできないのですか?」でした。私はあなたがなぜそれがそうであるかに興味があると思った。 –

答えて

1

何に動作しないことはDataTypeプロパティに設定されているので、あなたのXAMLマークアップで定義されたテンプレートが適用されていないので、これはテンプレート自体

の内容ですインタフェースタイプ。 @Manfred Radlwimmerが示唆しているように、これは設計によるものです:https://social.msdn.microsoft.com/Forums/vstudio/en-US/1e774a24-0deb-4acd-a719-32abd847041d/data-templates-and-interfaces?forum=wpf。このようなテンプレートをDataTemplateSelectorから返すと、既に発見したようには機能しません。

しかし、あなたは適切なデータテンプレートを選択するために、DataTemplateSelectorを使用する場合は、データテンプレートからdatatype属性を削除し、各テンプレートに一意のxを与えることができる:代わりにキー:

<HierarchicalDataTemplate x:Key="ICategory" ItemsSource="{Binding Subcategories}"> 
    <TextBlock Text="{Binding Name}" /> 
</HierarchicalDataTemplate> 

するあなたは、その後のことができるようにすべきです例えば、このキーを使用してリソースを解決:

var baseTypeName = "ICategory"; 
var dataTemplate = (DataTemplate)tryFindResource("baseTypeName"); 
+0

実際、私はそれを正確に試したが、どちらもうまくいきません。具体的には、DataTypeプロパティを削除してキーを追加し、そのキーで見つかったテンプレートを返しました(これは本質的にあなたが提案したものです)。しかし、もっと奇妙なことに、そのテンプレートをTreeViewのItemTemplate( '{StaticResource ICategory}')に直接設定すると、そのテンプレートは機能します。また、ItemsSourceバインディングはどちらのケースでも機能します。 – MarqueIV

-1
  1. DataTemplatesは、インタフェースに目指すことはできません - あなたは、セレクタまたは回避策を必要とする - >行わ。代わりに、あなたはあなたからテンプレート定義をタイプを削除する必要が一致
  2. を持っている場合、あなたは持っているならば、それは割り当てることはできませんチェックするBaseTypeMapping
  3. 使用BaseType.IsAssignableFrom(item.GetType())を実装する:あなただけの{タイプX}を使用することができます
  4. 間違ったタイプ - キーを追加します。
  5. #4の後にテンプレートにキーがあり、タイプを割り当てるだけで暗黙的に機能しないので、タイプを割り当てた後でそれを削除する必要があります - >dataTemplate.Key = null
  6. ここではIDEはありませんが、ressourcesはインスタンスを提供するため、参照によって変更されます。これはあなたの意図ですか?
+0

私は実際には、DataTemplateとDataTemplateKeyのプロパティを持っているので、実際にはBaseTypeMappingを使用しています(ここでは省略します)...代わりに、テンプレートにはDataTypeが割り当てられていないことを意味します。 ItemTemplateを返しますが、ItemTemplateSelectorで返されたときには返されません。なぜなら、特に私が言ったようにItemsSourceバインディング*が機能するからです。 – MarqueIV

関連する問題