2011-01-08 1 views
0

Ich versuche, eine ControlTemplate für eine System.Windows.Controls.Button zu schreiben, aber ich laufe immer wieder in Schwierigkeiten mit einer Animation, die ich in einem angehängten Verhalten habe. Insbesondere erzeugt Fehler bei der Laufzeit über die Schaltfläche mousing:WPF: Namescope Problem mit Steuerelement Vorlage

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

Dies geschieht in der Datei 'ButtonVisualBehavior.cs', wenn sb.Begin() aufgerufen wird (siehe Code unten geschrieben). Jedenfalls habe ich alles versucht, was ich mir vorstellen kann, um das zu beheben, und ich habe immer noch Probleme. Jede Hilfe wird sehr geschätzt!

Hier ist der Code:

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> 

und schließlich 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> 

Vielen Dank!

Andrew

+0

Hmm ... Nun, ich habe gerade bemerkt, dass alles gut funktioniert, wenn ich die Storyboard-Ressourcen von der ControlTemplate.Resources in die untergeordnete Grid.Resources-Sammlung verschiebe (dies ist in der ButtonStyleV.xaml-Datei). Ich bin nur nicht sicher, warum ... – Andrew

Antwort

0

Sie schien Ihr unmittelbares Problem gelöst zu haben, aber vielleicht zu schätzen wissen Sie, wie Sie die gleiche Sache mit viel weniger Aufwand erreichen können und in XAML nur durch die VisualStateManager wie folgt aus:

<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

Dank Rick, du bist die Lösung funktioniert ganz gut. Ich bleibe wahrscheinlich bei dem angehängten Verhalten, da der Code, aus dem ich diesen Code gezogen habe, einige andere visuelle Änderungen an der Schaltfläche erfordert, die für mich in C# einfacher waren. Deine Lösung scheint die elegantere zu sein. – Andrew