web-dev-qa-db-fra.com

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 Windows WPF dans mon app.xaml. Jusqu'à présent, 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 apparaître la fenêtre avec ce style lors de l'exécution de l'application (mais pas VS designer) en disant spécifiquement à la fenêtre d'utiliser ce style via:

Style="{DynamicResource WindowStyle}

Cela fonctionne, mais n'est pas idéal. Alors, comment puis-je:

  1. Est-ce que toutes les fenêtres utilisent automatiquement le style (donc je n'ai pas à le spécifier sur chaque fenêtre)?
  2. Le concepteur VS a-t-il montré le style?

Merci!

63
NoizWaves

Pour ajouter à ce que dit Ray:

Pour les styles, vous devez soit fournir une clé/ID, soit spécifier un TargetType.

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

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

  • Utilisez un style à clé que vous spécifiez comme propriété Style de chaque fenêtre à laquelle vous souhaitez appliquer le style. Le concepteur montrera 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 pouvez dériver d'une classe BaseWindow personnalisée (qui a ses propres bizarreries ), où vous définissez la propriété Style lors de l'étape Ctor/Initialization/Load une fois. Toutes les dérivations auraient alors automatiquement le style appliqué. Mais le concepteur ne tiendra pas compte de votre style Vous devez exécuter votre application pour voir le style appliqué. Je suppose que le concepteur vient exécute InitializeComponent (qui est du code généré automatiquement/par le concepteur) afin que XAML soit appliqué mais pas de code personnalisé derrière.

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

46
Gishu

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

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

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

  2. Ajoutez le code à resourceDict.XAML:

    <Style x:Key="WindowStyle" Target Type="Window" >
         <Setter Property="Background" Value="Blue" />
    </Style>
    
  3. Dans votre fichier Project XAML, 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>
    

    ref le site web suivant: Problème de référencement d'un dictionnaire de ressources qui contient un dictionnaire fusionné "Il y a un bug: si tous vos styles par défaut sont imbriqués dans des dictionnaires fusionnés à trois niveaux de profondeur (ou plus profond), le meilleur dictionnaire ne ne sont pas signalés, la recherche l'ignore. La solution consiste à mettre un style par défaut dans quelque chose, n'importe quoi, dans le dictionnaire racine. " Et cela semble arranger les choses de manière fiable. Allez comprendre...

  4. Et enfin, sous Window, peut-être après le titre, mais avant la dernière fenêtre '>':

    Style="{DynamicResource windowStyle}"
    
  5. Et vous devrez ajouter le code des étapes 3 et 4 à chaque projet auquel vous souhaitez appliquer le style.

  6. Si vous souhaitez utiliser un arrière-plan dégradé plutôt qu'une couleur unie, ajoutez le code suivant au 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 lue:

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

Les étapes 3 et 4 doivent être répétées dans chaque fichier project.XAML comme décrit ci-dessus, mais bon, vous obtenez des fenêtres uniformes dans la solution! Et le même processus pourrait s'appliquer à tous les contrôles que vous souhaitez avoir un aspect uniforme, aux boutons, peu importe.

Pour tous ceux qui arrivent tard, espérons que cela aide, car je suis sûr que les affiches originales ont tout compris il y a des années.

Paul

20
Paul1307

Le concepteur ne fonctionne pas car vous spécifiez un DynamicResource. Veuillez changer cela en StaticResource et tout ira bien.

Pour appliquer à toutes les fenêtres, vous devez supprimer la clé x: du style. La définition du TargetType définit implicitement la clé x: à tout ce qui se trouve dans TargetType. Cependant, dans mes tests, cela ne fonctionne pas, donc je m'y intéresse.

Si je définit le TargetType sur x: Type TextBlock, le concepteur fonctionne parfaitement, il semble que ce soit la fenêtre qui affiche un comportement différent.

8
Ray Booysen

Vous pouvez ajouter ce code à votre fichier App.xaml.cs:

        FrameworkElement.StyleProperty.OverrideMetadata(typeof(Window), new FrameworkPropertyMetadata
        {
            DefaultValue = Application.Current.FindResource(typeof(Window))
        });

Après cela, le style appliqué au type Window s'appliquera également à tous les types dérivés de Window

4
STiLeTT

J'ai étudié celui-ci depuis quelques jours et l'ai fait fonctionner via le constructeur de ma classe de fenêtre personnalisée:

public class KWindow : Window
{
        public KWindow()
        {
            this.SetResourceReference(StyleProperty, typeof(KWindow));
        }

        static KWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(KWindow), new FrameworkPropertyMetadata(typeof(KWindow)));

        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            // gets called finally
        }
}

J'espère que cela aide quelqu'un

3
KroaX

Pour ceux qui ont du mal à trouver une solution au problème: comment puis-je appliquer automatiquement un style personnalisé à tous mes types dérivés de Windows? Voici la solution que j'ai trouvée

REMARQUE: je ne voulais vraiment pas dériver du type Window ou devoir insérer du XAML sur chaque fenêtre pour forcer une mise à jour de style, etc. pour des raisons spécifiques à mon projet (les consommateurs de mon produit nous utilisent ma bibliothèque générique de styles réutilisables et créent la leur) disposition/fenêtres, etc.) donc j'étais vraiment motivé pour trouver une solution qui fonctionnait et que j'étais prêt à vivre avec tous les effets secondaires

Vous devez parcourir toutes les fenêtres instanciées et les forcer simplement à 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 quand une fenêtre ou une fenêtre enfant est instanciée, elle ne saura pas utiliser le nouveau type/personnalisé qui a été déclaré pour son type de base; le type Vanilla Window. Donc, le mieux que j'ai pu trouver était d'utiliser le LostKeyBoardFocus sur le MainWindow quand il perd le focus sur un ChildWindow (IOW lorsqu'une fenêtre enfant a été créée), puis invoquer ce FixupWindowDerivedTypes ().

Si quelqu'un a une meilleure solution pour "détecter" quand tout type de type dérivé de fenêtre est instancié et donc appeler FixupWindowDerivedTypes (), ce serait formidable. Il peut y avoir quelque chose d'utile avec la gestion de WM_WINDOWPOSCHANGING dans cette zone également.

Cette solution n'est donc pas élégante à proprement parler, mais fait le travail sans que je doive toucher à aucun code ou XAML lié à mes fenêtres.

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

Compte tenu de la réponse de Gish, j'ai trouvé une autre solution de contournement. Mais ça pourrait être un peu bizarre. Si vous utilisez un modèle MVVM, vous pouvez supprimer le code-behind de votre fenêtre et le balisage x: Class dans le fichier XAML. Vous obtiendrez donc une instance de window ou votre fenêtre personnalisée, mais pas une instance de la classe 'MainWindow' dérivée de la classe 'Window' et marquée comme partielle. Je crée une fenêtre de type VS, j'ai donc dû hériter de la classe de fenêtre et étendre ses fonctionnalités. Dans ce cas, il sera possible de faire une nouvelle classe de fenêtre comme partielle qui nous permettrait de faire du code-back sans héritage.

0
Crossman