Just thought I’d put out some quick WPF performance statistics thanks to Microsoft. You can download the entire slideshow
here.
- DependencyProperty is x3 faster than INotifyPropertyChanged
- ObservableCollection accesses single items 90 times faster than List
- ObjectDataProvider is x20 smaller than XmlDataProvider
Microsoft also have some other good tips over here too.
I’d like to see some real world statistics on the differences between using static vs dynamic resources too. Anybody know of any?
Further to Gerrod’s post on selecting an item in a treeview, I found myself scratching my head on how to find a treeviewitem’s parent item. Here I was expecting a TreeViewItem.Parent property. Unfortunately after scouring the dark depths of the internet, I found that using the VisualTreeHelper class was the answer:
private static TreeViewItem GetParentTreeViewItem(DependencyObject item)
{
if (item != null)
{
DependencyObject parent = VisualTreeHelper.GetParent(item);
TreeViewItem parentTreeViewItem = parent as TreeViewItem;
return parentTreeViewItem ?? GetParentTreeViewItem(parent);
}
return null;
}
I’m sure this can be easily converted into an extension method for those of you expecting the Parent property like I was.
One thing that I find myself doing all the time is creating some type of base class for my windows/controls in WPF:
namespace Editors {
public class EntityEditorControlBase<TModel> : UserControl
where TModel : class, IEntityEditorModel {
public TModel Model {
get { return DataContext as TModel; }
protected set { DataContext = value; }
}
}
}
Since this is a generic control you need to specify the concrete type arguments when you subclass it. You can do this in your WPF markup via the x:TypeArguments attribute:
<Editors:EntityEditorControlBase
x:Class="ConcreteEntityEditorControl"
x:TypeArguments="Models:ConcreteEntityEditorControlModel"
xmlns:Editors="clr-namespace:Editors">
<UserControl.Resources>
<ResourceDictionary Source="../Resources/EditorResources.xaml" />
</UserControl.Resources>
<!-- control content here -->
</Editors:EntityEditorControlBase>
Two important things to note:
- When you want to attach a resource dictionary to the class, you need to do so using the <UserControl.Resources> tag
- In your base class control, make sure you include the [ContentProperty("Content")] and [DefaultProperty("Content")] tags on your class to avoid the horrible “The type ‘{0}’ does not support direct content” error.
I have to admit that I much prefer WPF over Windows Forms (but prefer ASP.Net to either). However, the programming model is still a bit immature (in my opinion), and sometimes things that you wish were simple just aren’t. Case and point: trying to programmatically select an item in a TreeView control; it just ain’t easy!
Anyway, after scrubbing the web and finding a few solutions that really didn’t appeal (e.g. using reflection; surely it’s not that hard!) I came up with this extension method which does the trick quite nicely.
/// <summary>
/// Walks the tree items to find the node corresponding with
/// the given item, then sets it to be selected.
/// </summary>
/// <param name="treeView">The tree view to set the selected
/// item on</param>
/// <param name="item">The item to be selected</param>
/// <returns><c>true</c> if the item was found and set to be
/// selected</returns>
static public bool SetSelectedItem(
this TreeView treeView, object item) {
return SetSelected(treeView, item);
}
static private bool SetSelected(ItemsControl parent,
object child) {
if (parent == null || child == null) {
return false;
}
TreeViewItem childNode = parent.ItemContainerGenerator
.ContainerFromItem(child) as TreeViewItem;
if (childNode != null) {
childNode.Focus();
return childNode.IsSelected = true;
}
if (parent.Items.Count > 0) {
foreach (object childItem in parent.Items) {
ItemsControl childControl = parent
.ItemContainerGenerator
.ContainerFromItem(childItem)
as ItemsControl;
if (SetSelected(childControl, child)) {
return true;
}
}
}
return false;
}
(Forgive formatting; the code window is only so-wide.)
The trick, you see, is to use the ItemContainerGenerator on the ItemsControl – which TreeView and TreeViewNode both inherit from – to try to find the container for the item you are selecting. This will only work for the immediate children of the control that you’re calling it on – so asking your root node for the container for an item which is three nodes deep is fruitless; hence, you have to walk down the tree asking each branch node if it contains the item.
It’s possibly not the fastest executing code in the world – walking a tree rarely is – but you could speed things up if you knew where the parent node was; then you could just call the recursive method directly.
Enjoy!
I’ve been focusing a lot (read: “learning”) on WPF lately, and one thing that crops up all the time is StaticResource and DynamicResource. I had tried to infer their usage/differences from the context of where I’d seen them used, but I could never quite get it right. Anyway, I just read a nice definition which makes it all rather clear:
Static resources are resolved at compile time, whereas dynamic resources are resolved at runtime.
Use DynamicResources when the value of the resource could change during the lifetime of the Application.
Use StaticResources when it’s clear that you don’t need your resource re-evaluated when fetching it – static resources perform better than dynamic resources.