Wie Sie TemplateBindings zu Bindungen in einer Steuer der Schaltfläche Vorlage ändern, ohne die gesamte Steuerungsschablone wiederholen

StackOverflow https://stackoverflow.com/questions/4432671

Frage

Ich möchte in seinem normalen die Hintergrundfarbe einer Taste ändern, moused-und drückte Staaten zu verschiedenen Schattierungen von Grün. Ich bin gezwungen, die folgende grotesk ausführliche Button.Template meiner Schaltfläche hinzufügen, damit ich die RenderMouseOver ändern und RenderPressed Attribute Binding statt TemplateBinding zu verwenden, so dass meine Trigger (in der Button.Style) tatsächlich wirksam statt aufgrund der Kompilierung ignoriert Zeit Natur TemplateBinding. Gibt es trotzdem, diese beiden Attribute sauberer für ein Aero-Design außer Kraft zu setzen als die gesamte Vorlage in all ihren Teilen verbindlich zu wiederholen? XAML folgt:

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

Wichtiger Hinweis: : Die Steuervorlage erforderlich ist, nur für das Aero-Design. Für andere Themen, mit nur dem Button.Style allein wird die Arbeit tun.

War es hilfreich?

Lösung

The best I can think of is to add an attached behavior which disables this with reflection once the Button has Loaded. I don't know if you like this better than to re-template it, but you won't have to include PresentationFramework.Aero and its re-usable

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

The 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); 
    } 
}

Update
There's also the shorter non re-usable way, just doing this in code behind.

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);
    }
}

Or (if you don't mind including Aero)

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

Other than that, I think you don't have any other outs than the solution you pointed yourself (re-templating).

Andere Tipps

If you want to use the style to toggle the Background, you can't explicitly set the Background property as you have done here:

<Button Background="LightGreen">

This will override any style you set. Try this instead:

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

This should make it so you can get rid of the button template, unless you want to do more in it.

If you would like to get rid of the Aero nonsense, replace the template like so:

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

The drawback here is if you don't want Aero, you don't get any of it and you have to start from scratch with your template.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top