WPF:带控件模板的Namescope问题

时间:2011-01-08 00:14:31

标签: wpf templates animation controls

我正在尝试为System.Windows.Controls.Button编写一个ControlTemplate,但是我在附加行为中的动画时遇到了麻烦。具体来说,鼠标悬停在按钮上会产生运行时错误:

  

InvalidOperationException是   未处理:没有适用的名称范围   存在以解析名称'myBrush'。

当调用sb.Begin()时,会在'ButtonVisualBehavior.cs'文件中发生这种情况(请参阅下面发布的代码)。无论如何,我已经尝试了我能想象到的一切来解决这个问题,而且我仍然遇到麻烦。任何帮助将不胜感激!

以下是代码:

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>

谢谢!

安德鲁

1 个答案:

答案 0 :(得分:0)

您似乎已经解决了眼前的问题,但也许您很欣赏如何以更少的努力完成同样的事情,并且只使用VisualStateManager这样的XAML:

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