2009-04-07 8 views
5

Estoy alojando un UserControl de WPF en un contenedor WinForms. Ahora, quiero ser capaz de tema/skin el UserControl. Para hacer esto, tengo varios diccionarios de recursos que definen las "máscaras". Cuando se inicia mi aplicación, creo una "nueva aplicación System.Windows.All()" para que Application.Current exista. Para cambiar el tema, se elimina la máscara anterior y se fusiona una nueva máscara en el diccionario de recursos de nivel de aplicación en tiempo de ejecución. Sin embargo, esto no cambia ninguno de los recursos referenciados dinámicamente en el UserControl. Intenté esto en una aplicación WPF recta y funcionó bien. ¿Me estoy perdiendo algo, o no es posible hacer esto? Por cierto, si agrego un aspecto en los recursos de la aplicación antes de que se inicialice el UserControl, funcionará pero no puedo cambiar el aspecto después de eso.Los recursos dinámicos de nivel de aplicación no son dinámicos cuando se alojan en ElementHost

Para Repo esto de la manera más básica:

crear una nueva aplicación Windows Forms. Agregue un UserControl de WPF a la aplicación. Esto es bastante simple:

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

Cree dos ResourceDictionaries, White.xaml y Black.xaml (o lo que sea) que tienen un SolidColorBrush con el ButtonBG clave con el color correspondiente. En Form1.cs, agregue dos botones y ElementHost. Establezca el elemento secundario de ElementHost en una instancia del UserControl que acabamos de crear. De cable hasta los botones a eventos que intercambian la piel:

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))); 
} 

En Program.cs, asegurar que Application.Current existe y configurar la máscara inicial:

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

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

    ... 
} 

Ahora, cuando se hace clic en el botón blanco Esperaría que el botón en UserControl se ponga blanco y cuando se haga clic en el botón Negro, esperaría que el botón se ponga negro. Esto no sucede, sin embargo.

¿Alguien sabe por qué? ¿Hay una solución?

Editar: Idea: Tal vez, si hay una manera de forzar la reevaluación de DynamicResources cuando cambia el tema, eso funcionaría.

Gracias, Dusty

Respuesta

6

creo que esto puede ser un problema por alto en el marco de WPF.

Por lo que puedo decir a través de Reflector, parece que cuando el diccionario de recursos Application se cambia catastróficamente (un cambio que probablemente tendrá efectos de amplio alcance como agregar, quitar o reemplazar un aspecto), hay un código que se repite todos los Windows en la aplicación y los obliga a volver a evaluar su DynamicResources. Sin embargo, otros elementos que consideraría de nivel superior en WPF como ElementHost s no reciben el mismo tratamiento. Esto conduce al comportamiento que estoy experimentando.

Mi solución a este problema es pasar manualmente todos mis ElementHost s de forma individual y agregar, quitar o reemplazar el archivo ResourceDictionary de la piel. No es perfecto, pero hace el trabajo bien.

+0

hello dustyburwell, ¿podría proporcionar un código de muestra, por favor? – user1912383

-1

Otra solución alternativa sería crear una ventana ficticia y especificar el contenido del elementohost como contenido. Si observa la Aplicación y comprueba cómo maneja los cambios de los recursos, verá que solo notifica las ventanas.

Lo único que debe recordar es no mostrar nunca la ventana (-> excepción) y cerrarla cuando deseche el elementohost para que la aplicación se cierre correctamente.