故事板找不到 ControlTemplate 元素

Posted

技术标签:

【中文标题】故事板找不到 ControlTemplate 元素【英文标题】:Storyboards can't find ControlTemplate elements 【发布时间】:2010-09-14 04:25:43 【问题描述】:

我创建了一些相当简单的 XAML,并且它运行良好(至少在 KAXML 中)。当从 XAML 中调用情节提要时,情节提要可以完美运行,但是当我尝试从外部访问它们时出现错误:

'buttonGlow' name cannot be found in the name scope of 'System.Windows.Controls.Button'.

我正在使用流阅读器加载 XAML,如下所示:

Button x = (Button)XamlReader.Load(stream);

并尝试使用以下方式运行情节提要:

Storyboard pressedButtonStoryboard =   
    Storyboard)_xamlButton.Template.Resources["ButtonPressed"];
pressedButtonStoryboard.Begin(_xamlButton);

我认为问题在于我正在制作动画的字段位于模板中,而情节提要正在访问该按钮。

这是 XAML:

<Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:customControls="clr-namespace:pk_rodoment.SkinningEngine;assembly=pk_rodoment" 
    Width="150" Height="55">
    <Button.Resources>
        <Style TargetType="Button">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid Background="#00FFFFFF">
                            <Grid.BitmapEffect>
                                <BitmapEffectGroup>
                                    <OuterGlowBitmapEffect x:Name="buttonGlow" GlowColor="#A0FEDF00" GlowSize="0"/>
                                </BitmapEffectGroup>
                            </Grid.BitmapEffect>
                            <Border x:Name="background" Margin="1,1,1,1" CornerRadius="15">
                                <Border.Background>
                                    <SolidColorBrush Color="#FF0062B6"/>
                                </Border.Background>                                
                            </Border>                            
                            <ContentPresenter HorizontalAlignment="Center"
                                Margin="TemplateBinding Control.Padding"
                                VerticalAlignment="Center"
                                Content="TemplateBinding ContentControl.Content"
                                ContentTemplate="TemplateBinding ContentControl.ContentTemplate"/>
                        </Grid>
                        <ControlTemplate.Resources>
                            <Storyboard x:Key="ButtonPressed">
                                <Storyboard.Children>
                                    <DoubleAnimation Duration="0:0:0.4"
                                                  FillBehavior="HoldEnd"
                                                  Storyboard.TargetName="buttonGlow"
                                                  Storyboard.TargetProperty="GlowSize" To="4"/>
                                    <ColorAnimation Duration="0:0:0.6"
                                                  FillBehavior="HoldEnd"
                                                  Storyboard.TargetName="background"
                                                  Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)"
                                                  To="#FF844800"/>
                                </Storyboard.Children>
                            </Storyboard>
                            <Storyboard x:Key="ButtonReleased">
                                <Storyboard.Children>
                                    <DoubleAnimation Duration="0:0:0.2"
                                                  FillBehavior="HoldEnd"
                                                  Storyboard.TargetName="buttonGlow"
                                                  Storyboard.TargetProperty="GlowSize" To="0"/>
                                    <ColorAnimation Duration="0:0:0.2"
                                                  FillBehavior="Stop"
                                                  Storyboard.TargetName="background"
                                                  Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)"
                                                  To="#FF0062B6"/>
                                </Storyboard.Children>
                            </Storyboard>
                        </ControlTemplate.Resources>
                        <ControlTemplate.Triggers>
                            <Trigger Property="ButtonBase.IsPressed" Value="True">
                                <Trigger.EnterActions>
                                    <BeginStoryboard Storyboard="StaticResource ButtonPressed"/>
                                </Trigger.EnterActions>
                                <Trigger.ExitActions>
                                    <BeginStoryboard Storyboard="StaticResource ButtonReleased"/>
                                </Trigger.ExitActions>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Button.Resources>
    <DockPanel>
        <TextBlock x:Name="TextContent" FontSize="28" Foreground="White" >Test</TextBlock>        
    </DockPanel>
</Button>

任何比我更了解 WPF 和 XAML 的人有什么建议吗?

这是错误堆栈跟踪:

