2009-04-07 13 views
5

Sto ospitando un UserControl WPF in un contenitore WinForms. Ora, voglio essere in grado di applicare a tema/skin l'UserControl. Per fare questo, ho diversi dizionari di risorse che definiscono le "skin". Quando viene avviata la mia app, creo un "nuovo System.Windows.Application()" in modo che Application.Current esista. Per modificare il tema, il vecchio skin viene rimosso e un nuovo skin viene unito al dizionario delle risorse a livello di applicazione in fase di runtime. Tuttavia, ciò non modifica nessuna delle risorse referenziate dinamicamente in UserControl. Ho provato questo in un'applicazione WPF semplice e ha funzionato bene. Mi manca qualcosa o non è possibile farlo affatto? A proposito, se aggiungo uno skin alle risorse dell'applicazione prima che l'UserControl sia inizializzato funzionerà, ma dopo non posso cambiare la skin.Le risorse a livello di applicazione dinamica non sono dinamiche quando sono ospitate in ElementHost

Per Repo questo nel modo più semplice:

Creare una nuova applicazione WinForms. Aggiungi un UserControl WPF all'app. Questo è abbastanza semplice:

<UserControl ...> 
    <Grid> 
     <Button 
     Background="{DynamicResource ButtonBG}"/> 
    </Grid> 
</UserControl> 

Creare due ResourceDictionaries, White.xaml e Black.xaml (o qualsiasi altra cosa) che hanno un SolidColorBrush con la ButtonBG chiave con colore corrispondente. In Form1.cs, aggiungi due pulsanti e un ElementHost. Imposta il figlio di ElementHost su un'istanza di UserControl appena creata. Filo i pulsanti agli eventi che scambiano la pelle:

private void White_Click(object sender, EventArgs e) 
{ 
    Application.Current.Resources.MergedDictionaries[0] = 
     (ResourceDictionary)Application.LoadComponent(
     new Uri(@"\WpfThemes;component\White.xaml", UriKind.Relative))); 
} 

private void Black_Click(object sender, EventArgs e) 
{ 
    Application.Current.Resources.MergedDictionaries[0] = 
     (ResourceDictionary)Application.LoadComponent(
     new Uri(@"\WpfThemes;component\Black.xaml", UriKind.Relative))); 
} 

Nel Program.cs, garantire che Application.Current esiste e impostare la pelle iniziale:

[STAThread] 
static void Main() 
{ 
    new System.Windows.Application(); 

    Application.Current.Resources.MergedDictionaries[0] = 
     (ResourceDictionary)Application.LoadComponent(
     new Uri(@"\WpfThemes;component\White.xaml", UriKind.Relative))); 

    ... 
} 

Ora, quando il pulsante bianco si fa clic Mi aspetto che il pulsante in UserControl diventi bianco e quando si fa clic sul pulsante nero, mi aspetto che il pulsante diventi nero. Questo non succede, comunque.

Qualcuno sa perché? C'è una soluzione?

Modifica: Idea: Forse, se c'è un modo per forzare la rivalutazione di DynamicResources quando il tema cambia, funzionerebbe.

Grazie, Dusty

risposta

6

Penso che questo possa essere un problema trascurato nel quadro WPF.

Da quello che posso dire tramite Reflector, sembra che quando il dizionario delle risorse Application viene modificato in modo catastrofico (una modifica che probabilmente avrà effetti di ampia portata come l'aggiunta, la rimozione o la sostituzione di una skin), c'è il codice che scorre su tutto il Windows nell'applicazione e costringe a rivalutare il proprio DynamicResources. Tuttavia, altri elementi che considererei di livello superiore in WPF come ElementHost s non ottengono lo stesso trattamento. Questo porta al comportamento che sto vivendo.

La mia soluzione a questo problema è quella di passare manualmente a tutte le mie ElementHost s singolarmente e aggiungere, rimuovere o sostituire il file di skin ResourceDictionary. Non è perfetto, ma ha fatto il lavoro.

+0

ciao dustyburwell, potresti fornire un codice di esempio, per favore? – user1912383

-1

Un'altra soluzione alternativa sarebbe quella di creare una finestra fittizia e specificare il contenuto dell'elementohost come contenuto. Se si esamina l'applicazione e si controlla come gestisce le modifiche dei resourcedictionaries, si vede che notifica solo le finestre ..

L'unica cosa che dovresti ricordare è non mostrare mai la finestra (-> eccezione) e chiuderla al momento dello smaltimento dell'elementohost, in modo che l'applicazione possa spegnersi correttamente.

Problemi correlati