Storyboards can't find ControlTemplate elements
Solution 1
Finally found it. When you call Begin on storyboards that reference elements in the ControlTemplate, you must pass in the control template as well.
Changing:
pressedButtonStoryboard.Begin(_xamlButton);
To:
pressedButtonStoryboard.Begin(_xamlButton, _xamlButton.Template);
Fixed everything.
Solution 2
I made it work by restructuring the XAML so that the SolidColorBrush
and OuterGlowBitmapEffect
were resources of the button and thus referenced are shared by the Storyboard
s and the elements they're applied to. I retrieved the Storyboard
and called Begin()
on it just as you did, but here is the modified XAML for the Button
:
(Please note the keys "buttonGlow"
and "borderBackground"
and all StaticResource
markup extensions referencing them.)
<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>
Solution 3
I think just had this problem.
Let me refer you to my blog entry on the matter: http://www.cplotts.com/2008/09/26/dr-wpf-namescopes/
Basically, the trick is that you need to call Begin with an argument that is an object in the same name scope that the storyboards are targeting.
In particular, from your sample above, I would try to call Begin and send in a reference to the _background element in your template.
Let me know if this doesn't solve your problem.
Update:
I like Erickson's solution better than mine ... and it worked for me too. I don't know how I missed that overload of the Begin method!
Solution 4
(@ Sam Meldrum) To get STOP working, add 'true for "isControllable" at the begin
pressedButtonStoryboard.Begin(_xamlButton, _xamlButton.Template);
change to
pressedButtonStoryboard.Begin(_xamlButton, _xamlButton.Template,true);
and now
pressedButtonStoryboard.Stop(xamlButton)
will work
Solution 5
I ran into this error as well. My situation is a bit different, perhaps simpler. I have a WPF window that has a template with an animation on it. I then had a separate completely unrelated animation triggered by MouseEnter defined for a button, both on the window itself. I started getting 'button1 cannot be found in the namescope'. After playing around a bit with some of the ideas here and debugging the actual Namescope (put a watch on the result of NameScope.GetNameScope(this), I finally found the solution was to put:
this.RegisterName("button1", this.button1);
in a MouseEnter method defined in code and attached to the button. This MouseEnter will be called before the xaml Trigger. Curiously, the register method does not work if it is in the constructor or Window.Activated() method. Hope this helps someone.
Kris Erickson
Full Stack developer, in spare time blogger about programming and builder of things (Recipe Folder for example).
Updated on June 19, 2022Comments
-
Kris Erickson almost 2 years
I've created some fairly simple XAML, and it works perfectly (at least in KAXML). The storyboards run perfectly when called from within the XAML, but when I try to access them from outside I get the error:
'buttonGlow' name cannot be found in the name scope of 'System.Windows.Controls.Button'.
I am loading the XAML with a stream reader, like this:
Button x = (Button)XamlReader.Load(stream);
And trying to run the Storyboard with:
Storyboard pressedButtonStoryboard = Storyboard)_xamlButton.Template.Resources["ButtonPressed"]; pressedButtonStoryboard.Begin(_xamlButton);
I think that the problem is that fields I am animating are in the template and that storyboard is accessing the button.
Here is the 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>
Any suggestions from anyone who understands WPF and XAML a lot better than me?
Here is the error stacktrace:
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()
-
Kris Erickson over 15 yearsThe problem was that everything that was being animated was in the control template. I had to pass both (_xamlButton, _xamlButton.Template) into the begin method. Similar problem, not exactly the same.
-
Joel B Fant over 15 yearsOh. That is much easier. Learn something new every day.
-
Kris Erickson over 15 yearsI was trying to figure out how to do what you did, but had messed it up somehow. That is when I stumbled over the passing in the template element as well.
-
cplotts over 15 yearsDid you try what I suggested at all? I bet it would have worked for the stuff that was being animated for me ... was also in the control template. However, I like your method much better.
-
Sam Meldrum almost 15 yearsSolved my problem. But calling Stop() doesn't Stop my animation.
-
Shimmy Weitzhandler about 14 yearsThe problem is that if I place the glow and storyboards outside, the storyboard is triggered on ALL the buttons on the page and they all get the glow!
-
Shimmy Weitzhandler about 14 yearsis there a xamly way to do this?
-
cplotts about 14 yearsHmmm ... not that I know of ... the namescopes are implicit in how you build up your xaml. Comment back here if you find a way!
-
Joel B Fant about 14 yearsShimmy, how far 'outside' did you put them? My example above has everything inside the
Resources
of a singleButton
. If you put everything asResources
of theWindow
, I would expect to see what you describe. TheStoryboard
needs to stay inside theControlTemplate
so that eachButton
gets its own and they're not all sharing 1 instance. -
Jared Thirsk about 12 yearsIs there a way to do this in XAML?
-
Jared Thirsk about 12 yearsIs it possible to do this with a resource of type double? (For example, animating the opacity of an element inside a template)