at System.Windows.Media.Animation.Storyboard.ResolveTargetName(String targetName, INameScope nameScope, DependencyObject element)
at System.Windows.Media.Animation.Storyboard.ClockTreeWalkRecursive(Clock currentClock, DependencyObject containingObject, INameScope nameScope, DependencyObject parentObject, String parentObjectName, PropertyPath parentPropertyPath, HandoffBehavior handoffBehavior, HybridDictionary clockMappings, Int64 layer)
at System.Windows.Media.Animation.Storyboard.ClockTreeWalkRecursive(Clock currentClock, DependencyObject containingObject, INameScope nameScope, DependencyObject parentObject, String parentObjectName, PropertyPath parentPropertyPath, HandoffBehavior handoffBehavior, HybridDictionary clockMappings, Int64 layer)
at System.Windows.Media.Animation.Storyboard.BeginCommon(DependencyObject containingObject, INameScope nameScope, HandoffBehavior handoffBehavior, Boolean isControllable, Int64 layer)
at System.Windows.Media.Animation.Storyboard.Begin(FrameworkElement containingObject)
at pk_rodoment.SkinningEngine.ButtonControlWPF._button_MouseDown(Object sender, MouseButtonEventArgs e)
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run(Window window)
at System.Windows.Application.Run()
at ControlTestbed.App.Main() in C:\svnprojects\rodomont\ControlsTestbed\obj\Debug\App.g.cs:line 0
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

【问题讨论】:

你如何显示按钮?您是否将其添加为某事物的子项......在任何地方? 是的,添加到网格中。 【参考方案1】:

终于找到了。当您在引用 ControlTemplate 中元素的情节提要上调用 Begin 时,您也必须传入控件模板。

变化:

pressedButtonStoryboard.Begin(_xamlButton);

收件人:

pressedButtonStoryboard.Begin(_xamlButton, _xamlButton.Template);

修复一切。

【讨论】:

哦。那容易得多。每天学习新东西。 解决了我的问题。但是调用 Stop() 不会停止我的动画。 有没有办法在 XAML 中做到这一点?【参考方案2】:

我通过重组 XAML 使其工作,以便 SolidColorBrushOuterGlowBitmapEffect 是按钮的资源,因此引用由 Storyboards 和它们应用的元素共享。我像您一样检索了Storyboard 并在其上调用了Begin(),但这里是Button 的修改后的XAML:

(请注意键 "buttonGlow""borderBackground" 以及所有引用它们的 StaticResource 标记扩展。)

<Button
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="150"
    Height="55">
    <Button.Resources>
        <OuterGlowBitmapEffect
            x:Key="buttonGlow"
            GlowColor="#A0FEDF00"
            GlowSize="0" />
        <SolidColorBrush
            x:Key="borderBackground"
            Color="#FF0062B6" />
        <Style
            TargetType="Button">
            <Setter
                Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate
                        TargetType="Button">
                        <Grid
                            Name="outerGrid"
                            Background="#00FFFFFF"
                            BitmapEffect="StaticResource buttonGlow">
                            <Border
                                x:Name="background"
                                Margin="1,1,1,1"
                                CornerRadius="15"
                                Background="StaticResource borderBackground">
                            </Border>
                            <ContentPresenter
                                HorizontalAlignment="Center"
                                Margin="TemplateBinding Control.Padding"
                                VerticalAlignment="Center"
                                Content="TemplateBinding ContentControl.Content"
                                ContentTemplate="TemplateBinding ContentControl.ContentTemplate" />
                        </Grid>
                        <ControlTemplate.Resources>
                            <Storyboard
                                x:Key="ButtonPressed">
                                <Storyboard.Children>
                                    <DoubleAnimation
                                        Duration="0:0:0.4"
                                        FillBehavior="HoldEnd"
                                        Storyboard.Target="StaticResource buttonGlow"
                                        Storyboard.TargetProperty="GlowSize"
                                        To="4" />
                                    <ColorAnimation
                                        Duration="0:0:0.6"
                                        FillBehavior="HoldEnd"
                                        Storyboard.Target="StaticResource borderBackground"
                                        Storyboard.TargetProperty="Color"
                                        To="#FF844800" />
                                </Storyboard.Children>
                            </Storyboard>
                            <Storyboard
                                x:Key="ButtonReleased">
                                <Storyboard.Children>
                                    <DoubleAnimation
                                        Duration="0:0:0.2"
                                        FillBehavior="HoldEnd"
                                        Storyboard.Target="StaticResource buttonGlow"
                                        Storyboard.TargetProperty="GlowSize"
                                        To="0" />
                                    <ColorAnimation
                                        Duration="0:0:0.2"
                                        FillBehavior="Stop"
                                        Storyboard.Target="StaticResource borderBackground"
                                        Storyboard.TargetProperty="Color"
                                        To="#FF0062B6" />
                                </Storyboard.Children>
                            </Storyboard>
                        </ControlTemplate.Resources>
                        <ControlTemplate.Triggers>
                            <Trigger
                                Property="ButtonBase.IsPressed"
                                Value="True">
                                <Trigger.EnterActions>
                                    <BeginStoryboard
                                        Storyboard="StaticResource ButtonPressed" />
                                </Trigger.EnterActions>
                                <Trigger.ExitActions>
                                    <BeginStoryboard
                                        Storyboard="StaticResource ButtonReleased" />
                                </Trigger.ExitActions>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Button.Resources>
    <DockPanel>
        <TextBlock
            x:Name="TextContent"
            FontSize="28"
            Foreground="White">Test</TextBlock>
    </DockPanel>
