WPF Animations and Performance#

I’ve been working on a WPF application that is fully skinned to make everything in the application look custom. WPF makes this really easy…almost too easy. We’ve been adding a lot of animations and storyboards to make transitions between screens and long running operations look much better. Everything worked perfectly, but we were getting some complaints from customers with older computers and slower video cards. Everything on the computer ran slower with our application running; much slower than I would have expected. The performance problems would persist even when our application was idle.

A while back, I added a cheap GeForce 8400GS to my workstation for my 3rd and 4th monitors so I decided to run our application on it to see if it was slow too. I use EVGA Precision to tweak my video cards and it has a GPU usage graph, so I fired up our application and monitored it with EVGA Precision. I could see excessive GPU usage when our application was running on this card (up to 70% GPU usage while the application is idle). I could even see consistent GPU usage on faster video cards (in the 5% range).

Something was obviously going on in the background. Our application does medical imaging, so my first thought was that we had something running in the background. But, running a profiler on the application showed that our background threads weren’t doing anything. What else could be going on?

On a whim, I disabled all of our animations. The GPU usage went to 0%. We are obviously doing something wrong with the animations. After some googling, I learned that WPF storyboards and animations keep running even when the element being animated is not visible. Many of our recent storyboards were started on the ContentControl.Loaded event and the animations were set to have a RepeatBehavior of Forever. I changed all of our storyboards to begin when needed and to stop when not needed. This change kept our GPU usage at 0% and made our users much happier.

Much of our storyboard and animation XAML code was pulled directly from blog posts and samples found on the internet. I really learned my lesson this time:

Thou shall understand your technology before using (and abusing) it.
.NET | WPF
Wednesday, November 24, 2010 2:38:45 PM (Mountain Standard Time, UTC-07:00) #    Comments [0]  | 

 

WPF Parent of a Specific Type#
I've been doing a lot of WPF work lately and ran across a situation where I need to get a reference to a specific type of object up the control hierarchy.  I didn't want to have everything register with everything else to get this functionality so I wrote this little method to walk up the hierarchy and return the first instance of the type that is found.  You can use it by simply adding this method to the class that you need and then calling it with the type you're looking for as the generic T.
private T GetParent<T>() where T : class
{
  FrameworkElement parent = this.Parent as FrameworkElement;
  while((parent.Parent as FrameworkElement) != null)
  {
    parent = parent.Parent as FrameworkElement;
    if(parent is T)
    {
      break;
    }
  }
  return parent as T;
}
This isn't too fancy, but someone else may find it useful.

Monday, December 15, 2008 3:10:56 PM (Mountain Standard Time, UTC-07:00) #    Comments [0]  | 

 

Testing Installations using Virtual Machines and Undo Disks#
I’ve begun to love Virtual PC and undo disks.

The application I am working on right now is distributed to locations that don’t typically have an IT person on staff.  We need to make sure the installation of our software is as painless as possible.  Our software also has an auto-update feature so it can automatically pull down the latest version and update itself.

I’ve been using Virtual PC and undo disks to test the install and update process.  The undo disks make things so easy.  After I’m done testing the install/update, I simply close the VM and select “Turn off and delete changes”.  My VM is still in its initial state before the install/update.

This is handy when you need to duplicate configurations on different OS’s so you can test.  I have configurations for XP, Vista, server 2003, etc.  Each OS has several VM’s for the different configurations we need to handle (.NET, no .NET, SQL Express, no SQL Express, etc).  When I come across a new configuration that behaves differently, I simply create the VM and I’m ready to test to my heart’s content.

The only thing I haven’t been able to test using this method is installing on both x86 and x64 (VPC is a 32-bit application).  One other issue that you may run across is disk space problems.  I recently got a 250GB drive so I don’t need to worry about disk space usage so much.  I’m also using vOptimizer to compact the size of the VHD files.

This is the best way I've found to test installations.  When will someone figure out how to unit test an InstallShield installer?  :-)

Tuesday, December 09, 2008 2:01:34 PM (Mountain Standard Time, UTC-07:00) #    Comments [0]  | 

 

Unnecessary Technical Debt#
I recently started a new job and was working with some of the existing code that didn't have much logging (it didn't have ANY logging).  I was trying to debug an issue on a non-development machine and needed some way to figure out what was going on.  I was in a hurry to get the thing working because some clients were waiting on us.  So I quickly added some EventLog.Write() logging statements to the code to debug it.  This worked great at the time and I made a note to update it to log4net as soon as possible.

