Ist es möglich, Code hinter einem Ressourcenwörterbuch in WPF für die Ereignisbehandlung festzulegen?

147

Ist es möglich, Code hinter einem Ressourcenwörterbuch in WPF festzulegen? Beispielsweise deklarieren Sie in einer Benutzersteuerung für eine Schaltfläche diese in XAML. Der Ereignisbehandlungscode für den Schaltflächenklick erfolgt in der Codedatei hinter dem Steuerelement. Wenn ich eine Datenvorlage mit einer Schaltfläche erstellen möchte, wie kann ich den Ereignishandlercode für die Schaltfläche schreiben, indem Sie im Ressourcenwörterbuch klicken.

Crippeoblade
quelle
1
Der richtige Weg, dies zu tun, ist die Verwendung eines Befehls. Er gibt Ihnen auch die Möglichkeit, die Schaltfläche zu aktivieren und zu deaktivieren, während Sie dies so tun können, wie es einige Antworten vermuten lassen, dass es für mich nach einem Hack riecht.
Aran Mulholland

Antworten:

209

Ich denke, Sie möchten eine CodeBehind-Datei für ein ResourceDictionary. Sie können dies völlig tun! Tatsächlich machen Sie es genauso wie bei einem Fenster:

Angenommen, Sie haben ein ResourceDictionary mit dem Namen MyResourceDictionary. Fügen Sie in Ihrer Datei MyResourceDictionary.xaml das Attribut x: Class wie folgt in das Stammelement ein:

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

Erstellen Sie dann einen Code hinter der Datei MyResourceDictionary.xaml.cs mit der folgenden Deklaration:

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

Und du bist fertig. Sie können alles, was Sie möchten, in den Code dahinter einfügen: Methoden, Eigenschaften und Ereignishandler.

== Update für Windows 10 Apps ==

Und nur für den Fall, dass Sie mit UWP spielen, sollten Sie noch eines beachten:

<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
quelle
7
Als Ergänzung zur Antwort von ageektrapped: Stellen Sie sicher, dass Sie den vollständig qualifizierten Namen Ihrer Codebehind-Klasse in das Attribut x: Class einfügen. x:Class="MyCompany.MyProject.MySubFolder1.MyResourceDictionary"Andernfalls findet der xaml-Parser Ihre Klasse nicht, wenn Sie lediglich x: Class = "MyResourceDictionary" eingeben.
Viggity
29
Stellen Sie sicher, dass Sie einen Standardkonstruktor in der Teilklasse codebehind angeben, und stellen Sie sicher, dass InitializeComponent () aufgerufen wird. (In meinem Fall habe ich MEF verwendet, um das Ressourcenwörterbuch zu exportieren.)
Scott Whitlock
4
Aktualisiertes Code-Snippet für einen optimierten Kommentar. Ich hatte das Gefühl, dass es notwendig war, um die Antwort zu vervollständigen. ein häufiger Fehler. Ich habe es gerade getan :) Zurücksetzen, wenn es dir nicht gefällt. Danke für die Antwort.
Gishu
2
Beachten Sie, dass dies (zumindest in wp8.1) nicht mehr gültig ist und Sie eine benutzerdefinierte Benutzersteuerung erstellen müssen, auf die Ihr Ressourcenwörterbuch verweist
Jared
9
Sie müssen auch die Build-Aktion in der XAML-Datei des ResourceDictionary auf "Seite" setzen, da sonst der Aufruf von InitializeComponent () nicht kompiliert wird. (ResourceDictionary XAML-Dateien sind normalerweise standardmäßig auf "Resource" eingestellt.)
user1454265
9

Ich bin nicht einverstanden mit "ageektrapped" ... die Methode einer Teilklasse zu verwenden, ist keine gute Praxis. Was wäre dann der Zweck, das Wörterbuch von der Seite zu trennen?

Über einen Code-Behind können Sie auf das Element ax: Name zugreifen, indem Sie Folgendes verwenden:

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

Sie können dies in der OnApplyTemplate-Methode tun, wenn Sie beim Laden Ihres benutzerdefinierten Steuerelements eine Verbindung zu Steuerelementen herstellen möchten. OnApplyTemplate muss dazu überschrieben werden. Dies ist eine gängige Praxis und ermöglicht es Ihrem Stil, von der Steuerung getrennt zu bleiben. (Der Stil sollte nicht vom Steuerelement abhängen, aber das Steuerelement sollte von einem Stil abhängen.)

Phobis
quelle
7
Phobis Ich denke, der Zweck der Trennung des Wörterbuchs von der Seite besteht in der Wiederverwendbarkeit und Lesbarkeit der Hauptseite xaml. Die obige Lösung hat auch bei mir funktioniert.
Cleftheris
5

Gishu - obwohl dies eine "im Allgemeinen nicht zu ermutigende Praxis" zu sein scheint, ist hier ein Grund, warum Sie dies tun möchten:

Das Standardverhalten für Textfelder beim Fokussieren besteht darin, dass das Caret an derselben Position platziert wird, an der das Steuerelement den Fokus verloren hat. Wenn Sie in Ihrer gesamten Anwendung bevorzugen, dass der Benutzer den gesamten Inhalt des Textfelds hervorhebt, wenn der Benutzer zu einem Textfeld wechselt, reicht das Hinzufügen eines einfachen Handlers im Ressourcenwörterbuch aus.

Jeder andere Grund, aus dem sich das Standardverhalten der Benutzerinteraktion vom Standardverhalten unterscheiden soll, scheint ein guter Kandidat für einen Code in einem Ressourcenwörterbuch zu sein.

Stimmen Sie voll und ganz zu, dass alles, was für die Anwendungsfunktionalität spezifisch ist, nicht in einem Code hinter einem Ressourcenwörterbuch enthalten sein sollte.

Pete Maher
quelle
0

XAML dient zum Erstellen von Objektgraphen, die keinen Code enthalten.
Eine Datenvorlage wird verwendet, um anzugeben, wie ein benutzerdefiniertes Benutzerobjekt auf dem Bildschirm gerendert werden soll ... (z. B. wenn es sich um ein Listenfeldelement handelt). Das Verhalten gehört nicht zum Fachgebiet einer Datenvorlage. Zeichnen Sie die Lösung neu ...

Gishu
quelle
Fazit: Würden Sie empfehlen, Resource Dic mit Code dahinter zu verwenden oder nicht? Ich habe es nie benutzt, ich bezweifle.
Shimmy Weitzhandler
1
Ich würde nicht - für mich fühlt es sich nicht richtig an. Ein Wörterbuch sollte Werte für bestimmte Schlüssel zurückgeben. Im Fall des OP wird Code mit der Datenvorlage gebündelt. Ich würde lieber einen anderen Ansatz ausprobieren. Verwenden Sie beispielsweise das Befehlsmodell. Ich benötige weitere Details zum Problem des OP, um eine Diff-Lösung zu empfehlen.
Gishu
1
Stimme überhaupt nicht zu. Bei MVVM gibt es ein Szenario, in dem Code äußerst nützlich ist: das Entwickeln angehängter Eigenschaften. Bringen Sie es mit Code dahinter zum Laufen und portieren Sie es dann auf eine angehängte Eigenschaft. Dies ist viel schneller als das einfache Entwickeln der angehängten Eigenschaft von Grund auf neu, es sei denn, Sie haben ein Gehirn von der Größe Manhattans.
Contango