Как изменить TemplateBindings на Bindings в шаблоне элемента управления кнопки, не повторяя весь шаблон элемента управления - PullRequest
0 голосов
/ 13 декабря 2010

Я хочу изменить цвет фона кнопки в ее нормальном, наведенном и нажатом состояниях на различные оттенки зеленого.Я вынужден добавить следующие гротескно подробные Button.Template к моей кнопке, чтобы я мог изменить атрибуты RenderMouseOver и RenderPressed, чтобы использовать Binding вместо TemplateBinding, чтобы мои триггеры (в Button.Style) фактически вступают в силу, а не игнорируются из-за природы времени компиляции TemplateBinding.Есть ли способ переопределить эти два атрибута для темы Aero более аккуратно, чем повторение всей привязки шаблона в целом?Ниже следует 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>
      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.

Ответы [ 2 ]

1 голос
/ 14 декабря 2010

Лучшее, что я могу придумать, - это добавить прикрепленное поведение, которое отключает это с отражением, как только кнопка будет загружена. Я не знаю, нравится ли вам это лучше, чем перепрограммировать его, но вам не нужно будет включать 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);
    }
}

Или (если не возражаете, включая 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;
    }
}

Кроме этого, я думаю, что у вас нет других выходов, кроме решения, которое вы указали себе (пересматривая).

0 голосов
/ 13 декабря 2010

Если вы хотите использовать стиль для переключения фона, вы не можете явно установить свойство Background, как вы сделали здесь:

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

Это должно сделать так, чтобы вы могли избавиться от шаблона кнопки, если вы не хотите делать больше в нем.

Если вы хотите избавиться отерунда Aero, замените шаблон следующим образом:

   <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, вы не получите ничего из этого и вам придется начинать с шаблона с нуля.

...