Перекрывающий фон кнопки в WPF на Aero - PullRequest
9 голосов
/ 13 декабря 2010

Итак, желание простое: измените фон кнопки на LightGreen, Green, когда курсор мыши наведен на нее, и 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 Chrome для соответствующих состояний кнопки.Не желая сдаваться, я пробую следующий разврат:

...
    <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 .Увы, это ничего не меняет.Затем я собираюсь удалить два атрибута (RenderPressed и RenderMouseOver) из элемента Microsoft_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, чтобы просто изменить цвет фона кнопки в некоторых ее различных состояниях (нормальный, зависание, нажатие)?Возможно, жизнь не была бы такой плохой, если бы мне не нужно было включать весь шаблон ButtonTemplate целиком, чтобы удалить из него два атрибута (RenderMouseOver и RenderPressed).

Спасибо залюбая помощь - я в конце остроумия.

Обновление: Но подождите, это еще не все.Вместо удаления атрибутов 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>

Это, конечно, при условии, что стилизована только одна кнопка, в противном случае шаблон и стиль можно переместитьгде-то в разделе ресурсов.Кроме того, нет триггера для состояния кнопки по умолчанию, но его легко добавить в приведенный выше пример (не забудьте изменить атрибут RenderDefaults в шаблоне элемента управления, чтобы использовать Binding вместо TemplateBinding).

Если у кого-то есть какие-либо предложения о том, как переопределить TemplateBinding с привязкой только для двух атрибутов в шаблоне элемента управления, которые необходимо изменить, не повторяя полного определения chrome из оптовой продажи aero xaml, я весь слух.

1 Ответ

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

Шаблон по умолчанию для Button использует ButtonChrome, который выполняет собственный рисунок.Если вы хотите полностью избавиться от внешнего вида по умолчанию, вам нужно определить свой собственный шаблон без ButtonChrome.Я знаю, это звучит скучно, но вы должны сделать это только один раз: вы можете поместить свой собственный стиль в словарь ресурсов и просто обратиться к нему с помощью StaticResource.Обратите внимание, что вы также можете применить стиль ко всем кнопкам в вашем приложении, используя {x:Type Button} в качестве ключа стиля (атрибут x:Key)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...