Thinking in WPF

It took me a long time to learn how to think in WPF.  I had spent years plunging into the depths of Windows Forms, and before that I learned the ropes of MFC.  Since WPF is a complete departure from the world of the HWND, most of my knowledge and “second instincts” gained from working with those other platforms had to be unlearned.  That’s not easy to do.

I realized the other day that my thinking about WPF has changed dramatically over the past five or six months.  Some of my older blog posts solve problems in ways that now seem to be “swimming upstream” to me.  Back then I was trying to solve WPF problems by applying a WinForms way of thinking.  I feel that now I have found the “spirit of WPF”, so to speak.

Below is a list of ten tips which, I feel, capture the essence of thinking in WPF.  This list is by no means complete or “correct.”  The tips are rules of thumb, not hard and fast absolutes. Take these ideas with a grain of salt; perhaps your way of approaching WPF is completely different than mine. 

  1. Do not hesitate to write code. Just because you can do so many things with XAML does not mean that you should.  WPF is an application development platform.  Applications are written in code, and use markup when appropriate. 
  2. Keep your XAML dumb.  Avoid being the geek who spends an hour concocting a dozen lines of abstruse XAML to do something which could easily be done with one or two lines of code.  XAML is great for declaring objects and the relationships between them.  It is possible to express behavior in XAML somewhat, but think twice before doing so.  Eventually your functional requirements might become more complicated, and you might find yourself rewriting that XAML logic in code anyways.  Always remember, there is no XAML debugger (except for your brain) and you cannot handle exceptions in XAML!
  3. Keep visual resources out of value converters.  You should avoid referencing brushes, images, colors, etc. in your value converter code.  Keep that stuff in XAML.  For instance, do not create a value converter which returns a brush.  Instead, create a value converter which returns a value that a trigger can use to select the appropriate brush.  Doing so makes the value converter more reusable, and allows you to keep brush declarations in the XAML file, where they belong.
  4. Create modular value converters. Avoid creating value converters which will only be used once.  It is better to build up a library of simple, modular value converters, which can be combined using the ValueConverterGroup.
  5. Expose functionality as services, not subclasses. Many features of WPF are exposed as services.  A service can be enabled for a particular element/control by setting an attached property on it.  Examples of this include validation, spellchecking, scrolling, drag-and-drop, and more.  It is preferable to expose extra functionality through one or more attached properties, as opposed to creating subclasses, so that the behavior can be used or not used with ease.  The consumer of that functionality will appreciate not having to change the type of element in his/her UI just to make use of it.  Also keep in mind that this “service oriented” approach is not always desirable or technically feasible.  It’s just a rule of thumb.
  6. Think thrice before creating a custom control.  It is rarely necessary to create a custom control in WPF.  Before you go ahead and subclass Control, consider your options.  Read this great article for an overview of what those options are: http://msdn.microsoft.com/msdnmag/issues/07/05/WPF/default.aspx
  7. Do not micromanage, let panels do the work. One of the best parts about WPF, in my opinion, is the layout system.  You put visual elements in a panel, and the panel manages the location and/or size of those elements for you.  You can put elements in a Canvas panel if you want to specify absolute coordinates for them, but you normally should not be doing so.  If you find that you are specifying coordinates for elements a lot, consider using other kinds of panels to make your life easier (and UIs better).
  8. Carefully consider where to put resources. The resource system in WPF is brilliant, if used properly.  When designing an application be sure to keep the hierarchical nature of resource lookups in mind so that you avoid duplicating brushes, images, data sources, etc.  Get into the habit of creating separate resource dictionaries for logically distinct resources.  You can use the MergedDictionaries property of ResourceDictionary to import physically separate resources at runtime.
  9. Strive for elegance, not eye candy.  With all of the visual goodies at your disposal it is tempting to add superfluous crap into a user interface.  Avoid this temptation.  If you find yourself adding animations that do not enhance the usability of a user interface, remove them.  Above all, keep it consistent. When you find a visual style which is appropriate for your application, create Styles that can be used to promote that look and feel throughout the application.  You don’t want your UI to look like a ransom note!
  10. Avoid being a Blender.  I am starting to see a lot of people who tinker with the Expression Blend program and suddenly call themselves WPF developers.  Blend is a nice comfy way to get familiar with many of the basics of WPF, but it is not a good way to really learn WPF.  If you want to really understand the platform, write your XAML by hand.  Look at the WPF assemblies in Reflector.  Subclass some WPF classes and see what it takes to customize their behavior.  Frequent the WPF Forum.  Read the documentation!  Those are the things that will truly show you how vast and incredible the platform is, not fiddling around in Blend.  In my opinion, Blend should be used as a productivity enhancer for people who already know WPF.

