2011-01-08 3 views
0

Я пытаюсь написать ControlTemplate для System.Windows.Controls.Button, но у меня все время возникают проблемы с анимацией, которая у меня есть в приложенном поведении. В частности, наведите курсор мыши на кнопку выдает ошибку во время выполнения:WPF: проблема с именами с шаблоном управления

InvalidOperationException was unhandled: No applicable name scope exists to resolve the name 'myBrush'.

Это происходит в файле «ButtonVisualBehavior.cs», когда sb.Begin() вызывается (см коды размещены ниже). Во всяком случае, я пробовал все, что могу себе представить, чтобы исправить это, и у меня все еще есть проблемы. Любая помощь будет оценена!

Вот код:

ButtonStyleV.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:WpfApplication4"> 
    <Style TargetType="{x:Type Button}" x:Key="{x:Type Button}"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type Button}"> 
        <ControlTemplate.Resources> 
         <Storyboard x:Key="ButtonStoryboardKey"> 
          <ColorAnimation Storyboard.TargetName="myBrush" 
              Storyboard.TargetProperty="Color" 
              From="White" 
              To="Black" 
              Duration="0:0:1.0" 
              RepeatBehavior="Forever" 
              AutoReverse="True" /> 
         </Storyboard> 
        </ControlTemplate.Resources> 

        <Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"> 

         <Rectangle x:Name="ButtonRect" 
            Stroke="{x:Null}" Opacity="1" 
            Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" 
            HorizontalAlignment="Center" VerticalAlignment="Center"> 
          <Rectangle.Fill> 
           <SolidColorBrush x:Name="myBrush" /> 
          </Rectangle.Fill> 
         </Rectangle> 

         <ContentPresenter x:Name="ButtonContentPresenter" 
              Content="{TemplateBinding Button.Content}" 
              ContentTemplate="{TemplateBinding Button.ContentTemplate}" 
              HorizontalAlignment="Center" VerticalAlignment="Center"> 
         </ContentPresenter> 

        </Grid> 

       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
     <Setter Property="local:ButtonVisualBehaviorV.IsBehaviorAttached" Value="True" /> 
    </Style> 
</ResourceDictionary> 

ButtonVisualBehavior.cs

using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Shapes; 
using System.Windows.Input; 
using System.Windows.Media.Animation; 

namespace WpfApplication4 
{ 
    class ButtonVisualBehaviorV 
    { 
     public static bool GetIsBehaviorAttached(DependencyObject obj) 
     { 
      return (bool)obj.GetValue(IsBehaviorAttachedProperty); 
     } 

     public static void SetIsBehaviorAttached(DependencyObject obj, bool value) 
     { 
      obj.SetValue(IsBehaviorAttachedProperty, value); 
     } 

     // Using a DependencyProperty as the backing store for IsBehaviorAttached. 
     // This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty IsBehaviorAttachedProperty = 
      DependencyProperty.RegisterAttached(
       "IsBehaviorAttached", 
       typeof(bool), 
       typeof(ButtonVisualBehaviorV), 
       new UIPropertyMetadata(false, OnIsBehaviorAttachedChanged)); 

     private static void OnIsBehaviorAttachedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      Button button = d as Button; 

      if ((button == null) || ((bool)e.NewValue == false)) 
       return; 

      if (((bool)e.NewValue) == true) 
      { 
       button.MouseEnter += Button_MouseEnter; 
       button.MouseLeave += Button_MouseLeave; 
      } 
      else 
      { 
       button.MouseEnter -= Button_MouseEnter; 
       button.MouseLeave -= Button_MouseLeave; 
      } 
     } 

     private static void Button_MouseEnter(object sender, MouseEventArgs e) 
     { 
      Button button = sender as Button; 
      Rectangle buttonRectangle = button.Template.FindName("ButtonRect", button) as Rectangle; 

      Storyboard sb = buttonRectangle.FindResource("ButtonStoryboardKey") as Storyboard; 

      sb.Begin(); 
     } 

     private static void Button_MouseLeave(object sender, MouseEventArgs e) 
     { 
      Button button = sender as Button; 
      Rectangle buttonRectangle = button.Template.FindName("ButtonRect", button) as Rectangle; 

      Storyboard sb = buttonRectangle.FindResource("ButtonStoryboardKey") as Storyboard; 

      sb.Begin(); 
     } 
    } 
} 

Window2.xaml:

<Window x:Class="WpfApplication4.Window2" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:WpfApplication4" 
     Title="Window2" Height="300" Width="300"> 
    <Grid> 
     <Button Background="Green" Content="Button" Height="30" HorizontalAlignment="Left" Margin="120,138,0,0" VerticalAlignment="Top" Width="75" /> 
    </Grid> 
</Window> 

и, наконец, App.xaml :

<Application x:Class="WpfApplication4.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:local="clr-namespace:WpfApplication4" 
      StartupUri="Window2.xaml"> 
    <Application.Resources> 
     <ResourceDictionary> 
      <ResourceDictionary.MergedDictionaries> 
       <ResourceDictionary Source="/Troubleshooting/ButtonStyleV.xaml" /> 
      </ResourceDictionary.MergedDictionaries> 
     </ResourceDictionary> 
    </Application.Resources> 
</Application> 

Спасибо!

Andrew

+0

Хм ... Ну, я просто заметил, что все работает отлично, если я перемещаю ресурсы Storyboard из ControlTemplate.Resources в дочерний сбор Grid.Resources (это в файле ButtonStyleV.xaml). Я просто не знаю, почему ... – Andrew

ответ

0

Вы, казалось, решили вашу непосредственную проблему, но, возможно, вы оценить, как вы можете сделать то же самое с гораздо меньшими усилиями и в XAML только с помощью VisualStateManager так:

<ControlTemplate TargetType="{x:Type Button}"> 
    <Grid> 
     <VisualStateManager.VisualStateGroups> 
      <VisualStateGroup x:Name="CommonStates"> 
       <VisualState x:Name="Normal"/> 
       <VisualState x:Name="MouseOver"> 
        <Storyboard> 
         <ColorAnimation Storyboard.TargetName="myBrush" 
             Storyboard.TargetProperty="Color" 
             From="White" 
             To="Black" 
             Duration="0:0:1.0" 
             RepeatBehavior="Forever" 
             AutoReverse="True" /> 
        </Storyboard> 
       </VisualState> 
       <VisualState x:Name="Pressed"/> 
       <VisualState x:Name="Disabled"/> 
      </VisualStateGroup> 
     </VisualStateManager.VisualStateGroups> 
     <Rectangle x:Name="ButtonRect" 
        Stroke="{x:Null}" Opacity="1" 
        Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" 
        HorizontalAlignment="Center" VerticalAlignment="Center"> 
      <Rectangle.Fill> 
       <SolidColorBrush x:Name="myBrush" /> 
      </Rectangle.Fill> 
     </Rectangle> 
     <ContentPresenter x:Name="ButtonContentPresenter" 
         Content="{TemplateBinding Button.Content}" 
         ContentTemplate="{TemplateBinding Button.ContentTemplate}" 
         HorizontalAlignment="Center" VerticalAlignment="Center"> 
     </ContentPresenter> 
    </Grid> 
</ControlTemplate> 
+0

Спасибо, Рик, вы хорошо работаете. Я, вероятно, буду придерживаться приложенного поведения, поскольку код, который я вытащил из этого, требует некоторых других визуальных изменений кнопки, которые мне было легче сделать в C#. Вы - решение, кажется, более элегантное. – Andrew