65 votes

Comment définir le style de fenêtre WPF par défaut dans app.xaml ?

J'essaie de définir le style par défaut pour chaque fenêtre de mon application WPF Windows dans mon app.xaml. Pour l'instant, j'ai ceci dans app.xaml :

<Application.Resources>
    <ResourceDictionary>
        <Style x:Key="WindowStyle" TargetType="{x:Type Window}">
            <Setter Property="Background" Value="Blue" />
        </Style>
    </ResourceDictionary>
</Application.Resources>

Je peux faire en sorte que la fenêtre apparaisse avec ce style lors de l'exécution de l'application (mais pas dans VS Designer) en indiquant spécifiquement à la fenêtre d'utiliser ce style via.. :

Style="{DynamicResource WindowStyle}

Cela fonctionne, mais n'est pas idéal. Alors comment faire :

  1. Est-ce que toutes les fenêtres utilisent automatiquement le style (pour que je n'aie pas à le spécifier sur chaque fenêtre) ?
  2. Demander à VS designer de montrer le style ?

Merci !

49voto

Gishu Points 59012

Pour ajouter à ce que dit Ray :

Pour les Styles, vous devez soit fournir une Clé/ID, soit spécifier un Type de cible.

Si un FrameworkElement n'a pas de n'a pas de style explicitement spécifié, il toujours chercher une ressource Style, en utilisant son propre type comme clé
- Programmer WPF (Sells, Griffith)

Si vous fournissez un TargetType, toutes les instances de ce type se verront appliquer le style. Cependant, les types dérivés ne le feront pas... il semble. <Style TargetType="{x:Type Window}"> ne fonctionnera pas pour toutes vos dérivations/fenêtres personnalisées. <Style TargetType="{x:Type local:MyWindow}"> s'appliquera uniquement à MyWindow. Les options sont donc

  • Utilisez un style codé que vous spécifiez comme propriété Style de l'option chaque la fenêtre dans laquelle vous voulez appliquer le style. Le designer affichera la fenêtre stylisée.

.

    <Application.Resources>
        <Style x:Key="MyWindowStyle">
            <Setter Property="Control.Background" Value="PaleGreen"/>
            <Setter Property="Window.Title" Value="Styled Window"/>
        </Style>
    </Application.Resources> ...
    <Window x:Class="MyNS.MyWindow" Style="{StaticResource MyWindowStyleKey}">  ...
  • Ou vous pourriez dériver d'une classe BaseWindow personnalisée (qui a ses propres particularités ), où vous définissez la propriété Style pendant l'étape Ctor/Initialisation/Load une fois. Toutes les dérivations auront alors automatiquement le style appliqué. Mais le designer ne remarquera pas votre style. Vous devez exécuter votre application pour voir le style appliqué Je suppose que le concepteur ne fait qu'exécuter InitializeComponent (qui est un code généré automatiquement par le concepteur) et que XAML est appliqué mais pas le code personnalisé.

Je dirais donc que les styles explicitement spécifiés sont ceux qui donnent le moins de travail. Vous pouvez de toute façon modifier certains aspects du style de manière centralisée.

2 votes

La dernière ligne " <Window x:Class ... " va dans l'en-tête xaml def de la fenêtre et non dans le fichier App.resources.

0 votes

Vous pouvez "cascader" le style en utilisant la propriété BasedOn. BasedOn="{StaticResource {x:Type Window}}" Cependant, je n'ai pas réussi à faire accepter à Window les styles sans clé. Je suppose que c'est parce qu'il ne reconnaît pas les types dérivés, comme vous l'avez dit.

0 votes

Votre code est plein de bogues et n'arrive même pas à compiler et est effectivement inutile, par exemple en utilisant MyWindowStyleKey y MyWindowStyle . C'est l'une des nombreuses raisons pour lesquelles, près de 9 ans plus tard, elle n'a pas été acceptée.

24voto

Paul1307 Points 101

Je sais que c'est des années plus tard, mais puisque la question est toujours là...

  1. Créer un dictionnaire de ressources dans votre projet (clic droit sur le projet...)

    Je vais créer un nouveau dossier sous le projet appelé "Assets" et mettre "resourceDict.XAML" dedans.

  2. Ajoutez le code à resourceDict.XAML :

    <Style x:Key="WindowStyle" Target Type="Window" >
         <Setter Property="Background" Value="Blue" />
    </Style>
  3. Dans le fichier XAML de votre projet, ajoutez ce qui suit sous Window :

    <Window.Resources>
        <ResourceDictionary>
            <!-- Believe it or not the next line fixes a bug MS acknowledges -->
            <Style TargetType="{x:Type Rectangle}" />
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Assets/resourceDict.XAML" />
            </ResourceDictionary.MergedDictionaries>
        <ResourceDictionary>
    </Window.Resources>

    référez-vous au site web suivant : Problème de référencement d'un dictionnaire de ressources qui contient un dictionnaire fusionné "Il existe un bogue : si tous vos styles par défaut sont imbriqués dans des dictionnaires fusionnés de trois niveaux de profondeur (ou plus), le dictionnaire supérieur n'est pas signalé et la recherche l'ignore. La solution consiste à attribuer un style par défaut à quelque chose, n'importe quoi, dans le dictionnaire racine." Et cela semble régler les choses de manière fiable. Allez savoir...

  4. Et enfin, sous Window, peut-être après Title, mais avant le Window '>' final :

    Style="{DynamicResource windowStyle}"
  5. Et vous devrez ajouter le code des étapes 3 et 4 à chaque projet auquel vous voulez que le style s'applique.

  6. Si vous souhaitez utiliser un fond en dégradé plutôt qu'une couleur unie, ajoutez le code suivant au fichier resourceDict.XAML :

    <LinearGradientBrush x:Key="windowGradientBackground" StartPoint="0,0"
            EndPoint="0,1" >
    <GradientStop Color= "AliceBlue" Offset="0" />
    <GradientStop Color= "Blue" Offset=".75" />
    </LinearGradientBrush>
  7. Et modifiez votre Style Setter pour que la couleur d'arrière-plan soit la suivante :

    <Setter Property="Background" Value="{DynamicResource
            windowGradientBackground}" />

