Ivaylo Bratoev's blog Ivaylo Bratoev's blog http://blogs.telerik.com/IvayloBratoev/Posts.aspx http://backend.userland.com/rss Caveats with WPF dynamic resources and animations. <p>Recently we've been building some cool stuff in WPF with <a href="http://msdn.microsoft.com/en-us/library/ms750613.aspx">resources</a> and <a href="http://msdn.microsoft.com/en-us/library/ms752312.aspx">animations</a>. In this post I will share some experience with a bug from our code base I fought recently. The actual code is complex, so here is a simple example that I used when hunting the nasty bug (source code is in the bottom of the page):</p> <div style="font-size: 10pt; background: #404040; padding-bottom: 0px; color: #e0e0e0; line-height: 1em; font-family: consolas"> <p style="margin: 0px"><span style="color: #40c4ff">&lt;Window</span><span style="color: #eee8aa"> x</span><span style="color: #40c4ff">:</span><span style="color: #eee8aa">Class</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;WpfApplication1.Window1&quot;</span></p> <p style="margin: 0px">&#160;&#160; <span style="color: #eee8aa">xmlns</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></p> <p style="margin: 0px">&#160;&#160; <span style="color: #eee8aa">xmlns</span><span style="color: #40c4ff">:</span><span style="color: #eee8aa">x</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span></p> <p style="margin: 0px">&#160;&#160; <span style="color: #eee8aa">Title</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;Window1&quot;</span><span style="color: #eee8aa"> Height</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;300&quot;</span><span style="color: #eee8aa"> Width</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;300&quot;</span><span style="color: #40c4ff">&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;Window.Resources&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;Style</span><span style="color: #eee8aa"> TargetType</span><span style="color: #40c4ff">=&quot;{</span><span style="color: #60ff60">x</span><span style="color: #40c4ff">:</span><span style="color: #60ff60">Type</span><span style="color: #40c4ff"> Rectangle}</span><span style="color: #60ff60">&quot;</span><span style="color: #eee8aa"> x</span><span style="color: #40c4ff">:</span><span style="color: #eee8aa">Key</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;RectangleStyle&quot;</span><span style="color: #40c4ff">&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;Setter</span><span style="color: #eee8aa"> Property</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;Fill&quot;</span><span style="color: #eee8aa"> Value</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;Blue&quot;</span><span style="color: #40c4ff"> /&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;/Style&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;/Window.Resources&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;Grid</span><span style="color: #eee8aa"> Name</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;testGrid&quot;</span><span style="color: #40c4ff"> &gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;Rectangle</span><span style="color: #eee8aa"> x</span><span style="color: #40c4ff">:</span><span style="color: #eee8aa">Name</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;rectangle&quot;</span><span style="color: #eee8aa"> Margin</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;100&quot;</span><span style="color: #eee8aa"> Style</span><span style="color: #40c4ff">=&quot;{</span><span style="color: #60ff60">DynamicResource</span><span style="color: #40c4ff"> RectangleStyle}</span><span style="color: #60ff60">&quot;</span><span style="color: #40c4ff">&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;Rectangle.Triggers&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;EventTrigger</span><span style="color: #eee8aa"> RoutedEvent</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;Mouse.MouseLeave&quot;</span><span style="color: #40c4ff">&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;BeginStoryboard&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;Storyboard&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;ColorAnimation</span><span style="color: #eee8aa"> Duration</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;00:00:00.5&quot;</span><span style="color: #eee8aa"> From</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;Blue&quot;</span><span style="color: #eee8aa"> To</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;Red&quot;</span></p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #eee8aa">Storyboard.TargetProperty</span><span style="color: #40c4ff">=</span><span style="color: #60ff60">&quot;(Rectangle.Fill).(SolidColorBrush.Color)&quot;</span></p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #eee8aa">AutoReverse</span><span style="color: #40c4ff"> =</span><span style="color: #60ff60"> &quot;True&quot;</span><span style="color: #40c4ff">/&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;/Storyboard&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;/BeginStoryboard&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;/EventTrigger&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;/Rectangle.Triggers&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160;&#160;&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;/Rectangle&gt;</span></p> <p style="margin: 0px"><span style="color: #60ff60">&#160;&#160;&#160; </span><span style="color: #40c4ff">&lt;/Grid&gt;</span></p> <p style="margin: 0px"><span style="color: #40c4ff">&lt;/Window&gt;</span></p> </div> <p>&#160;</p> <p>What we have here - a very simple windows with a <strong>Grid</strong> and a <strong>Rectangle</strong> in it. The important things here are:</p> <ul> <li>The Rectangle has a style set through a <strong>DynamicResource</strong>. The style sets the <strong>Fill </strong>property. </li> <li>We have an event trigger for the <strong>MouseLeave</strong> event. On that trigger we start a color animation that changes the <strong>Fill </strong>property of the <strong>Rectangle</strong>. </li> </ul> <p>&#160;</p> <p>Everything seems perfectly normal for now, right? Ok, let's add some C# to the picture:</p> <div style="font-size: 10pt; background: #404040; padding-bottom: 0px; color: #e0e0e0; line-height: 1em; font-family: consolas"> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #40c4ff">protected</span> <span style="color: #40c4ff">override</span> <span style="color: #40c4ff">void</span> <span style="color: #eee8aa">OnKeyDown</span>( <span style="color: #66cdaa">KeyEventArgs</span> <span style="color: #eee8aa">e</span> )</p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; {</p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #40c4ff">base</span><span style="color: silver">.</span><span style="color: #eee8aa">OnKeyDown</span>( <span style="color: #eee8aa">e</span> ); </p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #40c4ff">if</span> ( <span style="color: #eee8aa">testGrid</span><span style="color: silver">.</span><span style="color: #eee8aa">Children</span><span style="color: silver">.</span><span style="color: #eee8aa">Contains</span>( <span style="color: #eee8aa">rectangle</span> ) )</p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {</p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #eee8aa">testGrid</span><span style="color: silver">.</span><span style="color: #eee8aa">Children</span><span style="color: silver">.</span><span style="color: #eee8aa">Remove</span>( <span style="color: #eee8aa">rectangle</span> );</p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #40c4ff">else</span></p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {</p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style="color: #eee8aa">testGrid</span><span style="color: silver">.</span><span style="color: #eee8aa">Children</span><span style="color: silver">.</span><span style="color: #eee8aa">Add</span>( <span style="color: #eee8aa">rectangle</span> );</p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</p> <p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; }</p> </div> <p>&#160;</p> <p>The code is very simple - we just remove the <strong>Rectangle </strong>from the <strong>Grid</strong>'s children if it is there, and add it back if it is already removed. And... we are ready. Let's see the bug - start the project, hold any key (space is good candidate) and in the same time move the mouse over the <strong>Rectangle</strong>. BOOM - exception :) It says: &quot;<em>System.InvalidOperationException: 'Fill' property does not point to a DependencyObject in path '(0).(1)'.</em>&quot; So where exactly is the problem? To answer the question I will explain when exactly the exception is thrown:</p> <p>1. The mouse leaves the <strong>Rectangle </strong>and the animation changing the <strong>Fill</strong> color is started.</p> <p>2. While the animation is working the <strong>Rectangle</strong> is removed from the <strong>Grid's </strong>logical tree.</p> <p>3. When the <strong>Rectangle </strong>is removed, the style is applied again (because it is a <strong>DynamicResource</strong>). The <strong>DynamicResource</strong> starts searching up the logical tree, but as the <strong>Rectangle </strong>has already been removed from the <strong>Grid</strong>, the <strong>RectangleStyle </strong>is not found, it is not applied and the <strong>Fill </strong>property is not set.</p> <p>4. In the same time the animation keeps working and tries to access <strong>Fill</strong> property as a <strong>SolidColorBrush</strong> and... the Exception.</p> <p>&#160;</p> <p>So how can we fix that? I can propose a few solutions, but I am sure you can think of even more:</p> <p>1. Replace the <strong>DynamicResource</strong> with <strong>StaticResource. </strong>The static resource is applied statically at load time and is not updated, so this completely solves the problem. Actually, this is the preferred approach if you do not need to update the style dynamically.</p> <p>2. If you need the functionality of <strong>DynamicResource</strong> - move the animation in the style. When the <strong>Rectangle</strong>'s<strong> </strong>parent is changed the style is unset, and because the animation is in the style it is removed as well.</p> <p>&#160;</p> <p>So that's it - the bug was discovered and smashed. Any comments/ideas are highly appreciated.</p> <p>Here is the <a href="http://blogs.telerik.com/photos/storage/bratoev/Caveats with WPF dynamic resource and animations/Caveats with WPF dynamic resources and animations - sample.zip">sample code</a>.</p> <p>Happy coding!</p> http://blogs.telerik.com/IvayloBratoev/Posts/08-06-27/caveats_with_wpf_dynamic_resources_and_animations.aspx bratoev http://blogs.telerik.com/IvayloBratoev/Posts/08-06-27/caveats_with_wpf_dynamic_resources_and_animations.aspx 4d368ebc-f015-486f-9fa2-df654e1d4201 Fri, 27 Jun 2008 05:25:03 GMT Tip of the Day: Remove the most annoying Visual Studio shortcut - F1 <p>Have you pressed <strong>F1</strong> in Visual Studio? Did you wait a couple of minutes cursing it? I did. And I found a cure, a very simple cure - remove the F1 shortcut. </p> <p>Here are the simple steps: in Visual Studio -&gt; Tools -&gt; Option -&gt; Keyboard -&gt; find Help.F1Help shortcut -&gt; remove F1 key binding.</p> <p><a href="http://blogs.telerik.com/Libraries/MetaBlog/WindowsLiveWriter-TipoftheDayRemovethemostannoyingVisualSt_B245-image_4.sflb"><img height="335" border="0" width="574" src="http://blogs.telerik.com/Libraries/MetaBlog/WindowsLiveWriter-TipoftheDayRemovethemostannoyingVisualSt_B245-image_thumb_1.sflb" alt="image" style="border-width: 0px;" /></a> </p> <p>You are cured!</p> http://blogs.telerik.com/IvayloBratoev/Posts/08-06-19/tip_of_the_day_remove_the_most_annoying_visual_studio_shortcut_-_f1.aspx bratoev http://blogs.telerik.com/IvayloBratoev/Posts/08-06-19/tip_of_the_day_remove_the_most_annoying_visual_studio_shortcut_-_f1.aspx 4f9e67f0-85c4-4603-9255-d966bc9efff4 Thu, 19 Jun 2008 04:40:30 GMT