In general, beware of memory leaks I. Fix Binding Errors and Exceptions Every time a binding error occurs, your app hangs for just a split second as it writes out errors to the trace log. If you have a lot of binding errors, then those split seconds start to add up.
Make sure to go through your bindings, especially those on ItemsControls ListViews, custom grids, etc. Open up your app in the debugger and play around, especially where there is slowness. Make sure all bindings resolve without errors. RelativeSource in DataTemplates may also result in bindings that break initially, but then later resolve properly. Be wary of them, and try to use inherited attached properties instead of relying on RelativeSource in DataTemplates.
Viewmodel bindings Make sure that your views and view models are in sync. Use ReSharper 6 to help you find broken bindings. These have a cost too. This essentially pushes property values down the visual tree instead of searching up. Hard-code sizes where possible This may not always be a practical or desirable solution, but layout passes perform faster when widths and heights do not have to be recalculated. They may also help stop a layout pass from rippling through an entire visual tree.
Add when the collection is data-bound can be a prohibitively expensive operation, especially with thousands of rows. Unfortunately, the framework provides no easy, satisfactory fix.
Use ObservableCollection as-is, but break bindings Break the binding to the collection. Update the collection while not data-bound. Create your own collection that implements INotifyCollectionChanged.
Raise INotifyCollectionChanged as sparingly as you can. Raise the event with a NotifyCollectionChangedAction. Reset event for anything more trivial than a simple single-item add, remove, change, or move. Do not take advantage of the NotifyCollectionChangedEventArgs constructors that take collections of items; you will find support for it spotty at best.
IList on your collection. WPF does not use the generic System. Avoid DynamicResources Even in. Avoid ResourceDictionary This advice is practically impossible to follow, but do your best. There is a huge cost in constructing ResourceDictionaries, and depending on where you place them, you are probably constructing many more objects than you realize.
A common, sensible, and logical pattern is to keep usages of elements as close to where you use them as possible. Many people place resources in UserControl. Resources, or break up their themes into multiple ResourceDictionaries for clarity and separation. Although this is arguably good programming practice, it also tends to be insanely slow. Collapse ResourceDictionaries as much as you can, and try to ensure that the contents of these dictionaries is only loaded once.
The easiest and surest way is to include it in the resources of your System. Application object, almost always difficult or infeasible for composite applications. Not necessary the healthiest design, but the performance is quite a bit better. Simplify your visual tree Shallow visual trees are better than deeper visual trees. Be wary of System. OnDetaching will generally not get called.
Put a breakpoint and see for yourself. The Unloaded event is a better place for that, but be aware that it will get raised every time the control is removed from the visual tree.
A better alternative is to rely on data binding where you can; create a DependencyProperty for the sole purpose of listening to changes on your target property, and use the change notifications in DependencyProperty in order to listen to changes on the target property.
It keeps the observed object generally, your view model from accidentally holding a strong reference to your view. Be careful of view model events If your views or behaviors rely on events being raised from a viewmodel as innocuous as INotifyPropertyChanged. CollectionChanged , subscribe to them weakly. BeginInvoke calls which is not as good. BeginInvokes into a single call, the more likely WPF will be able to help you out by making single subsequent layout and render passes, and the lower your overall CPU usage.
In general, beware of memory leaks This is a bit of a generalization of the last few points, but memory leaks make apps behave worse over time. Fixing memory leaks goes a long way in fixing the performance of an application. And since most developers are constantly restarting WPF apps as they work on them, they often go undetected until the software is delivered.