2013-03-26 8 views
1

Nous souhaitons styliser un bouton wpf afin que le contenu défini dans le bouton s'affiche deux fois. La raison en est que nous voulons obtenir un effet d'ombre portée du contenu du bouton. Sur la pensée était d'avoir deux ContentControls dans le style de bouton comme ci-dessous:Afficher deux fois le même contenu dans le bouton WPF

<ContentControl x:Name="ContentControl" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> 
<ContentControl Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Foreground="White" Margin="0,1,0,0" /> 

Ainsi, un ContentControl est pour afficher le contenu réel et un ContentControl est d'afficher le même contenu avec un peu de marge pour qu'il donne l'effet d'être l'ombre portée. Le problème est qu'il n'affiche pas de contenu dans les deux contrôles de contenu. Un seul d'entre eux montre du contenu. Comment puis-je afficher le contenu avec succès dans les deux contrôles de contenu?

De plus, l'effet dropshadow n'est pas une option puisque le contenu du bouton devient flou.

Merci pour votre aide!

+0

Le deuxième ContentControl n'a pas une fixation ContentTemplate, et vous devez toujours lier aussi le ContentTemplateSelector, croyez-moi, cela vous fera économiser beaucoup de chasse aux bugs ennuyeux. En outre, vous devriez lire sur ContentPresenter et son utilisation dans ContentControls. – dowhilefor

+0

Merci pour la réponse. Je sais qu'il existe des différences dans l'utilisation de ContentPresenter et de ContentControl dans les modèles. La raison pour laquelle j'utilise contentControl ici est de pouvoir définir la propriété Foreground de contentControl. De cette façon, je peux contrôler le premier plan en fonction de VisualState (bouton pressé, etc.). Le ContentPresenter n'a pas de propriété de premier plan. Le ContentTemplate ne fait aucune différence et l'utilisation de 2 ContentPresenters n'aide pas non plus. – exkoria

Répondre

1

boutons avec des contenus Nested:

<Style x:Key="ShadowButton" 
     TargetType="{x:Type Button}"> 
    <Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="{x:Type Button}"> 
     <Grid> 
      <Rectangle Width="{Binding ActualWidth, 
             ElementName=presenter}" 
         Height="{Binding ActualHeight, 
             ElementName=presenter}"> 
      <Rectangle.Fill> 
       <VisualBrush AlignmentX="Left" 
          Stretch="None" 
          Visual="{Binding ElementName=presenter}" /> 
      </Rectangle.Fill> 
      <Rectangle.RenderTransform> 
       <TranslateTransform X="3" 
            Y="3" /> 
      </Rectangle.RenderTransform> 
      </Rectangle> 
      <!-- You can replace the following line to a ContentControl if you absolutely have to --> 
      <ContentPresenter x:Name="presenter" 
          ContentSource="Content" /> 
     </Grid> 
     </ControlTemplate> 
    </Setter.Value> 
    </Setter> 
</Style> 

Utilisation peuvent alors être dynamiques comme:

<Button HorizontalAlignment="Center" 
     VerticalAlignment="Center" 
     FontSize="36" 
     Style="{StaticResource ShadowButton}"> 
    <StackPanel> 
    <Button Margin="2" 
      Content="A" /> 
    <Button Margin="2" 
      Content="B" /> 
    <TextBox Margin="2" 
      Text="Blah" /> 
    </StackPanel> 
</Button> 

En utilisant un VisualBrush votre ne pas avoir 2 ContentControl/ContentPresenter dans votre style et sont tout simplement rendu un dans un Brush pour remplir un rectangle et obtenir votre effet.

Duplication Arbre visuelle avec un modèle

Essayez d'avoir un UserControl faire ce qu'un Button en premier lieu. Vous devez utiliser un modèle si vous souhaitez dupliquer l'arbre visuel dans votre style.

<Style x:Key="ShadowButton" 
     TargetType="{x:Type Button}"> 
    <Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="{x:Type Button}"> 
     <Grid> 
      <ContentControl x:Name="shadow" 
          ContentTemplate="{TemplateBinding ContentTemplate}" 
          Foreground="SpringGreen"> 
      <ContentControl.RenderTransform> 
       <TranslateTransform X="50" 
            Y="50" /> 
      </ContentControl.RenderTransform> 
      </ContentControl> 
      <ContentControl x:Name="presenter" 
          ContentTemplate="{TemplateBinding ContentTemplate}" 
          Foreground="SlateBlue" /> 
     </Grid> 
     <ControlTemplate.Triggers> 
      <Trigger SourceName="presenter" 
        Property="IsMouseOver" 
        Value="True"> 
      <Setter TargetName="shadow" 
        Property="Foreground" 
        Value="Teal" /> 
      <Setter TargetName="presenter" 
        Property="Foreground" 
        Value="Red" /> 
      </Trigger> 
     </ControlTemplate.Triggers> 
     </ControlTemplate> 
    </Setter.Value> 
    </Setter> 
</Style> 

et utilisation:

<Button HorizontalAlignment="Center" 
     VerticalAlignment="Center" 
     Style="{StaticResource ShadowButton}"> 
    <Button.ContentTemplate> 
    <DataTemplate> 
     <StackPanel> 
     <Button Margin="2" 
       Content="A" 
       Foreground="{Binding RelativeSource={RelativeSource FindAncestor, 
                    AncestorType={x:Type ContentControl}}, 
             Path=Foreground}" /> 
     <TextBox Margin="2" 
        Foreground="{Binding RelativeSource={RelativeSource FindAncestor, 
                     AncestorType={x:Type ContentControl}}, 
             Path=Foreground}" 
        Text="Blah" /> 
     </StackPanel> 
    </DataTemplate> 
    </Button.ContentTemplate> 
</Button> 
+0

Modifier le modèle comme ceci supprimera l'option de l'utiliser avec des données personnalisées, car il manque maintenant le ContentPresenter. Bien que je comprenne cela dans le but d'expliquer, il convient de noter que ce n'est pas une bonne pratique. – dowhilefor

+0

J'utilise ContentControl au lieu de ContentPresenter parce que j'ai besoin de changer le contenu du premier plan du bouton en fonction de l'état visuel. Votre solution fonctionnerait si le contenu du bouton est uniquement du texte. Cependant, cela ne fonctionnera pas si vous avez du contenu personnalisé dans le contenu du bouton (exemple un panneau de pile avec plusieurs éléments enfants) – exkoria

+0

@dowhilefor Oui ce style posté serait spécifique pour un bouton avec juste du contenu textuel pour l'effet d'ombre.Il ne manque pas de ContentPresenter tho (il l'utilise toujours dans le style) seul l'effet est lié à la propriété Text du ContentPresenter qui si ce bouton contenait d'autres éléments enfants et que ce Style ne fonctionnerait pas. Am Mise à jour de la réponse pour accommoder les contrôles enfants imbriqués. – Viv

0

J'ai essayé dans une petite application factice et il fonctionne très bien. Voyez si c'est ce que vous voulez.

 <Window.Resources> 
     <Style x:Key="test" TargetType="Button"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="{x:Type Button}"> 
         <Grid> 
          <ContentControl Content="{TemplateBinding Content}" 
              ContentTemplate="{TemplateBinding ContentTemplate}" 
              ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"/> 
          <ContentControl Foreground="DarkGray" 
              Content="{TemplateBinding Content}" 
              ContentTemplate="{TemplateBinding ContentTemplate}" 
              ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"> 
           <ContentControl.RenderTransform> 
            <TranslateTransform Y="2" X="2"/> 
           </ContentControl.RenderTransform> 
          </ContentControl> 
         </Grid> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </Window.Resources> 
    <Grid> 
     <Button Style="{StaticResource test}"> 
      Test 
     </Button> 
    </Grid> 
+0

Merci pour la réponse. Non, ça ne marche pas. Il fonctionne pour tout le contenu de la chaîne, mais pas pour le contenu complexe tel que exkoria

+0

bien il n'y a pas moyen facile de résoudre ce alors, le mieux est maintenant d'utiliser un VisualBrush pour l'effet d'ombre, tout en ne conservant qu'un seul contenu. – dowhilefor

Questions connexes