Les étapes 3 et 4 doivent être répétées dans chaque fichier XAML du projet comme décrit ci-dessus, mais vous obtenez des fenêtres uniformes dans toute la solution ! Et le même processus peut s'appliquer à tous les contrôles que vous souhaitez uniformiser, comme les boutons, par exemple.

Pour tous ceux qui viennent d'arriver, j'espère que cela vous aidera, car je suis sûr que les personnes qui ont posé la question à l'origine ont tout compris il y a des années.

Paul

0 votes

L'astuce consistant à ne pas intégrer les MergedDictionaries dans les MergedDictionaries a été la solution pour moi. Il suffit de déclarer tous les fichiers de thème directement dans le App.xaml. Merci donc !

1 votes

Modifier s'il vous plaît. Dans le fichier des ressources, le nom de la propriété est TargetType pas Target Type .

0 votes

Des années plus tard. J'aide toujours.

8voto

Ray Booysen Points 10606

Le concepteur ne fonctionne pas parce que vous spécifiez une DynamicResource. Veuillez le changer en StaticResource et tout ira bien.

Pour qu'il s'applique à toutes les fenêtres, vous devez supprimer le x:Key du style. En définissant le TargetType, vous définissez implicitement le x:Key à ce qui se trouve dans le TargetType. Cependant, dans mes tests, cela ne fonctionne pas, c'est pourquoi je me penche sur la question.

Si je fixe le TargetType à x:Type TextBlock, le concepteur fonctionne parfaitement. Il semble que ce soit la fenêtre qui présente un comportement différent.

1 votes

