Как найти ресурс в UserControl из класса DataTemplateSelector в WPF?

Я создаю свой собственный UserControl, и у меня есть два разных DataTemplates в разделе UserControl.Resources в моем XAML. Я хочу выбирать между этими двумя шаблонами данных в зависимости от значения свойства объектов, отображаемых в списке. Я делаю это, создавая собственный класс DataTemplateSelector и переопределяя метод SelectTemplate, который должен возвращать шаблон DataTemplate, который я хочу использовать. Однако я понятия не имею, как «найти» мои шаблоны данных, расположенные в разделе ресурсов UserControls, все примеры, которые я видел, извлекают шаблоны данных только из Window.Resources. В этом примере они извлекают текущий MainWindow, а затем используют FindResource для поиска DataTemplate. Как мне получить свой UserControl аналогично?:


public override DataTemplate 
            SelectTemplate(object item, DependencyObject container)
        {
            if (item != null && item is AuctionItem)
            {
                AuctionItem auctionItem = item as AuctionItem;
                Window window = Application.Current.MainWindow;

                switch (auctionItem.SpecialFeatures)
                {
                    case SpecialFeatures.None:
                        return 
                            window.FindResource("AuctionItem_None") 
                            as DataTemplate;
                    case SpecialFeatures.Color:
                        return 
                            window.FindResource("AuctionItem_Color") 
                            as DataTemplate;
                }
            }

            return null;
        }

Приведенный выше пример взят отсюда: ItemsControl.ItemTemplateSelector Свойство


person Joakim    schedule 27.05.2009    source источник


Ответы (3)


Обычно я создаю свой экземпляр DataTemplateSelector из кода с параметром UserControl as в конструкторе DataTemplateSelector, например так:

public class MyUserControl : UserControl
{
    public MyUserControl()
    {
        Resources["MyDataTemplateSelector"] = new MyDataTemplateSelector(this);
        InitializeComponent();
    }
}

public class MyDataTemplateSelector : DataTemplateSelector
{
    private MyUserControl parent;
    public MyDataTemplateSelector(MyUserControl parent)
    {
        this.parent = parent;
    }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        parent.DoStuff();
    }
}

Не самая красивая девушка в городе, но со своей задачей справляется ;)

Надеюсь это поможет!

person Arcturus    schedule 27.05.2009
comment
Нет ли способа сделать то же самое в XAML? - person Joakim; 27.05.2009
comment
Хорошо, это прекрасно работает... Но было бы неплохо узнать, как это сделать рекомендуется, предпочтительно делать все это в XAML. - person Joakim; 27.05.2009
comment
Так и есть... Я тоже хотел бы знать более красивый способ... но я не думаю, что эту проблему можно решить с помощью XAML. Вам понадобится какая-то ссылка в вашем коде, поэтому проще всего просто дать прямо;) - person Arcturus; 28.05.2009
comment
Кажется, это единственный способ выполнить эту задачу и в Метро. Ни один из других вариантов не работает из-за ограничений в реализации Metro. - person SergioL; 20.07.2012
comment
Создает ли это цикл сохранения? - person Vasiliy Kulakov; 20.08.2014

Попробуй это:

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item != null && item is AuctionItem)
        {
            AuctionItem auctionItem = item as AuctionItem;

            switch (auctionItem.SpecialFeatures)
            {
                case SpecialFeatures.None:
                    return 
                        ((FrameworkElement)container).FindResource("AuctionItem_None") 
                        as DataTemplate;
                case SpecialFeatures.Color:
                    return 
                        ((FrameworkElement)container).FindResource("AuctionItem_Color") 
                        as DataTemplate;
            }
        }

        return null;
    }
person scrat789    schedule 17.08.2011

Решение WinRT и Windows Phone включает перемещение вверх по визуальному дереву до тех пор, пока не будет найден родительский элемент управления:

    protected override Windows.UI.Xaml.DataTemplate SelectTemplateCore(object item, Windows.UI.Xaml.DependencyObject container)
    {
        var parent = FindParent<MyParentControlType>(container as FrameworkElement);

        if(parent != null)
        {
            if (item is Something)
                return parent.Resources["TemplateForSomething"] as DataTemplate;
            else if(item is SomethingElse)
                return parent.Resources["TemplateForSomethingElse"] as DataTemplate;
            else 
                // etc
        }
        else
        {
            return App.Current.Resources["SomeFallbackResource"] as DataTemplate;
        }
    }

    public static T FindParent<T>(FrameworkElement element) where T : FrameworkElement
    {
        FrameworkElement parent = Windows.UI.Xaml.Media.VisualTreeHelper.GetParent(element) as FrameworkElement;

        while (parent != null)
        {
            T correctlyTyped = parent as T;

            if (correctlyTyped != null)
                return correctlyTyped;
            else
                return FindParent<T>(parent);
        }

        return null;
    }

Метод FindParent основан на принятом здесь ответе: Как получить ListView из ListViewItem?

person Vasiliy Kulakov    schedule 20.08.2014