2010-12-12 48 views
9

Ainsi, le désir est simple, changez l'arrière-plan d'un bouton en LightGreen, Green quand le curseur de la souris passe dessus et DarkGreen quand il est pressé. Le XAML suivant est ma première tentative:Overrider l'arrière-plan du bouton dans WPF on Aero

<Window x:Class="ButtonMouseOver.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
    <Button Background="LightGreen"> 
     Hello 
     <Button.Style> 
     <Style TargetType="Button"> 
      <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="true"> 
       <Setter Property = "Background" Value="Green"/> 
      </Trigger> 
      <Trigger Property="IsPressed" Value="true"> 
       <Setter Property = "Foreground" Value="DarkGreen"/> 
      </Trigger> 
      </Style.Triggers> 
     </Style> 
     </Button.Style> 
    </Button> 
    </Grid> 
</Window> 

Mais, hélas, cela ne fonctionne pas. Nous ne sommes qu'à 1/3 du but. Oui, le bouton devient vert clair, mais dès que vous le survolez ou appuyez dessus, vous obtenez le chrome Aero standard pour les états respectifs des boutons. Ne voulant pas abandonner, je tente la débauche suivante:

... 
    <Button xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" 
      Background="LightGreen"> 
     Hello 
     <Button.Template> 
     <ControlTemplate TargetType="{x:Type Button}"> 
      <Microsoft_Windows_Themes:ButtonChrome SnapsToDevicePixels="true" 
      x:Name="Chrome" Background="{TemplateBinding Background}" 
      BorderBrush="{TemplateBinding BorderBrush}" RenderDefaulted="{TemplateBinding IsDefaulted}" 
      RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" 
      > 
      <ContentPresenter Margin="{TemplateBinding Padding}" 
              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
              RecognizesAccessKey="True" 
              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> 
      </Microsoft_Windows_Themes:ButtonChrome> 
     </ControlTemplate> 
     </Button.Template> 
     <Button.Style> 
     <Style TargetType="Button"> 
      <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="true"> 
       <Setter Property = "Background" Value="Green"/> 
      </Trigger> 
      <Trigger Property="IsPressed" Value="true"> 
       <Setter Property = "Foreground" Value="DarkGreen"/> 
      </Trigger> 
      </Style.Triggers> 
     </Style> 
     </Button.Style> 
    </Button> 
... 

Maintenant, nous avons l'ensemble friggine modèle de contrôle jetés là-dedans soulevé de Aero.NormalColor.xaml. Hélas, cela ne change rien. Je vais ensuite supprimer deux attributs (RenderPressed et RenderMouseOver) de l'élément Microsoft_Windows_Themes:ButtonChrome. Pourtant, il n'y a pas de changement. Je puis retirer le réglage de l'attribut Background du bouton, laissant juste la déclaration d'espace de noms pour l'assemblage PresentationFramework.Aero:

... 
<Button xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"> 
    Hello 
... 

Enfin, nous avons des progrès. Nous sommes passés de 1/3 des exigences aux 2/3, avec IsMouseOver et IsPressed fonctionnant, mais pas d'arrière-plan vert clair pendant l'état normal du bouton (de ne pas avoir été survolé ou pressé), puisque j'ai supprimé la propriété Background du bouton, pour que les deux autres états s'appliquent et soient visibles. Maintenant, après cette XAML ne nous maniaques obtenir l'arrière-plan VertClair pour l'état de bouton normal, je modifie le style de jeter la couleur de fond là-dedans aussi:

<Button xmlns... 
    <ControlTemplate... 
    ... 
    </ControlTemplate> 
    <Button.Style> 
     <Style TargetType="Button"> 
     <!-- ##### Normal state button background added ##### --> 
     <Setter Property="Background" Value="LightGreen" /> 
     <!-- ################################################ --> 
     <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="true"> 
      <Setter Property = "Background" Value="Green"/> 
      </Trigger> 
      <Trigger Property="IsPressed" Value="true"> 
      <Setter Property = "Background" Value="DarkGreen"/> 
      </Trigger> 
     </Style.Triggers> 
     </Style> 
    </Button.Style> 
    </Button> 

Enfin, il fonctionne comme prévu. Est-ce que je suis fou, ou sont-ce (et plus) les cerceaux que vous devez traverser avec un thème Aero pour changer la couleur de fond d'un bouton dans certains de ses différents états (normal, survolé, pressé)? Peut-être, la vie ne serait pas si mauvaise si je n'avais pas besoin d'inclure tout le ButtonTemplate dang là juste pour enlever les deux attributs (RenderMouseOver et RenderPressed) de lui.

Merci pour toute aide - je suis à la fin.

Mise à jour: Mais attendez, il n'y a plus à cela. Au lieu d'enlever les RenderMouseOver et RenderPressed attributs du modèle de contrôle, en les changeant simplement de:

<Microsoft_Windows_Themes:ButtonChrome SnapsToDevicePixels="true" ... 
    RenderMouseOver="{TemplateBinding IsMouseOver}" 
    RenderPressed="{TemplateBinding IsPressed}" ... 

à:

<Microsoft_Windows_Themes:ButtonChrome SnapsToDevicePixels="true" ... 
    RenderMouseOver="{Binding IsMouseOver}" 
    RenderPressed="{Binding IsPressed}" ... 

..., résout également le problème (d'ignorer le style du bouton déclenche) . Je pense que la racine du problème est que les liaisons de modèles sont appliquées au moment de la compilation (pour des raisons de performances), tandis que les liaisons normales sont appliquées au moment de l'exécution. Pour cette raison, les liaisons des déclencheurs de style à partir des boutons individuels ne sont pas utilisées si les attributs utilisent des liaisons de modèle (c'est-à-dire que IsMouseOver et IsPressed du modèle d'origine sont utilisés à la place).

Après avoir dit tout ce qui précède, voici l'exemple canonique pour changer l'arrière-plan d'un bouton Aero tout en conservant son modèle de contrôle d'origine:

<Window x:Class="ButtonMouseOver.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
    <Button> 
     Hello 
     <Button.Template> 
     <ControlTemplate TargetType="{x:Type Button}"> 
      <Microsoft_Windows_Themes:ButtonChrome SnapsToDevicePixels="true" 
      x:Name="Chrome" Background="{TemplateBinding Background}" 
      BorderBrush="{TemplateBinding BorderBrush}" RenderDefaulted="{TemplateBinding IsDefaulted}" 
      RenderMouseOver="{Binding IsMouseOver}" RenderPressed="{Binding IsPressed}" 
      > 
      <ContentPresenter Margin="{TemplateBinding Padding}" 
              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
              RecognizesAccessKey="True" 
              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> 
      </Microsoft_Windows_Themes:ButtonChrome> 
     </ControlTemplate> 
     </Button.Template> 
     <Button.Style> 
     <Style TargetType="Button"> 
      <Setter Property="Background" Value="LightGreen"/> 
      <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="true"> 
       <Setter Property = "Background" Value="Green"/> 
      </Trigger> 
      <Trigger Property="IsPressed" Value="true"> 
       <Setter Property = "Foreground" Value="DarkGreen"/> 
      </Trigger> 
      </Style.Triggers> 
     </Style> 
     </Button.Style> 
    </Button> 
    </Grid> 
</Window> 

Ceci est bien sûr en supposant qu'un seul bouton est appelé ainsi, sinon, le modèle et le style peuvent être déplacés dans une section de ressources quelque part. De plus, il n'y a pas de déclencheur pour l'état par défaut d'un bouton, mais il est facilement ajouté à l'exemple ci-dessus (n'oubliez pas de changer l'attribut RenderDefaulted dans le modèle de contrôle pour utiliser Binding au lieu de TemplateBinding).

Si quelqu'un a des suggestions sur la façon de override le TemplateBinding avec liaison seulement pour les deux attributs du modèle de contrôle qui ont besoin de changer, sans répéter toute la définition de chrome du gros XAML aéro, je suis toutes les oreilles.

Répondre

2

Le modèle par défaut pour Button utilise un ButtonChrome qui exécute son propre dessin. Si vous voulez vous débarrasser complètement de l'apparence par défaut, vous devez définir votre propre modèle, sans le ButtonChrome. Je sais que cela semble fastidieux, mais il suffit de le faire une fois: vous pouvez mettre votre style personnalisé dans un dictionnaire de ressources, et vous y référer simplement avec StaticResource. Notez que vous pouvez également appliquer le style à tous les boutons de votre application en utilisant {x:Type Button} comme clé de style (attribut x:Key)

+0

Le problème est que je veux juste changer l'arrière-plan d'un bouton. Le chrome Aero gère cela correctement en utilisant l'attribut bouton d'arrière-plan pour l'état normal du bouton. Mais, cette gestion est défectueuse, car l'arrière-plan change dès le passage de la souris et lorsque le bouton est enfoncé. Il semble qu'il n'y ait pas de moyen facile de changer l'arrière-plan du bouton dans ces deux états. Cela va à l'encontre de l'objectif d'avoir un attribut Background dans Button (et peut-être d'autres améliorations visuelles). –

+0

La propriété Background est commune à tous les contrôles, donc elle sera présente de toute façon, mais rien ne garantit que le template le prendra en compte. Je peux reproduire votre problème avec le thème Aero, et un problème similaire avec le thème Luna. Il semble que ButtonChrome ne prenne pas en compte l'arrière-plan pour certains états ... De toute façon, je ne pense pas que le bouton chrome standard soit conçu pour que ses couleurs soient personnalisées. Si vous voulez faire cela, n'utilisez pas le chrome ... Il est assez facile de créer votre propre template de bouton sans cela. –

+0

De MSDN (propriété Control.Background): La propriété Background s'applique uniquement à l'état de repos d'un contrôle. Le style par défaut du contrôle spécifie son apparence lorsque l'état du contrôle change. Par exemple, si vous définissez la propriété Background sur un bouton, le bouton n'a cette valeur que lorsqu'il n'est pas enfoncé ou désactivé. Si vous souhaitez créer un contrôle ayant une personnalisation plus avancée de l'arrière-plan, vous devez définir le style du contrôle. –