A few weeks passed and I hadn't been able to fix the logging but it wasn't causing any problems so "out of sight == out of mind".  Then, we suddenly started having all kinds of issues on the machine where this was installed.  Things simply weren't working and we weren't getting any messages in the event log like we should.  I spent at least an hour trying to figure out what was going on.  Finally, I noticed the last entry in the event log was from several days ago.  The event log was full and wasn't set to over-write events as needed.

So, my "harmless" log statements ended up being not so "harmless" after all.  I could have spent an extra 10 minutes and used log4net from the beginning.  The moral of this story is: don't take shortcuts and incur technical debt unless you have a really good reason.

.NET | Design
Monday, December 08, 2008 3:21:35 PM (Mountain Standard Time, UTC-07:00) #    Comments [0]  | 

 

Unit Testing Workflow Foundation Rules#

This post discusses writing unit tests against Windows Workflow Foundation rules outside of the workflow runtime.  I had to do this for a project recently and didn’t find very many good resources on the net, so hopefully someone will find this useful.  See the notes at the bottom of this post that discuss why unit testing rules may not be a good idea.

 

I am loading the RuleDefinitions into an object in the unit test constructor.  I'm doing this work in the constructor because the rules don’t change during execution and I don’t want to incur this overhead during every test execution.

private RuleDefinitions ruleSetDefinitions;

public MainWorkflowTest()
{
    WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
    // The rules are embedded into the DLL, so I’m just reading the resource stream
    Stream rulesResource = Assembly.GetAssembly(typeof(MyWorkflowClass)).GetManifestResourceStream("MyWorkflowClass.rules");
    XmlReader reader = XmlReader.Create(rulesResource);
    ruleSetDefinitions = serializer.Deserialize(reader) as RuleDefinitions;
}

 

I created a method to run the rules and report any exceptions.  This method is really just a helper so I don’t have this embedded into all of my test methods.  Notice how I’m using LINQ to query the RuleSetDefinition for the RuleSet I would like to execute; the more I use LINQ, the more I like it :-)

public void RunRuleSet(MyWorkflowClass workflow, string ruleSetName)
{
    var rules = from rs in ruleSetDefinitions.RuleSets
                where rs.Name == ruleSetName
                select rs;
    RuleSet ruleset = rules.First<RuleSet>();
    RuleValidation validation = new RuleValidation(typeof(MyWorkflowClass), null);
    RuleExecution execution = new RuleExecution(validation, workflow);
    try
    {
        ruleset.Execute(execution);
    }
    catch(Exception e)
    {
        if(validation.Errors.Count > 0)
        {
            Assert.Fail(validation.Errors[0].ErrorText);
        }
        Assert.Fail(e.Message);
    }
}

 

Finally, I can run the tests against the RuleSet like this:

MyWorkflowClass wf = new MyWorkflowClass();
// Do any setup of the workflow; setting variables, etc
RunRuleSet(wf, “NameOfTheRuleSetToExecute”);
// Perform any assertions to make sure the rule worked as expected

 

It's very easy to run rules outside of the Workflow Foundation runtime.  I found it nice because I could test individual rules easily.  But, this could be very useful for applications that need to load rules files at runtime and allow someone to change the rules outside of typical “code”.

 

Let the buyer beware

Running unit tests against your rules may or may not be a good idea.  I totally agree with everything Mike says about it.  In general, you want to be very careful about unit testing rules because they are so easy to change and it can be very difficult to write the tests correctly (especially when you get into chaining and re-evaluation).

 

In my situation, I had some state regulations that needed to be followed so I decided the rules were worthy of unit tests.  The major reasons for this decision are the fact that the rules won’t change frequently and the consequences of the rules being wrong were fairly severe.

 

Tuesday, June 10, 2008 10:19:02 AM (Mountain Standard Time, UTC-07:00) #    Comments [0]  | 

 

All content © 2013, Rob Mulcahey
On this page
This site
Calendar
<May 2013>
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
Archives
Sitemap
Blogroll OPML
Disclaimer

Powered by: newtelligence dasBlog 2.0.7226.0

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Send mail to the author(s) E-mail

Theme design by Jelle Druyts


Pick a theme: