Можно ли установить код позади словаря ресурсов в WPF для обработки событий?

147

Можно ли установить код за словарь ресурсов в WPF. Например, в пользовательском контроле для кнопки вы объявляете ее в XAML. Код обработки события для нажатия кнопки выполняется в файле кода за элементом управления. Если бы мне нужно было создать шаблон данных с кнопкой, как я могу написать код обработчика событий для его нажатия кнопки в словаре ресурсов.

Crippeoblade
источник
1
Правильный способ сделать это - использовать команду, она также дает вам возможность включать и отключать кнопку, в то время как вы можете сделать это так, как некоторые ответы предложили, чтобы она пахла мне как хак.
Аран Малхолланд

Ответы:

209

Я думаю, что вы спрашиваете, что вы хотите файл с выделенным кодом для ResourceDictionary. Вы можете полностью сделать это! На самом деле, вы делаете это так же, как для окна:

Скажем, у вас есть ResourceDictionary под названием MyResourceDictionary. В вашем файле MyResourceDictionary.xaml поместите атрибут x: Class в корневой элемент, например, так:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    x:Class="MyCompany.MyProject.MyResourceDictionary"
                    x:ClassModifier="public">

Затем создайте код для файла MyResourceDictionary.xaml.cs со следующим объявлением:

namespace MyCompany.MyProject
{
    partial class MyResourceDictionary : ResourceDictionary
    { 
       public MyResourceDictionary()
       {
          InitializeComponent();
       }     
       ... // event handlers ahead..
    }
}

И вы сделали. Вы можете поместить в код все, что пожелаете: методы, свойства и обработчики событий.

== Обновление для приложений Windows 10 ==

И на случай, если вы играете с UWP, есть еще одна вещь, о которой нужно знать:

<Application x:Class="SampleProject.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:rd="using:MyCompany.MyProject">
<!-- no need in x:ClassModifier="public" in the header above -->

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <!-- This will NOT work -->
                <!-- <ResourceDictionary Source="/MyResourceDictionary.xaml" />-->

                <!-- Create instance of your custom dictionary instead of the above source reference -->
                <rd:MyResourceDictionary />

            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

</Application>
ageektrapped
источник
7
Как дополнение к ответу ageektrapped: убедитесь, что вы указали полное имя вашего класса codebehind в атрибуте x: Class. x:Class="MyCompany.MyProject.MySubFolder1.MyResourceDictionary"В противном случае, если вы просто введете x: Class = "MyResourceDictionary", парсер xaml не найдет ваш класс.
энергично
29
Убедитесь, что вы предоставляете конструктор по умолчанию в частичном классе codebehind, и убедитесь, что он вызывает InitializeComponent (). (В моем случае я использовал MEF для экспорта словаря ресурсов.)
Скотт Уитлок
4
Обновлен фрагмент кода для комментария. Я чувствовал, что это было необходимо, чтобы завершить ответ; распространенная ошибка Я сделал это только сейчас :) Вернитесь, если вам это не нравится. Спасибо за ответ.
Гишу
2
Обратите внимание, что (по крайней мере, в wp8.1) это больше не действует, и вам нужно будет создать пользовательский пользовательский контроль, на который ссылается ваш ресурсный справочник
Jared
9
Вам также нужно будет установить действие Build для файла XAML ResourceDictionary на «Page», в противном случае вызов InitializeComponent () не будет скомпилирован. (Файлы ResourceDictionary XAML обычно по умолчанию имеют значение «Ресурс».)
user1454265
9

Я не согласен с «ageektrapped» ... использование метода частичного класса не является хорошей практикой. Какова будет цель отделения словаря от страницы?

Из выделенного кода вы можете получить доступ к элементу ax: Name, используя:

Button myButton = this.GetTemplateChild("ButtonName") as Button;
if(myButton != null){
   ...
}

Вы можете сделать это в методе OnApplyTemplate, если хотите подключиться к элементам управления при загрузке пользовательского элемента управления. OnApplyTemplate должен быть переопределен, чтобы сделать это. Это обычная практика, которая позволяет вашему стилю оставаться оторванным от контроля. (Стиль не должен зависеть от элемента управления, но элемент управления должен зависеть от наличия стиля).

Phobis
источник
7
Фобис Я думаю, что целью отделения словаря от страницы является возможность повторного использования и удобочитаемости главной страницы xaml. Вышеупомянутое решение работает для меня тоже.
cleftheris
5

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

Стандартное поведение для текстовых полей, когда они получают фокус, заключается в том, что курсор помещается в то же положение, в котором он находился, когда элемент управления терял фокус. Если вы предпочитаете во всем приложении, чтобы, когда пользователь вкладывал в любое текстовое поле, было выделено все содержимое текстового поля, то добавление простого обработчика в словаре ресурсов могло бы помочь.

Любая другая причина, по которой вы хотите, чтобы поведение по умолчанию для взаимодействия с пользователем отличалось от стандартного, кажется хорошим кандидатом на код в словаре ресурсов.

Полностью согласен, что все, что специфично для функциональности приложения, не должно быть в коде позади словаря ресурсов.

Пит Махер
источник
0

XAML предназначен для построения графов объектов, не содержащих код.
Шаблон данных используется для указания того, как пользовательский объект-объект должен отображаться на экране ... (например, если это элемент списка), поведение не является частью области компетенции шаблона данных. Перерисовать решение ...

Gishu
источник
Вывод: вы бы порекомендовали использовать ресурс dic с кодом позади или нет? Я никогда не использовал это, я сомневаюсь.
Шимми Вайцхандлер
1
Я бы не стал - для меня это неправильно. Словарь должен возвращать значения для определенных ключей. В случае OP, связывание кода с шаблоном данных. Я бы предпочел другой подход. Например, используйте модель Command. Мне нужно больше деталей по проблеме ОП, чтобы порекомендовать другой вариант.
Гишу
1
Совершенно не согласен. С MVVM есть один сценарий, где наличие кода чрезвычайно полезно: разработка вложенных свойств. Получите его работу с кодом позади, затем перенесите его на присоединенное свойство. Это намного быстрее, чем простая разработка присоединенного свойства с нуля, если только у вас нет мозга размером с Манхэттен.
Контанго