在Aero上覆盖WPF中的按钮背景

时间:2010-12-12 23:20:03

标签: c# wpf c#-4.0 wpf-controls wpf-4.0

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

<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镀铬。不想放弃,我尝试以下放荡:

...
    <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 中取出了整个friggin'控制模板。唉,这没什么改变。然后,我将从RenderPressed元素中删除两个属性(RenderMouseOverMicrosoft_Windows_Themes:ButtonChrome)。不过,没有变化。然后我删除Button的Background属性的设置,只留下PresentationFramework.Aero程序集的名称空间声明:

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

最后,我们取得了进展。我们已经从1/3的要求变为2/3,IsMouseOver和IsPressed工作,但在按钮的正常状态(没有被碾过或按下)时没有浅绿色背景,因为我已经删除了按钮的Background属性,以使其他两个状态应用并可见。现在,在这个疯狂的XAML无法获得正常按钮状态的LightGreen背景之后,我修改了样式以在那里抛出背景颜色:

  <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主题来改变按钮的背景颜色,只是在一些不同的状态(正常,悬停,按下)?也许,如果我不必在其中包含整个Button Button,只是为了从中移除两个属性(RenderMouseOverRenderPressed),生活就不会那么糟糕。

感谢您的帮助 - 我结束了。

更新:但等待还有更多内容。而不是从控件模板中删除RenderMouseOver和RenderPressed属性,只需从以下位置更改它们:

<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),则不使用来自单个按钮的样式触发器的绑定。

说完上述所有内容后,这里是在保留原始控件模板的同时更改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>
      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)。

如果有任何人对如何覆盖有关Binding的TemplateBinding只有控件模板中需要更改的两个属性有任何建议,而不重复aero xaml批发的整个Chrome定义,我我都是耳朵。

1 个答案:

答案 0 :(得分:2)

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