2010-03-04 7 views
10

Je vous écris une application WPF sur Windows XP et j'ai le thème de substitution par défaut avec le thème vista comme ceci:Override surchargée WPF Thème

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

Et cela fonctionne très bien la plupart du temps. Lorsque j'utilise le contrôle comme un bouton:

<Button /> 

Le style a l'air bien, mais si j'utiliser un bouton avec un style différent comme celui-ci:

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

Le style remplacera le style de thème spécifié avec le style standard WinXP au lieu de construire sur le dessus. Ceci est extrêmement limitant pour moi. Y a-t-il un moyen d'éviter ce problème?

Répondre

10

Pourquoi cela se produit

La valeur par défaut = BasedOn pour un style est généré en utilisant uniquement dictionnaire des ressources du thème actuel. La technique que vous utilisez pour remplacer un thème ne modifie pas réellement le dictionnaire de thèmes utilisé: Il ajoute simplement les ressources du dictionnaire de ressources du thème au dictionnaire de ressources de l'application. Étant donné que le thème actuel est inchangé, le paramètre BasedOn par défaut est également inchangé.

Comment résoudre

Option 1: remplacer localement le thème par l'interception des appels à Uxtheme.dll GetCurrentThemeName au niveau Win32!. C'est assez complexe mais fonctionne pour tous vos styles sans modification de votre XAML.

Option 2: Définir BasedOn à l'aide d'une extension Markup personnalisée. Il ressemblerait à ceci:

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

Votre MarkupExtension personnalisé chargerait le dictionnaire thème Aero de la première utilisation et le stocker dans un champ statique. Son constructeur prendrait un Type, et son ProvideValue chercherait le type dans le dictionnaire pour trouver le style.

Option 3: Définissez BasedOn sur un style nommé intermédiaire. Il ressemblerait à ceci:

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

maintenant dans votre dictionnaire de niveau inférieur, vous pouvez dire:

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

Option 4: Set BasedOn en utilisant une propriété statique et x: extension de balisage statique

+1

Merci, votre réponse a été très utile. Cette zone semble manquer de WPF. Quelle option utilisez-vous habituellement pour résoudre ce problème? –

+0

Option 2 est très cool, dans une certaine mesure, il contourne même le problème de ne pas être à BasedOn DynamicResources. –

+0

Je résous normalement le problème en expliquant au client qu'il est préférable de rester avec le thème actuel du système d'exploitation parce que les fenêtres sembleront "normales" à l'utilisateur final. Cependant, j'ai utilisé l'option 2 et l'option 3 dans les situations où j'ai besoin d'une section de l'interface utilisateur à redéfinir, mais une section interne de l'interface utilisateur (comme un popup) pour * ne * pas être restylée. –