views:

485

answers:

0

I'm using multiple ResourceDictionarys to enable skinning in my WPF application. I have a button that's using WPF Toolkit's VisualStateManager to animate state changes. Great!

Now, when the button is pressed, the style changes by loading a different ResourceDictionary. Now the problem comes when the button's Storyboard for transitioning from pressed to unpressed state tries to access the theme's style during the time which the ResourceDictionary doesn't exist.

Here's the code that loads the new style:

Uri uri = new Uri(..., UriKind.Relative);
Resources.MergedDictionaries.Clear();
Resources.MergedDictionaries.Add(Application.LoadComponent(uri) as ResourceDictionary);

I've tried removing the Resources.MergedDictionaries.Clear(); line, and that doesn't fix my problem (I figured, if I didn't remove it, it wouldn't throw the exception, right? wrong).

Here's the exception that I'm getting:

System.InvalidOperationException was unhandled
  Message="'Border' name cannot be found in the name scope of 'System.Windows.Controls.Border'."
  Source="PresentationFramework"
  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, HandoffBehavior handoffBehavior, Boolean isControllable)
   at System.Windows.VisualStateGroup.StartNewThenStopOld(FrameworkElement element, Storyboard[] newStoryboards) in C:\dd\WPF_1\src\wpf\src\ControlsPack\WPFToolkit\VSM\VisualStateManager\System\Windows\VisualStateGroup.cs:line 102
   at System.Windows.VisualStateManager.<>c__DisplayClass3.<GoToStateInternal>b__0(Object sender, EventArgs e) in C:\dd\WPF_1\src\wpf\src\ControlsPack\WPFToolkit\VSM\VisualStateManager\System\Windows\VisualStateManager.cs:line 264
   at System.Windows.Media.Animation.Clock.FireEvent(EventPrivateKey key)
   at System.Windows.Media.Animation.Clock.RaiseAccumulatedEvents()
   at System.Windows.Media.Animation.TimeManager.RaiseEnqueuedEvents()
   at System.Windows.Media.Animation.TimeManager.Tick()
   at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
   at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
   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.DispatcherOperation.InvokeImpl()
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(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.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
   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.TranslateAndDispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Application.RunInternal(Window window)
   at SampleThemedApp.App.Main() in C:\VSProjects\ShadesOfGreyStyles\ShadesOfGreyStyles\obj\Debug\App.g.cs:line 0
   at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

I'm thinking that the easiest way to fix this would be to stop all Storyboards, but I don't think there's an easy way to do that. I've tried "taking off" the animation from Pressed to * states, but there's no real good way to do that using VisualStateManager. I'm just setting Duration to 00:00:00.

So, is there a way to ignore this exception? I've tried wrapping the code that loads the styles in a try {} catch {} block, but it doesn't throw from there.

EDIT: Forgot to mention that this exception doesn't get thrown if I don't style the button that changes the ResourceDictionary.