È possibile impostare il codice dietro un dizionario di risorse in WPF per la gestione degli eventi?


147

È possibile impostare il codice dietro un dizionario di risorse in WPF. Ad esempio in un controllo utente per un pulsante lo dichiari in XAML. Il codice di gestione degli eventi per il clic sul pulsante viene eseguito nel file di codice dietro il controllo. Se dovessi creare un modello di dati con un pulsante, come posso scrivere il codice del gestore eventi per il relativo pulsante, fare clic nel dizionario delle risorse.


1
Il modo corretto per farlo è usare un comando, ti dà anche la possibilità di abilitare e disabilitare il pulsante, mentre puoi farlo nel modo in cui alcune risposte mi hanno suggerito che puzza di un hack.
Aran Mulholland,

Risposte:


209

Penso che quello che stai chiedendo sia che desideri un file code-behind per un ResourceDictionary. Puoi farlo totalmente! In effetti, lo fai allo stesso modo di una finestra:

Supponi di avere un ResourceDictionary chiamato MyResourceDictionary. Nel tuo file MyResourceDictionary.xaml, inserisci l'attributo x: Class nell'elemento root, in questo modo:

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

Quindi, crea un codice dietro il file chiamato MyResourceDictionary.xaml.cs con la seguente dichiarazione:

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

E hai finito. Puoi inserire ciò che desideri nel codice: metodi, proprietà e gestori di eventi.

== Aggiornamento per le app di Windows 10 ==

E nel caso in cui tu stia giocando con UWP c'è un'altra cosa da tenere presente:

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

7
Come addendum alla risposta di ageektrapped: assicurati di inserire il nome completo del codice dietro la classe nell'attributo x: Class. x:Class="MyCompany.MyProject.MySubFolder1.MyResourceDictionary"Altrimenti, se si inserisce semplicemente x: Class = "MyResourceDictionary", il parser xaml non troverà la propria classe.
vigore

29
Assicurati di fornire un costruttore predefinito nella classe parziale codebehind e assicurati che chiami InitializeComponent (). (Nel mio caso stavo usando MEF per esportare il dizionario delle risorse.)
Scott Whitlock,

4
Snippet di codice aggiornato per il commento votato. Ho sentito che era necessario completare la risposta; un errore comune. L'ho fatto proprio ora :) Ripristina se non ti piace. Grazie per la risposta.
Gishu,

2
Nota che (almeno in wp8.1) questo non è più valido e dovresti creare un controllo utente personalizzato a cui fa riferimento il tuo codice risorse
Jared

9
Dovrai anche impostare l'azione di compilazione sul file XAML di ResourceDictionary su "Pagina", altrimenti la chiamata InitializeComponent () non verrà compilata. (I file XAML ResourceDictionary sono in genere impostati su "Risorsa" per impostazione predefinita.)
user1454265

9

Non sono d'accordo con "ageektrapped" ... l'uso del metodo di una classe parziale non è una buona pratica. Quale sarebbe lo scopo di separare il Dizionario dalla pagina allora?

Da un code-behind, puoi accedere a ax: Name element usando:

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

È possibile effettuare ciò nel metodo OnApplyTemplate se si desidera collegarsi ai controlli quando viene caricato il controllo personalizzato. OnApplyTemplate deve essere ignorato per fare questo. Questa è una pratica comune e consente al tuo stile di rimanere disconnesso dal controllo. (Lo stile non dovrebbe dipendere dal controllo, ma il controllo dovrebbe dipendere dall'avere uno stile).


7
Fobia Penso che lo scopo di separare il Dizionario dalla pagina sia sulla riusabilità e leggibilità della Pagina principale xaml. La soluzione sopra ha funzionato anche per me.
Cleftheris,

5

Gishu - anche se questa potrebbe sembrare una "pratica generalmente non incoraggiata" Ecco una ragione per cui potresti voler farlo:

Il comportamento standard per le caselle di testo quando ottengono lo stato attivo è che il cursore venga posizionato nella stessa posizione in cui si trovava quando il controllo perse lo stato attivo. Se preferisci in tutta la tua applicazione che quando l'utente accede a qualsiasi casella di testo che è stato evidenziato l'intero contenuto della casella di testo, l'aggiunta di un semplice gestore nel dizionario delle risorse farebbe il trucco.

Qualsiasi altro motivo per cui si desidera che il comportamento di interazione dell'utente predefinito sia diverso dal comportamento predefinito sembra un buon candidato per un codice in un dizionario delle risorse.

Concordo pienamente sul fatto che tutto ciò che è specifico della funzionalità dell'applicazione non dovrebbe trovarsi in un codice dietro un dizionario delle risorse.


0

XAML serve per costruire grafici di oggetti che non contengono codice.
Un modello di dati viene utilizzato per indicare come un oggetto utente personalizzato deve essere visualizzato sullo schermo ... (ad esempio se si tratta di un elemento della casella di riepilogo) il comportamento non fa parte dell'area di competenza di un modello di dati. Ridisegna la soluzione ...


conclusione: consiglieresti di usare la risorsa dic con il codice dietro o no ?? Non l'ho mai usato, ne dubito.
Shimmy Weitzhandler,

1
Non lo farei - per me non sembra giusto. Un dizionario dovrebbe restituire valori per chiavi specifiche. Nel caso del PO, raggruppando il codice con il modello di dati .. Preferirei provare un approccio diverso .. usare il modello di comando per esempio. Ho bisogno di maggiori dettagli sul problema del PO per raccomandare una soluzione differenziale.
Gishu,

1
Completamente in disaccordo. Con MVVM, esiste uno scenario in cui il codice dietro è estremamente utile: lo sviluppo di proprietà associate. Fallo funzionare con il codice dietro, quindi portalo su una proprietà collegata. Questo è molto più veloce del semplice sviluppo da zero della proprietà collegata, a meno che tu non abbia un cervello delle dimensioni di Manhattan.
Contango,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.