WPF:控件模板的名称范围问题

发布于 2024-10-10 19:07:07 字数 6560 浏览 1 评论 0原文

我正在尝试为 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>

谢谢!

安德鲁

I'm trying to write a ControlTemplate for a System.Windows.Controls.Button, but I keep running into trouble with an animation that I have in an attached behavior. Specifically, mousing over the button produces the runtime error:

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

This happens in the 'ButtonVisualBehavior.cs' file when sb.Begin() is called (see code posted below). Anyway, I've tried everything I can imagine to fix this, and I'm still having trouble. Any help will be greatly appreciated!

Here's the 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>

and finally, 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>

Thanks!

Andrew

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

归途 2024-10-17 19:07:07

您似乎已经解决了眼前的问题,但也许您很欣赏如何以更少的努力完成同样的事情,并且仅在 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>

You seemed to have solved your immediate problem but perhaps you appreciate how you can accomplish the same thing with a lot less effort and in XAML only by using the VisualStateManager like this:

<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文