4

特定のデータ型とその要素が与えられた場合、バインドされた要素に自動的に適用されるテンプレートをコードで決定する必要があります。

カスタム ロジックに基づいて特定のオブジェクトに使用するテンプレートを UIに伝えるために使用される DataTemplateSelector は探していません。代わりに、特定のデータ型と UI 要素にどのテンプレートを使用するかを UI に問い合わせています。

つまり、ウィンドウのリソース セクションで定義されたテンプレートに基づいて WPF が適用するものを探しています。これは、そのウィンドウのコントロールのリソースによってオーバーライドでき、DataTemplate または DataTemplate を明示的に設定することでオーバーライドできます。その要素に DataTemplateSelector を直接提供します。

また、SelectTemplate のデフォルトの実装を試しましたが、null が返されるため、そのルートにも進むことができません。

テストは、UI のどこにもデータ テンプレートまたはセレクターが定義されていない要素に「この値をどのように表示しますか?」と尋ねることです。うまくいけば、Text プロパティがそのオブジェクトの ToString メソッドに設定された TextBlock の定義を含む DataTemplate が返されます。これは、他に何も定義されていない場合にデフォルトで表示されるものです。

4

3 に答える 3

1

Thomas Levesque のテストされていないソリューションは、私にとってはうまくいきませんでしたが、素晴らしい出発点を提供してくれました。この場合、「コンテナー」引数は常にビジュアル ツリーにあるとは限らないため、最初にビジュアルが見つかるまで論理ツリーを上っていきます。それは、MarqueIV の優れた提案と相まって、かなり単純な解決策につながります。

次のコードは、本番環境で機能しています。あなたのマイレージは異なる場合があります。:)

public static DataTemplate FindTemplateForType(Type dataType, DependencyObject container)
{
    var frameworkElement = container as FrameworkElement;
    if (frameworkElement != null)
    {
        var key = new DataTemplateKey(dataType);
        var template = frameworkElement.TryFindResource(key) as DataTemplate;
        if (template != null)
            return template;
    }

    if (!(container is Visual || container is Visual3D))
    {
        container = FindClosestVisualParent(container);
        return FindTemplateForType(dataType, container);
    }
    else
    {
        var parent = VisualTreeHelper.GetParent(container);
        if (parent != null)
            return FindTemplateForType(dataType, parent);
        else
            return FindTemplateForType(dataType, Application.Current.Windows[0]);
    }
}

public static DependencyObject FindClosestVisualParent(DependencyObject initial)
{
    DependencyObject current = initial;
    bool found = false;

    while (!found)
    {
        if (current is Visual || current is Visual3D)
        {
            found = true;
        }
        else
        {
            current = LogicalTreeHelper.GetParent(current);
        }
    }

    return current;
}
于 2015-11-02T23:11:01.117 に答える
0

私は karfus と同じ方法を使用し、Type.Basetype に関連する datatemplate がある場合に備えて baseType に検索 datattemplate を追加しました

<Extension>
Public Function GetDatatemplateForType(container As DependencyObject, dataType As Type) As DataTemplate
    Dim dTemplate As DataTemplate = Nothing
    Dim currentType As Type = dataType
    Do While dTemplate Is Nothing And currentType IsNot Nothing
        dTemplate = DataTemplateForType(container, currentType)
        currentType = currentType.BaseType
    Loop
    Return dTemplate
End Function

Private Function DataTemplateForType(Container As DependencyObject, dataType As Type) As DataTemplate
    Dim resTemplate As DataTemplate = Nothing
    Dim dKey As DataTemplateKey = New DataTemplateKey(dataType)
    Dim fm As FrameworkElement = TryCast(Container, FrameworkElement)
    If fm IsNot Nothing Then
        resTemplate = fm.TryFindResource(dKey)
        If resTemplate Is Nothing AndAlso fm.GetVisualParent(Of FrameworkElement) IsNot Nothing Then
            Return DataTemplateForType(fm.GetVisualParent(Of FrameworkElement), dataType)
        Else
            Return resTemplate
        End If
    End If
    Return Nothing

End Function
于 2016-12-10T17:29:58.003 に答える
0

DataTemplateビジュアル ツリーを上って、適切なキーを持つリソースを探すことで、WPF が適切な を見つけるために使用しているロジックを手動で再現できると思います。可能な実装は次のとおりです(テストされていません):

static DataTemplate FindTemplateForType(Type dataType, DependencyObject container)
{
    var frameworkElement = container as FrameworkElement;
    if (frameworkElement != null)
    {
        var template = FindTemplateForType(dataType, frameworkElement.Resources);
        if (template != null)
            return template;
    }

    var parent = VisualTreeHelper.GetParent(container);
    if (parent != null)
        return FindTemplateForType(dataType, parent);
    else
        return FindTemplateForType(dataType, Application.Current.Resources);
}

static DataTemplate FindTemplateForType(Type dataType, ResourceDictionary resources)
{
    var entries =
        from DictionaryEntry e in resources
        where e.Key is Type && e.Value is DataTemplate
        let type = (Type)e.Key
        let template = (DataTemplate)e.Value
        where dataType.IsAssignableFrom(type)
        select template;

    var template = entries.FirstOrDefault();
    if (template != null)
        return template;

    foreach(var mergedDic in resources.MergedDictionaries)
    {
        template = FindTemplateForType(dataType, mergedDic);
        if (template != null)
            return template;        
    }

    return null;
}
于 2013-08-31T10:23:17.017 に答える