Czy można ustawić kod za słownikiem zasobów w WPF do obsługi zdarzeń?

147

Czy można ustawić kod za słownikiem zasobów w WPF. Na przykład w kontrolce użytkownika dla przycisku deklarujesz go w języku XAML. Kod obsługi zdarzenia dla kliknięcia przycisku znajduje się w pliku kodu znajdującym się za formantem. Gdybym miał utworzyć szablon danych z przyciskiem, w jaki sposób mogę napisać kod obsługi zdarzeń dla jego kliknięcia przycisku w słowniku zasobów.

Crippeoblade
źródło
1
Prawidłowym sposobem na to jest użycie polecenia, które daje również możliwość włączania i wyłączania przycisku, podczas gdy możesz to zrobić w sposób, w jaki niektóre odpowiedzi sugerowały, że pachnie włamaniem.
Aran Mulholland

Odpowiedzi:

209

Myślę, że chcesz mieć plik związany z kodem dla ResourceDictionary. Możesz to zrobić całkowicie! W rzeczywistości robisz to tak samo, jak w przypadku okna:

Załóżmy, że masz ResourceDictionary o nazwie MyResourceDictionary. W pliku MyResourceDictionary.xaml umieść atrybut x: Class w elemencie głównym, na przykład:

<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">

Następnie utwórz kod związany z plikiem o nazwie MyResourceDictionary.xaml.cs z następującą deklaracją:

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

I jesteś skończony. Możesz umieścić w kodzie wszystko, co chcesz: metody, właściwości i programy obsługi zdarzeń.

== Aktualizacja dla aplikacji Windows 10 ==

Na wypadek, gdybyś grał z UWP , jest jeszcze jedna rzecz, o której należy pamiętać:

<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
źródło
7
Jako dodatek do odpowiedzi ageektrapped: Upewnij się, że w atrybucie x: Class umieściłeś w pełni kwalifikowaną nazwę swojej klasy codebehind. x:Class="MyCompany.MyProject.MySubFolder1.MyResourceDictionary"W przeciwnym razie, jeśli po prostu wstawisz x: Class = "MyResourceDictionary", parser xaml nie znajdzie twojej klasy.
viggity
29
Upewnij się, że podałeś domyślny konstruktor w częściowej klasie codebehind i upewnij się, że wywołuje InitializeComponent (). (W moim przypadku użyłem MEF do wyeksportowania słownika zasobów.)
Scott Whitlock,
4
Zaktualizowano fragment kodu komentarza za głosem. Czułem, że trzeba uzupełnić odpowiedź; częsty błąd. Zrobiłem to przed chwilą :) Przywróć, jeśli ci się nie podoba. Dziękuję za odpowiedź.
Gishu
2
Zauważ, że (przynajmniej w wp8.1) nie jest to już ważne i musiałbyś utworzyć niestandardową kontrolę użytkownika, do której odwołuje się twój słownik zasobów
Jared
9
Będziesz także musiał ustawić akcję kompilacji w pliku XAML ResourceDictionary na „Page”, w przeciwnym razie wywołanie InitializeComponent () nie zostanie skompilowane. (Pliki ResourceDictionary XAML są zwykle domyślnie ustawione na „Zasób”).
user1454265
9

Nie zgadzam się z „ageektrapped”… stosowanie metody częściowej nie jest dobrą praktyką. Jaki byłby zatem cel oddzielenia Słownika od strony?

Z poziomu kodu można uzyskać dostęp do elementu ax: Name za pomocą:

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

Można zrobić to w metodzie OnApplyTemplate jeśli chcesz hookup kontrolom Po wczytaniu kontroli zwyczaj. Aby to zrobić, należy zastąpić OnApplyTemplate. Jest to powszechna praktyka i pozwala na odłączenie twojego stylu od kontroli. (Styl nie powinien zależeć od kontrolki, ale kontrolka powinna zależeć od posiadania stylu).

Fobie
źródło
7
Fobie Myślę, że celem oddzielenia Słownika od strony jest możliwość ponownego wykorzystania i czytelności strony głównej xaml. U mnie też to rozwiązanie zadziałało.
cleftheris
5

Gishu - chociaż może się to wydawać, że jest to praktyka „generalnie nie do zachęcania”. Oto jeden z powodów, dla których warto to zrobić:

Standardowym zachowaniem pól tekstowych, gdy są one aktywne, jest umieszczenie karetki w tym samym miejscu, w którym było, gdy formant stracił fokus. Jeśli wolisz, aby w całej aplikacji, gdy użytkownik przechodził do dowolnego pola tekstowego, cała zawartość pola tekstowego była podświetlona, ​​dodanie prostego modułu obsługi w słowniku zasobów załatwi sprawę.

Każdy inny powód, dla którego chcesz, aby domyślne zachowanie interakcji użytkownika różniło się od zachowania po wyjęciu z pudełka, wydaje się być dobrym kandydatem na kod znajdujący się w słowniku zasobów.

Całkowicie zgadzam się, że wszystko, co jest specyficzne dla funkcji aplikacji, nie powinno znajdować się w kodzie za słownikiem zasobów.

Pete Maher
źródło
0

XAML służy do konstruowania grafów obiektów niezawierających kodu.
Szablon danych służy do wskazania, w jaki sposób niestandardowy obiekt użytkownika ma być renderowany na ekranie ... (np. Jeśli jest to element listy) zachowanie nie jest częścią obszaru specjalizacji szablonu danych. Przerysuj rozwiązanie ...

Gishu
źródło
Wniosek: Czy poleciłbyś używanie dic zasobów z kodem, czy nie? Nigdy go nie użyłem, wątpię.
Shimmy Weitzhandler
1
Nie chciałbym - nie wydaje mi się to właściwe. Słownik powinien zwracać wartości dla określonych kluczy. W przypadku OP, łączenie kodu z szablonem danych… Wolałbym spróbować innego podejścia… na przykład użyć modelu poleceń. Potrzebuję więcej szczegółów na temat problemu OP, aby polecić rozwiązanie różnicowe.
Gishu
1
Całkowicie się nie zgadzam. W przypadku MVVM istnieje jeden scenariusz, w którym posiadanie kodu jest niezwykle przydatne: tworzenie dołączonych właściwości. Uruchom go z kodem, a następnie przenieś go do dołączonej właściwości. Jest to znacznie szybsze niż po prostu rozwijanie dołączonej właściwości od zera, chyba że masz mózg wielkości Manhattanu.
Contango