在 Aero 上覆盖 WPF 中的按钮背景 [英] Overriding button background in WPF on Aero

查看:20
本文介绍了在 Aero 上覆盖 WPF 中的按钮背景的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,希望很简单,将按钮的背景更改为浅绿色,当鼠标光标悬停在其上时为绿色,按下时为深绿色.以下 XAML 是我的第一次尝试:

So, the desire is simple, change a button's background to LightGreen, Green when the mouse cursor hovers over it and DarkGreen when it is pressed. The following XAML is my first attempt:

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

但是,唉,这行不通.我们距离目标只有 1/3 的路程.是的,按钮变成浅绿色,但是只要您将鼠标悬停在它上面或按下它,您就会获得相应按钮状态的标准 Aero 镀铬.不想放弃,我尝试了以下放荡:

But, alas this doesn't work. We're only 1/3 of the way towards the goal. Yes, the button becomes light green, but as soon as you hover over it or press it you get standard Aero chrome for the respective button states. Not wanting to give up, I attempt the following debauchery:

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

现在我们已经从 Aero.NormalColor.xaml 中取出了整个该死的控制模板.唉,这没有任何改变.然后我着手从 Microsoft_Windows_Themes:ButtonChrome 元素中删除两个属性(RenderPressedRenderMouseOver).尽管如此,还是没有改变.然后我删除了按钮的 Background 属性的设置,只留下 PresentationFramework.Aero 程序集的命名空间声明:

Now we've got the whole friggin' control template thrown in there lifted from Aero.NormalColor.xaml. Alas, this changes nothing. I then go about removing two attributes (RenderPressed and RenderMouseOver) from the Microsoft_Windows_Themes:ButtonChrome element. Still, there is no change. I then remove the setting of the Button's Background attribute, leaving just the namespace declaration for the PresentationFramework.Aero assembly:

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

我们终于有了进展.我们已经从 1/3 的要求变成了 2/3 的方式,IsMouseOver 和 IsPressed 工作,但在按钮的正常状态(没有被鼠标悬停或按下)期间没有浅绿色背景,因为我已经删除按钮的 Background 属性,以应用其他两个状态并使其可见.现在,在这个疯狂的 XAML 无法为我们提供正常按钮状态的 LightGreen 背景后,我修改了样式以将背景颜色也放入其中:

Finally, we have progress. We've gone from 1/3 of the requirements to 2/3 of the way, with IsMouseOver and IsPressed working, but no light green background during the button's normal state (of not being moused over or pressed), since I've removed the Background property from the button, to get the other two states to apply and be visible. Now, after this maniacal XAML fails to get us the LightGreen background for the normal button state, I modify the style to throw the background color in there as well:

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

最后,它按预期工作.

我是不是疯了,或者这些(以及更多)是您必须通过 Aero 主题来改变按钮在某些不同状态(正常、悬停、按下)下的背景颜色的麻烦吗?也许,如果我不必将整个 dang ButtonTemplate 包含在其中只是为了从中删除两个属性(RenderMouseOverRenderPressed),生活就不会那么糟糕.

Am I crazy, or are these (and more) the hoops you have to go through with an Aero theme to just change a button's background color in some of its various states (normal, hovered over, pressed)? Maybe, life wouldn't be so bad if I didn't have to include the whole dang ButtonTemplate in there just to remove the two attributes (RenderMouseOver and RenderPressed) from it.

感谢您的任何帮助 - 我无能为力了.

Thank you for any help - I am at wit's end.

更新:但是等等还有更多.而不是从控件模板中删除 RenderMouseOver 和 RenderPressed 属性,只需将它们从:

Update: But wait there's more to this. Instead of removing the RenderMouseOver and RenderPressed attributes from the control template, simply changing them from:

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

到:

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

...,也解决了这个问题(忽略按钮的样式触发器).我认为问题的根源在于模板绑定在编译时应用(出于性能原因),而常规绑定在运行时应用.因此,如果属性使用模板绑定(即,改为使用原始模板中的 IsMouseOver 和 IsPressed),则不会使用来自各个按钮的样式触发器的绑定.

..., also fixes the problem (of ignoring the button's style triggers). I think the root of the issue is that the template bindings are applied at compile time (for performance reasons), while regular bindings are applied at run time. Because of this, the bindings from the style triggers from the individual buttons are not used if attributes use template bindings (i.e., the IsMouseOver and IsPressed from the original template are used instead).

综上所述,以下是在 Aero 中更改按钮背景同时保留其原始控件模板的规范示例:

Having said all of the above, here is the canonical example for changing a button's background in Aero while keeping its original control template:

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

这当然是假设只有一个按钮如此样式化,否则模板和样式可以移到某个资源部分中.此外,按钮的默认状态没有触发器,但它很容易添加到上面的示例中(不要忘记将控件模板中的 RenderDefaulted 属性更改为使用 Binding 而不是 TemplateBinding).

This is of course assuming that only one button is so styled, otherwise the template and style can be moved out into a resources section somewhere. Also, there is no trigger for the default state of a button, but it is easily added to the above example (don't forget to change the RenderDefaulted attribute in the control template to use Binding instead of TemplateBinding).

如果有人对如何覆盖 TemplateBinding with Binding 仅针对需要更改的控件模板中的两个属性有任何建议,而无需重复 aero xaml 批发中的整个 chrome 定义,我我全都在听.

If anyone has any suggestions on how to override the TemplateBinding with Binding for only the two attributes in the control template that need to change, without repeating the entire chrome definition from the aero xaml wholesale, I am all ears.

推荐答案

Button 的默认模板使用 ButtonChrome,它执行自己的绘图.如果你想完全摆脱默认的外观,你需要定义你自己的模板,没有 ButtonChrome.我知道这听起来很乏味,但您只需要做一次:您可以将自定义样式放在资源字典中,然后使用 StaticResource 引用它.请注意,您还可以通过使用 {x:Type Button} 作为样式的键(x:Key 属性)

The default template for Button uses a ButtonChrome, which performs its own drawing. If you want to get completely rid of the default appearance, you need to define your own template, without the ButtonChrome. I know it sounds tedious, but you only have to do it once: you can put your custom style in a resource dictionary, and just refer to it with StaticResource. Note that you can also apply the style to all buttons in your app by using {x:Type Button} as the style's key (x:Key attribute)

这篇关于在 Aero 上覆盖 WPF 中的按钮背景的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