Пытаясь взломать этот объект DataTemplateSelector


Я пытаюсь имитировать поведение по умолчанию в классе ItemsControl В класса ContentControl--персонализация контента на объект недвижимости и использовать DataTemplate, основанного на том, что типом объекта.

Я пытался отражатель dotPeek на осуществление управления ItemsControl, чтобы увидеть, как это работает, но я зашел в тупик. Следовательно, я придумал этот обычай объект DataTemplateSelector. Вот код, после которого я буду описывать, почему она хреновая.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Markup;
namespace TemplateSelectorAndInheritance
{
    /// <summary>
    /// A <see cref="DataTemplateSelector"/> that finds <see cref="DataTemplate">
    /// DataTemplates</see> by the bound object's <see cref="Type"/>.
    /// </summary>
    /// <remarks>This selector supports keys defined by both the 
    /// <see cref="TypeExtension"/> and the type name specified by namespace 
    /// (xmlns).</remarks>
    public sealed class TypeBasedDataTemplateSelector : DataTemplateSelector
    {
        /// <summary>
        /// When overridden in a derived class, returns a  
        /// <see cref="T:System.Windows.DataTemplate"/> based on custom logic.
        /// </summary>
        /// <param name="item">The data object for which to select the template.</param>
        /// <param name="container">The data-bound object.</param>
        /// <returns>
        /// Returns a <see cref="T:System.Windows.DataTemplate"/> or null. The default
        ///  value is null.</returns>
        public override DataTemplate SelectTemplate(
            object item, DependencyObject container)
        {

            if (item == null)
                return null;
            if (container == null)
                throw new ArgumentNullException("container");
            return FindFirstDataTemplate(
                    item.GetType(), 
                    container as FrameworkElement);
        }
        /// <summary>
        /// Recursively searches up the visual tree searching for an applicable template.
        /// </summary>
        /// <param name="type">The <see cref="Type"/> of the template</param>
        /// <param name="frameworkElement"><see cref="FrameworkElement"/></param>
        /// <returns><see cref="DataTemplate"/> if found, <c>null</c> otherwise.</returns>
        private DataTemplate FindFirstDataTemplate(
            Type type, 
            FrameworkElement frameworkElement)
        {
            if (frameworkElement == null)
                return null;
            var key = frameworkElement.Resources.Keys.OfType<DataTemplateKey>()
                .FirstOrDefault(x =>
                {
                    // there be hacks here
                    var targetType = x.DataType as Type;
                    var targetTypeName = x.DataType as string;
                    // this one is very bad, since it doesn't take into account namespaces
                    if (targetTypeName != null && targetTypeName.EndsWith(type.Name))
                        return true;
                    if (targetType != null && targetType == type)
                        return true;
                    return false;
                });
            if (key != null)
                return frameworkElement.Resources[key] as DataTemplate;
            // here's another hack--I'm picking the TP first, but I'm not sure
            // if this is best all the time?
            var parent = frameworkElement.TemplatedParent as FrameworkElement ?? 
                            frameworkElement.Parent as FrameworkElement;
            return FindFirstDataTemplate(type, parent);
        }
    }
}

Это работает, но очень хрупкие и угловатые. Я надеялся получить помощь по следующим вопросам:

Во-первых: если вы не используете {х:тип} расширение разметки, этот селектор может потерпеть неудачу. Я не могу понять, в ограниченном контексте метода SelectTemplate, как найти определенного пространства имен. Например, если вы выполните следующие действия

<DataTemplate xmlns:t="clr-namespace:Fubar" DataType="t:Derp"

тогда стоимость DataTemplateKey представляет собой строку: "Т:баттхерт". Я не могу понять, как узнать, что пространства имен, Т: представляет в контексте SelectTemplate способ.

Во-вторых: мой метод поиска физического/логического дерева ищу ресурсы сосет и делает меня несчастной. Там получил быть лучший способ для поиска ресурсов!

В-третьих: как мне искать моих родителей, я почти произвольно решил, что я выберу свойство templatedparent перед родителем, но я даже не уверен, что это лучшее, что можно сделать.

Whadyathink?



1172
5
задан 15 июня 2011 в 05:06 Источник Поделиться
Комментарии
1 ответ

Я думаю, что прежде всего вы должны избавиться от ищу dataTemplates по имени тип. Тогда вместо вашего метода вы сможете использовать метода findresource способ:

var resourceKey = new DataTemplateKey { DataType = type };
var dataTemplate = (DataTemplate)frameworkElement.FindResource(resourceKey);

Что касается вашего второго вопроса: я думаю, что это не имеет значения, какой вы примете во-первых, насколько я помню, они являются взаимоисключающими. Также на MSDN говорит:


Для шаблонов, родительского шаблона в конечном итоге будет иметь значение null. Чтобы обойти этот момент и продлить в логическое дерево, в котором шаблон фактически применяется, используйте свойство templatedparent

Таким образом, принимая во внимание это заявление я бы родителей ?? Свойство templatedparent.

2
ответ дан 16 июня 2011 в 12:06 Источник Поделиться