2010-03-04 7 views
10

Estoy escribiendo una aplicación de WPF en WinXP y he anulado el tema por defecto con el tema Vista de esta manera:Anulación alteradas temporalmente WPF temático

protected override void OnStartup(StartupEventArgs e) 
{ 
    base.OnStartup(e); 

    var themerd = new ResourceDictionary(); 
    themerd.Source = new Uri(@"PresentationFramework.Aero;V3.0.0.0;31bf3856ad364e35;component\themes/aero.normalcolor.xaml", UriKind.Relative); 

    Resources.MergedDictionaries.Add(themerd); 
} 

y funciona bien en su mayoría. Cuando utilizo el control como un botón:

<Button /> 

El estilo se ve muy bien, pero si uso un botón con un estilo diferente de esta manera:

<Button> 
    <Button.Style> 
    <Style TargetType="Button"> 
     <Setter Property="Width" Value="80" /> 
    </Style> 
    </Button.Style> 
</Button> 

El estilo anulará el estilo del tema especificado con el estilo estándar de WinXP en lugar de construir sobre él. Esto es extremadamente limitante para mí. ¿Hay alguna forma de evitar este problema?

Respuesta

10

¿Por qué está sucediendo esto

El valor por defecto = BasedOn para un estilo se genera utilizando únicamente diccionario de recursos del tema actual. La técnica que muestra para anular un tema no cambia el diccionario de tema en uso: simplemente agrega los recursos del diccionario de recursos del tema al diccionario de recursos de la aplicación. Dado que el tema actual no se modifica, el valor predeterminado de BasedOn tampoco se modifica.

Cómo resolverlo

Opción 1: Localmente anular el tema mediante la interceptación de llamadas a UXTHEME.DLL GetCurrentThemeName a nivel Win32!. Esto es bastante complejo, pero funciona para todos sus estilos sin cambios en su XAML.

Opción 2: Establecer en base al uso de una extensión de marca personalizada. Se vería así:

<Style TargetType="Button" BasedOn="{DefaultAeroStyle Button}"> ... 

Su MarkupExtension encargo cargaría el diccionario tema Aero en el primer uso y almacenarla en un campo estático. Su constructor tomaría un Type, y su ProvideValue buscaría el tipo en el diccionario para encontrar el estilo.

Opción 3: Establecer Basado en un estilo intermedio con nombre. Se vería así:

<Application ...> 
    <Application.Resources> 
    <ResourceDictionary> 
     <ResourceDictionary.MergedDictionaries> 
     <ResourceDictionary Source="... theme path ..." /> 
     </ResourceDictionary.MergedDictionaries> 

     <Style x:Key="ThemeButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" /> 
     <Style x:Key="ThemeListBoxStyle" TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}" /> 
     ... 
    </ResourceDictionary> 
    </Application.Resources> 
</Application> 

Ahora en su diccionario de nivel más bajo que se puede decir:

<Style TargetType="Button" BasedOn="{StaticResource ThemeButtonStyle}" /> 

Opción 4: Conjunto BasedOn utilizando una propiedad estática y la x: extensión de marcado estático

+1

Gracias, tu respuesta fue realmente útil. Esta área parece faltar en WPF. ¿Qué opción usas normalmente para resolver este problema? –

+0

La opción 2 es muy buena, hasta cierto punto incluso soluciona el problema de no estar en BasedOn DynamicResources. –

+0

Normalmente resuelvo el problema explicando al cliente que es mejor seguir con el tema actual del sistema operativo porque las ventanas se verán "normales" para el usuario final. Sin embargo, he utilizado tanto la Opción 2 como la Opción 3 en situaciones en las que necesito una sección de la IU para rediseñar, pero una sección interna de la IU (como una ventana emergente) para * no * volver a ser rediseñada. –