Oui, je viens de rencontrer le même problème. Gishu a dit plus haut qu'il semble que le style implicite pour Window ne s'applique pas à votre fenêtre, puisqu'il s'agit en fait d'une classe dérivée.

1voto

Arnie Points 11

Pour ceux qui sont à la recherche d'une solution au problème suivant : comment puis-je faire en sorte qu'un style personnalisé soit automatiquement appliqué à tous mes types dérivés de fenêtres ? Voici la solution que j'ai trouvée

NOTE : Je ne voulais vraiment pas dériver du type Window ou avoir à insérer XAML sur chaque fenêtre pour forcer une mise à jour du style, etc. pour des raisons spécifiques à mon projet (les consommateurs de mon produit utilisent ma bibliothèque de style générique réutilisable et créent leur propre mise en page/fenêtres, etc. motivé de trouver une solution qui fonctionne et que j'étais prêt à vivre avec les effets secondaires.

Il faut itérer à travers toutes les fenêtres instanciées et les forcer à utiliser le nouveau style personnalisé que vous avez défini pour le type de fenêtre. Cela fonctionne très bien pour les fenêtres qui sont déjà en place, mais lorsqu'une fenêtre ou une fenêtre enfant est instanciée, elle ne sait pas qu'elle doit utiliser le nouveau type personnalisé qui a été déclaré pour son type de base, le type vanilla Window. Le mieux que j'ai pu faire est donc d'utiliser la fonction LostKeyBoardFocus de la fenêtre principale lorsqu'elle perd le focus au profit d'une fenêtre enfant (c'est-à-dire lorsqu'une fenêtre enfant a été créée), puis d'invoquer la fonction FixupWindowDerivedTypes().

Si quelqu'un a une meilleure solution pour "détecter" quand un type dérivé de fenêtre est instancié et ainsi appeler la fonction FixupWindowDerivedTypes(), ce serait génial. La gestion du WM_WINDOWPOSCHANGING pourrait également s'avérer utile dans ce domaine.

Cette solution n'est donc pas élégante en soi, mais elle permet de faire le travail sans que je doive toucher au code ou au XAML de mon Windows.

   public static void FixupWindowDerivedTypes()
    {
        foreach (Window window in Application.Current.Windows)
        {
           //May look strange but kindly inform each of your window derived types to actually use the default style for the window type

                    window.SetResourceReference(FrameworkElement.StyleProperty, DefaultStyleKeyRetriever.GetDefaultStyleKey(window));
                }
            }
        }
    }

//Great little post here from Jafa to retrieve a protected property like DefaultStyleKey without using reflection.
http://themechanicalbride.blogspot.com/2008/11/protected-dependency-properties-are-not.html

//Helper class to retrieve a protected property so we can set it
internal class DefaultStyleKeyRetriever : Control
{
    /// <summary>
    /// This method retrieves the default style key of a control.
    /// </summary>
    /// <param name="control">The control to retrieve the default style key 
    /// from.</param>
    /// <returns>The default style key of the control.</returns>
    public static object GetDefaultStyleKey(Control control)
    {
        return control.GetValue(Control.DefaultStyleKeyProperty);
    }
}

0voto

Crossman Points 66

Envisager Gishu J'ai trouvé une autre solution de contournement. Mais cela pourrait être un peu bizarre. Si vous utilisez le modèle MVVM, vous pouvez supprimer le code-behind de votre fenêtre et le balisage x:Class dans le fichier XAML. Ainsi vous obtiendrez une instance de la fenêtre ou de votre fenêtre personnalisée mais pas une instance de la classe 'MainWindow' qui est dérivée de la classe 'Window' et marquée comme partielle. Je crée une fenêtre semblable à celle de VS, j'ai donc dû hériter de la classe window et étendre sa fonctionnalité. Dans ce cas, il sera possible de créer une nouvelle classe de fenêtre comme partielle, ce qui nous permettra de faire du code-behind sans héritage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X