Happy coding!

22 Responses to Thinking in WPF

  1. Alan Cobb says:

    Hi Josh,

    Nice. A very thought-provoking list.

    “…there is no XAML debugger…”

    But given the huge amount of XAML that probably will be written over the next 20+ years, a lot of XAML “debugging” will still need to be done, by brain or otherwise.

    Which raises the question of how a “debugger” or debugging tools for XAML might work and what they might look like. I guess the main idea would be to try to easily associate run-time behavior including exceptions and other failures with specific pieces of XAML.

    Alan Cobb

  2. John Vanderburg says:

    Excellent guidelines. The learning curve of WPF is a steep one. I’ve spent way too much time trying to figuire out how to do something in XAML that would have only taken a few minutes to code. In time, you learn what to do in XAML (and how to do it) vs. code. Thanks!

  3. Thanks for your advices. I have not really start to develop with WPF so it’s a good think for me to read it.

  4. Josh Smith says:

    Alan,

    In addition to throwing a spotlight on the offending XAML, it would be nice if you could set a breakpoint inside of a Trigger (on the Setters).

    Josh

  5. Josh Smith says:

    John,
    I know the feeling. It is beneficial to figure out how to do things in XAML, but such “learning experiences” have no place in production code.🙂

    Matthieu,
    Thanks, I hope you find it informative and useful.

    Josh

  6. […] Bank « MIX07: Silverlight The Road to WPF Enlightenment May 1st, 2007 “Thinking in WPF” (Josh Smith) and Family.Show (Vertigo) both offer WPF […]

  7. Karl Shifflett says:

    Josh,

    Awesome work! I’m new to WPF and have read several WPF books and many online articles.

    My question is : Exception Handling. This is something I code day one. Almost every example application is void of exception handling.

    Example question : if my objectdatasource couldn’t connect to the database during a database operation, that exception could be caught in the object. What is the WPF way of displaying a message?

    Sorry for such a simple question.

    Thank you!

    Karl

  8. Josh Smith says:

    Karl,

    Good point. You just added another bullet to the list of reasons why WPF devs shouldn’t avoid using code. XAML has no exception handling support, so if the operation you are performing might throw one, don’t do it in XAML. In fact, that is such a good point that I’m going to add it into the blog entry!😀

    Regarding the “WPF way of displaying a message”…well there is no clear cut answer to that. You can use a MessageBox, but it does not look like a Vista messagebox. There is always the StatusBar, if the message isn’t too important. Vista has the Task Dialog, which look very nice but are a “Vista only” option. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/UxGuide/UXGuide/Resources/WhatsNewInVista/TaskDialogs.asp

    Thanks,
    Josh

  9. Karl Shifflett says:

    Josh,

    Thank you for the reply. I was thinking about exposing an area at the top of each form that when an exception occurs, display it. Sort of like the Validation Summary control in ASP.NET. I have one similar to this on my AJAX enabled forms for error reporting and to report successful database operations that the user initiated.

    No problem. Use the code.

    The question also came to mind about the validation pipeline that WPF uses. It’s expecting an exception be thrown from Business Objects if submitted data is invalid. I have not had time to figure out how to get into this pipeline, keep the current validation adorning on the control but also display a message at the top of the form that the user can see that is not a tooltip.

    Love WPF though. Have not looked at Orcas, trying to have fun with this version.

    Best to you,

    Karl

  10. […] posts, and samples.  Recently, Josh wrote 10 tips which he refers to as rules of thumb when thinking in WPF. Read his post to get the details on each of the tips […]

  11. Sacha Barber says:

    On the MessageBox thing for exceptions. Could you not use the WPF UIElement and have that shown with a margin that pops it into the same position every time, and of course the contents could display what ever you like.

    I have just used a popup control instead of a yes/no dialog quite happily. FYI josh this is in my next article at codeproject which I will publish today or tomorrow

  12. Josh Smith says:

    Sacha,

    I’m not sure what you’re referring to. This post does not discuss using a MessageBox to display exception messages.

    Josh

  13. Ruchi says:

    Hi,
    I am a new bee to WPF, I was just wondering is there any built in support for error handling other than try..catch of .net framework? actually I was trying to get asp.net like error handling functionlaity where we specify even the error code in configuration file and it takes us to proper page.

    Please help me in this issue.

    Thanks
    Ruchi

  14. Josh Smith says:

    Ruchi,

    WPF does not have an equivalent to ASP.NET’s error page functionality. It just uses standard try/catch/finally language syntax, and also there are some events which are raised when unhandled exceptions occur.

    Josh

  15. John "Z-Bo" Zabroski says:

    Josh,

    I was wondering if you still feel the same way about XAML that you did when you wrote this post?

    I’ve been working to push all UI-related stuff into XAML, contrary to your advice, so I’m interested to know if you’ve changed your mind. If so, why? Also, have you met others like me who want to push everything UI-related into XAML?

  16. Josh Smith says:

    John,

    I still think that XAML is not the appropriate place to put anything but the most simple conditional logic (i.e. triggers). XAML is a black box, which cannot be stepped through with a debugger, and has much less support for compile-time policing than code. However, I’m not quite clear on what you are referring to when you say “UI-related stuff” so perhaps we’re not talking about the same thing.

    Josh

  17. John "Z-Bo" Zabroski says:

    That’s interesting. In my experience, the one bug with XAML that catches me the most is a null pointers. I can’t easily inspect the datacontext to know that a binding isn’t possible, and what to do when it isn’t possible (fail-over strategies). This happens often with ItemsControls.

    By UI related, I mean totally separating the Developer and Designer stories. Having a file format to fully specify UI interaction, layout and positioning, accessibility, and brushes is critical to me to make this work.

    XAML may be a black box, but I’ve worked with black boxes before. What I really want is a miniature Expert System to help me identify common “Gotchas” that people do in XAML.

    What are is an example of *not* using XAML for the most simple conditional logic?

  18. Josh Smith says:

    One example is trying to disable a Save button if any of the input fields are empty. That logic should not exist in XAML, because it is more of a domain concern than a visualization concern.

  19. John "Z-Bo" Zabroski says:

    I see what you are saying, and to an extent I agree. Very few people understand how to correctly implement this logic.

    I recently read Extreme Swing Testing and the authors started the book out with an example they thought was an exemplary use case for unit tests. Except, it wasn’t. It was a lot like your Save button example: They wanted to ensure that, when a Form is shown to the user for the first time (focus), an “Apply Changes” button did not have default focus. The point was so that (1) users didn’t hit the space bar accidentally and (2) intercepting the Apply Changes command with a confirm dialog is a hamfisted approach.

    This really just beats on the drum that “automated testing” != “unit testing”, and that there are better ways to partition your logic than around “unit test-ability”. In my experience, knowing how to model problems modularly is more important than “listening to the tests”, so to speak.

    I’ve been toying with a convention-driven framework to automate some of this boilerplate, but it’s going slowly b/c of shifting priorities at work. When it’s done, though, it will be FLOSS. My boss already gave me the go ahead to release it and get community feedback on whether it’s a good idea or not.

  20. John "Z-Bo" Zabroski says:

    As a separate issue, I find there to be a dearth of material on XAML Best Practices. I’ve been working on that sort of stuff, like how to handle three-valued logics in various XAML scenarios. Obviously, the real issue is the data model is wrong, but sometimes there is data with “known unknowns” and the backing store representing that is just one field using three-valued logic.

  21. Josh Smith says:

    John,

    I, too, would love to see some best practice guidance for XAML from MSFT. I think it might be a while before such best practices emerge, especially since they would need to make sure that their tools adhere to those practices.

    Josh

  22. John "Z-Bo" Zabroski says:

    Well, on Page 398 of Essential WPF, Chris Anderson re-iterates your basic point to some extent: “Events allow us to connect an event handler to any objects to which the style is applied. Generally it is better to use commands to connect behavior to controls.”

    These are things that should be Line Items in an “Effective XAML” guide, not “by the ways” in a 500 page book.

%d bloggers like this: