在WPF按钮中显示相同内容两次

在WPF按钮中显示相同内容两次,wpf,button,styles,contentcontrol,Wpf,Button,Styles,Contentcontrol,我们希望设置wpf按钮的样式,以便按钮中设置的内容显示两次。这样做的原因是我们想要实现按钮内容的阴影效果。我们的想法是有两个按钮样式的ContentControl,如下所示: <ContentControl x:Name="ContentControl" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateB

我们希望设置wpf按钮的样式,以便按钮中设置的内容显示两次。这样做的原因是我们想要实现按钮内容的阴影效果。我们的想法是有两个按钮样式的ContentControl,如下所示:

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

因此,一个ContentControl用于显示真实内容,另一个ContentControl用于显示具有少量边距的相同内容,以使其产生阴影效果。问题是它不会在两个内容控件中都显示内容。其中只有一个显示内容。如何在两个内容控件中成功显示内容

此外,dropshadow效果不是选项,因为按钮的内容变得模糊


谢谢你的帮助

带有嵌套内容的按钮

<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>
使用方法:

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


带有嵌套内容的按钮

<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>
使用方法:

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

我在一个小型虚拟应用程序中尝试了这个方法,效果很好。看看这是不是你想要的

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

试验

我在一个小型虚拟应用程序中尝试了这个方法,效果很好。看看这是不是你想要的

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

试验

第二个ContentControl没有ContentTemplate绑定,您也应该始终绑定ContentTemplateSelector,相信我,这将为您节省大量烦人的bug搜索。您还应该了解ContentPresenter及其在ContentControls中的使用。谢谢您的回复。我知道在模板中使用ContentPresenter和ContentControl是有区别的。我在这里使用contentControl的原因是能够设置contentControl的前台属性。这样,我可以根据VisualState(按下按钮等)控制前景。ContentPresenter没有前台属性。ContentTemplate没有任何区别,使用两个ContentPresenter也没有任何帮助。第二个ContentControl没有ContentTemplate绑定,并且您应该始终绑定ContentTemplateSelector,相信我,这将为您节省大量烦人的bug搜索。您还应该了解ContentPresenter及其在ContentControls中的使用。谢谢您的回复。我知道在模板中使用ContentPresenter和ContentControl是有区别的。我在这里使用contentControl的原因是能够设置contentControl的前台属性。这样,我可以根据VisualState(按下按钮等)控制前景。ContentPresenter没有前台属性。ContentTemplate没有任何区别,使用2个ContentPresenter也没有帮助。这样更改模板将删除将其用于自定义数据的选项,因为现在缺少ContentPresenter。虽然我理解这一点是为了解释,但应该注意,这不是一个好的做法。我使用ContentControl而不是ContentPresenter,因为我需要根据视觉状态更改按钮内容的前景。如果按钮的内容仅为文本,您的解决方案将起作用。但是,如果按钮的内容中包含自定义内容(例如,具有多个子元素的stackpanel)@dowhilefor是的,发布的此样式仅适用于具有阴影效果的文本内容的按钮。它并不缺少ContentPresenter tho(它仍然在样式中使用它),只是效果绑定到ContentPresenter的文本属性,如果按钮包含其他子元素并且具有此样式,则该属性将不起作用。我正在更新答案以适应任何嵌套的子控件。感谢您的更新回复!我以前确实尝试过这个解决方案,问题是VisualBrush总是作为内容的精确副本呈现,所以我无法以其他颜色获得它。我需要白色的dropshadow和另一种颜色的内容,这也需要根据视觉状态进行更改:-)您需要了解,当您设置内容时,实际的视觉树为“1”。因此,您不能将其添加到样式中的两个不同元素中,您需要使用模板来完成此操作。但是,您实际上应该将整个控件设置为一个单独的UserControl tbh。我将用一个工作来更新我的答案,但是要考虑把控制变成一个用户控件,而不是在按钮上这样做。像这样改变模板将取消使用自定义数据的选项,因为现在缺少内容演示者。虽然我理解这一点是为了解释,但应该注意,这不是一个好的做法。我使用ContentControl而不是ContentPresenter,因为我需要根据视觉状态更改按钮内容的前景。如果按钮的内容仅为文本,您的解决方案将起作用。但是,如果按钮的内容中包含自定义内容(例如,具有多个子元素的stackpanel)@dowhilefor是的,发布的此样式仅适用于具有阴影效果的文本内容的按钮。它并不缺少一个ContentPresenter tho(它还是我们)