2010-12-13 23 views
0

我想將按鈕的背景顏色更改爲正常,隱藏和按下的狀態爲各種不同的綠色。我被迫添加以下奇怪的詳細Button.Template到我的按鈕,以便我可以修改RenderMouseOverRenderPressed屬性以使用Binding而不是TemplateBinding,以便我的觸發器(在Button.Style中)實際上生效,而不是由於編譯而被忽略時間性質爲TemplateBinding。無論如何,爲了更好地覆蓋Aero主題而重寫這兩個屬性要比重複整個模板綁定更重要嗎? XAML如下:如何在不重複整個控件模板的情況下將TemplateBindings更改爲按鈕控件模板中的綁定

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

重要提示:控制模板只爲Aero主題是必要的。對於其他主題,僅僅使用Button.Style就可以完成這項工作。

+0

我不明白你爲什麼不創建一個樣式來處理這個問題,只是將它應用到每個按鈕,你認爲合適?我錯過了抵制這種行爲的那一塊......?看起來像我的標準按鈕樣式... – 2010-12-13 19:36:09

+0

抵制這種行爲的部分是Aero Chrome。我添加了一個註釋來強調這一事實。 – 2010-12-13 21:34:51

回答

1

我能想到的最好的方法是添加一個附加的行爲,一旦按鈕加載就禁用此功能。我不知道如果你喜歡這比重新模板,但你不會有包括PresentationFramework.Aero和可重複使用的

<Button behaviors:DisableButtonChromeBehavior.DisableButtonChrome="True" 
     ...> 
    <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> 

的DisableButtonChromeBehavior

public static class DisableButtonChromeBehavior 
{ 
    public static readonly DependencyProperty DisableButtonChromeProperty = 
     DependencyProperty.RegisterAttached 
     (
      "DisableButtonChrome", 
      typeof(bool), 
      typeof(DisableButtonChromeBehavior), 
      new UIPropertyMetadata(false, OnDisableButtonChromePropertyChanged) 
     ); 
    public static bool GetDisableButtonChrome(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(DisableButtonChromeProperty); 
    } 
    public static void SetDisableButtonChrome(DependencyObject obj, bool value) 
    { 
     obj.SetValue(DisableButtonChromeProperty, value); 
    } 
    private static void OnDisableButtonChromePropertyChanged(DependencyObject dpo, 
                  DependencyPropertyChangedEventArgs e) 
    { 
     Button button = dpo as Button; 
     if (button != null) 
     { 
      if ((bool)e.NewValue == true) 
      { 
       button.Loaded += OnButtonLoaded; 
      } 
      else 
      { 
       button.Loaded -= OnButtonLoaded; 
      } 
     } 
    } 
    private static void OnButtonLoaded(object sender, RoutedEventArgs e) 
    { 
     Button button = sender as Button; 
     Action action =() => 
      { 
       object buttonChrome = VisualTreeHelper.GetChild(button, 0); 
       Type type = buttonChrome.GetType(); 
       PropertyInfo propertyInfo = type.GetProperty("RenderMouseOver"); 
       if (propertyInfo != null) 
       { 
        propertyInfo.SetValue(buttonChrome, false, null); 
        propertyInfo = type.GetProperty("RenderPressed"); 
        propertyInfo.SetValue(buttonChrome, false, null); 
        propertyInfo = type.GetProperty("RenderDefaulted"); 
        propertyInfo.SetValue(buttonChrome, false, null); 
       } 
      }; 
     button.Dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle); 
    } 
} 

更新
還有更短的不可重用的方式,只是在代碼背後做這個。

private void Button_Loaded(object sender, RoutedEventArgs e) 
{ 
    Button button = sender as Button; 
    object buttonChrome = VisualTreeHelper.GetChild(button, 0); 
    PropertyInfo renderMouseOverInfo = buttonChrome.GetType().GetProperty("RenderMouseOver"); 
    if (renderMouseOverInfo != null) 
    { 
     renderMouseOverInfo.SetValue(buttonChrome, false, null); 
    } 
} 

或者(如果你不介意,包括航空)

<Button ...> 
    <Button.Resources> 
     <Style TargetType="Microsoft_Windows_Themes:ButtonChrome"> 
      <EventSetter Event="Loaded" Handler="ButtonChrome_Loaded"/> 
     </Style> 
    </Button.Resources> 

void ButtonChrome_Loaded(object sender, RoutedEventArgs e) 
{ 
    ButtonChrome buttonChrome = sender as ButtonChrome; 
    if (buttonChrome != null) 
    { 
     buttonChrome.RenderMouseOver = false; 
     buttonChrome.RenderPressed = false; 
    } 
} 

除此之外,我覺得你沒有任何其他的出局比你指出自己的解決方案(重新模板) 。

+0

哇,雖然我相信這可以工作,但它比XAML包含所有的鉻更加「冗長」...... – 2010-12-13 23:55:16

+0

你是最終的解決方案看起來不錯!太糟糕了,它不能通過XAML完成... – 2010-12-14 14:58:07

0

如果你想使用的樣式切換背景,你不能明確設置背景屬性,你在這裏做:

<Button Background="LightGreen"> 

這將覆蓋您設置的任何樣式。試試這個:

<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.Template> 
    <ControlTemplate TargetType="{x:Type Button}"> 
     <Border SnapsToDevicePixels="true" x:Name="Chrome" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"> 
     <ContentPresenter Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> 
     </Border> 
    </ControlTemplate> 
    </Button.Template> 

這裏的缺點是,如果你不想要的Aero,你沒有得到任何的它,你必須從頭開始使用你的模板。

+0

我的意見,我糾正了這個疏忽。但是,您的解決方案不適用於Aero主題,並且控件模板仍然是必需的。 – 2010-12-13 21:04:43

+0

@Michael:你是否希望在所有操作系統中使用Aero主題?如果是這樣,因爲WPF旨在使用當前Windows操作系統的感覺,所以沒有其他方式強制使用Aero而不是重寫模板並特別使用Aero資源。 – poindexter12 2010-12-13 21:07:53

+0

不,我正在研究如何在使用Aero時有效地更改按鈕的背景顏色。簡單地設置按鈕樣式(對於Aero)不起作用。 – 2010-12-13 21:12:32