Est-il possible de définir du code derrière un dictionnaire de ressources dans WPF pour la gestion des événements?

147

Est-il possible de définir du code derrière un dictionnaire de ressources dans WPF. Par exemple, dans un usercontrol pour un bouton, vous le déclarez en XAML. Le code de gestion des événements pour le clic sur le bouton est effectué dans le fichier de code derrière le contrôle. Si je devais créer un modèle de données avec un bouton, comment puis-je écrire le code du gestionnaire d'événements pour son clic de bouton dans le dictionnaire de ressources.

Crippéoblade
la source
1
La bonne façon de faire est d'utiliser une commande, cela vous donne également la possibilité d'activer et de désactiver le bouton, tandis que vous pouvez le faire de la manière dont certaines réponses ont suggéré que cela me semble un hack.
Aran Mulholland

Réponses:

209

Je pense que ce que vous demandez, c'est que vous voulez un fichier code-behind pour un ResourceDictionary. Vous pouvez totalement le faire! En fait, vous procédez de la même manière que pour une fenêtre:

Supposons que vous ayez un ResourceDictionary appelé MyResourceDictionary. Dans votre fichier MyResourceDictionary.xaml, placez l'attribut x: Class dans l'élément racine, comme ceci:

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

Ensuite, créez un code derrière le fichier appelé MyResourceDictionary.xaml.cs avec la déclaration suivante:

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

Et tu as fini. Vous pouvez mettre ce que vous voulez dans le code derrière: méthodes, propriétés et gestionnaires d'événements.

== Mise à jour pour les applications Windows 10 ==

Et juste au cas où vous joueriez avec UWP, il y a encore une chose à savoir:

<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>
ageek piégé
la source
7
En complément à la réponse d'ageektrapped: assurez-vous de mettre le nom complet de votre classe codebehind dans l'attribut x: Class. x:Class="MyCompany.MyProject.MySubFolder1.MyResourceDictionary"Sinon, si vous mettez simplement x: Class = "MyResourceDictionary", l'analyseur xaml ne trouvera pas votre classe.
viggity le
29
Assurez-vous de fournir un constructeur par défaut dans la classe partielle codebehind et assurez-vous qu'il appelle InitializeComponent (). (Dans mon cas, j'utilisais MEF pour exporter le dictionnaire de ressources.)
Scott Whitlock
4
Extrait de code mis à jour pour le commentaire avec vote positif. J'ai senti qu'il était nécessaire de compléter la réponse; une erreur courante. Je l'ai fait tout à l'heure :) Revenez si vous ne l'aimez pas. Merci d'avoir répondu.
Gishu
2
Notez que (au moins dans wp8.1) ce n'est plus valide et vous devrez créer un contrôle utilisateur personnalisé auquel votre resourcedictionary fait référence
Jared
9
Vous devrez également définir l'action de génération sur le fichier XAML du ResourceDictionary sur "Page", sinon l'appel InitializeComponent () ne sera pas compilé. (Les fichiers ResourceDictionary XAML sont généralement définis sur "Resource" par défaut.)
user1454265
9

Je ne suis pas d'accord avec "ageektrapped" ... utiliser la méthode d'une classe partielle n'est pas une bonne pratique. Quel serait alors le but de séparer le dictionnaire de la page?

À partir d'un code-behind, vous pouvez accéder à l'élément ax: Name en utilisant:

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

Vous pouvez faire cela dans la méthode OnApplyTemplate si vous voulez brancher des contrôles à quand votre charge les de contrôle sur mesure. OnApplyTemplate doit être remplacé pour ce faire. Ceci est une pratique courante et permet à votre style de rester déconnecté du contrôle. (Le style ne doit pas dépendre du contrôle, mais le contrôle doit dépendre du style).

Phobis
la source
7
Phobis Je pense que le but de la séparation du dictionnaire de la page concerne la réutilisabilité et la lisibilité du xaml de la page principale. La solution ci-dessus a fonctionné pour moi aussi.
cleftheris le
5

Gishu - bien que cela puisse sembler être une "pratique généralement à ne pas encourager" Voici une raison pour laquelle vous pourriez vouloir le faire:

Le comportement standard des zones de texte lorsqu'elles obtiennent le focus consiste à placer le curseur à la même position que lorsque le contrôle a perdu le focus. Si vous préférez dans toute votre application que lorsque l'utilisateur clique sur une zone de texte pour que tout le contenu de la zone de texte soit mis en surbrillance, l'ajout d'un simple gestionnaire dans le dictionnaire de ressources ferait l'affaire.

Toute autre raison pour laquelle vous souhaitez que le comportement d'interaction utilisateur par défaut soit différent du comportement prêt à l'emploi semble être de bons candidats pour un code derrière dans un dictionnaire de ressources.

Tout à fait d'accord que tout ce qui est spécifique à une fonctionnalité d'application ne doit pas être dans un code derrière un dictionnaire de ressources.

Pete Maher
la source
0

XAML sert à construire des graphiques d'objets ne contenant pas de code.
Un modèle de données est utilisé pour indiquer comment un objet utilisateur personnalisé doit être rendu à l'écran ... (par exemple, s'il s'agit d'un élément de listbox), le comportement ne fait pas partie du domaine d'expertise d'un modèle de données. Redessiner la solution ...

Gishu
la source
conclusion: Recommanderiez-vous d'utiliser un dic de ressources avec du code derrière ou non? Je ne l'ai jamais utilisé, j'en doute.
Shimmy Weitzhandler
1
Je ne le ferais pas - pour moi, cela ne me semble pas bien. Un dictionnaire doit renvoyer des valeurs pour des clés spécifiques. Dans le cas de l'OP, regrouper le code avec le modèle de données .. Je préférerais essayer une approche différente .. utiliser le modèle Command par exemple. J'ai besoin de plus de détails sur le problème de l'OP pour recommander une solution de diff.
Gishu
1
Complètement en désaccord. Avec MVVM, il existe un scénario dans lequel avoir du code derrière est extrêmement utile: le développement de propriétés attachées. Faites-le fonctionner avec le code derrière, puis portez-le vers une propriété attachée. C'est beaucoup plus rapide que de simplement développer la propriété attenante à partir de zéro, sauf si vous avez un cerveau de la taille de Manhattan.
Contango