</Button>

【讨论】:

我试图弄清楚如何做你所做的,但不知何故搞砸了。那时我也偶然发现了模板元素的传递。 问题是如果我把发光和故事板放在外面,故事板会在页面上的所有按钮上触发,它们都会发光! Shimmy,你把它们放在“外面”多远?我上面的示例包含单个ButtonResources 内的所有内容。如果您将所有内容都放在WindowResources 中,我希望看到您所描述的内容。 Storyboard 需要留在 ControlTemplate 内,以便每个 Button 都有自己的,并且它们不都共享 1 个实例。 是否可以使用 double 类型的资源来执行此操作? (例如,对模板内元素的不透明度进行动画处理)【参考方案3】:

我想刚刚遇到了这个问题。

关于此事,请参阅我的博客文章:http://www.cplotts.com/2008/09/26/dr-wpf-namescopes/

基本上,诀窍是您需要使用一个参数调用 Begin,该参数是故事板所针对的同名范围内的对象。

特别是,从上面的示例中,我会尝试调用 Begin 并发送对模板中 _background 元素的引用。

如果这不能解决您的问题,请告诉我。

更新:

我比我更喜欢 Erickson 的解决方案……而且它也对我有用。我不知道我是怎么错过 Begin 方法的重载的!

【讨论】:

问题是所有动画都在控件模板中。我必须将两个 (_xamlButton, _xamlButton.Template) 都传递给 begin 方法。类似的问题,不完全相同。 您是否尝试过我的建议?我敢打赌它会为我制作动画的东西工作......也在控制模板中。不过,我更喜欢你的方法。 有没有一种方法可以做到这一点? 嗯...我不知道...名称范围隐含在您如何构建 xaml 中。如果您找到方法,请在此处评论!【参考方案4】:

(@Sam Meldrum) 要停止工作,请在开头添加 'true for "isControllable"

pressedButtonStoryboard.Begin(_xamlButton, _xamlButton.Template);

改成

pressedButtonStoryboard.Begin(_xamlButton, _xamlButton.Template,true);

现在

pressedButtonStoryboard.Stop(xamlButton)

会起作用

【讨论】:

【参考方案5】:

我也遇到了这个错误。我的情况有点不同,也许更简单。我有一个 WPF 窗口,上面有一个带有动画的模板。然后,我在窗口本身上为按钮定义了由 MouseEnter 触发的单独的完全不相关的动画。我开始收到“在名称范围内找不到 button1”。在这里玩了一些想法并调试了实际的 Namescope 之后(关注 NameScope.GetNameScope(this) 的结果,我终于发现解决方案是:

 this.RegisterName("button1", this.button1);

在代码中定义并附加到按钮的 MouseEnter 方法中。此 MouseEnter 将在 xaml 触发器之前调用。奇怪的是,如果 register 方法在构造函数或 Window.Activated() 方法中,则它不起作用。希望这对某人有所帮助。

【讨论】:

以上是关于故事板找不到 ControlTemplate 元素的主要内容,如果未能解决你的问题,请参考以下文章

无名板找驱动

WPF:为啥我不应该在 ControlTemplate 中使用 TemplateBinding Margin - Margin 是不是仅适用于元素的容器?

背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中的元素(代码片

请教WPF高手,如何使ControlTemplate内的元素自动适应整个控件的大小?

量角器+故事书:失败:使用定位器找不到元素:By(css选择器)

点击手势在collectionView Cell中不起作用,在故事板添加的单元格上都看不到任何UI元素