Documentation != Help, or why visual studio sucks

Visual Studio 2005 has the terrible habit of opening the full msdn library whenever you press F1, which in my case is mostly accidental. Not that I don't need help, but the F1 is a reflex I use when I don't understand the meaning of an option on the UI. I couldn't care less for msdn at that point.

Visual Studio 2008 seems to have a faster <cough> <cough> documentation explorer, but goes into what I'd consider to be pure vice: The little question mark box next to the close button is for bloody contextual help. Guess what, opening your big document explorer in my face when I'm already trying to understand what in the name of god you meant by allow checked-in items to be edited is not contextual. I loose my patience, and definitely loose my respect for whichever manager decided that after all, contextual help could be in the big documentation.

Can I have my tooltips back? Please?

Ads

WPF Tips n' Tricks – Receive notifications for dependency properties

Receiving notifications for dependency property changes on an existing object is a very common scenario. The way to do it properly is not very obvious. So much so that while reviewing some code, I found the following snippet.

// Believe it or not, this seems to be the only way to get change
// notifications for DPs unless you derive from the relevant
// class and override OnPropertyChanged.

PropertyDescriptor prop = TypeDescriptor.GetProperties(obj)["Prop"];
prop.AddValueChanged(obj, delegate { viewModel.RaisePropertyChanged("Prop"); });

There's a few issues with this code. The first one is that you reflect on the CLR property anchoring the dependency property, and not the dependency property itself. For example, the following code wouldn't work.

public Dock Dock { get { return DockPanel.GetDock(this); } }
public void TestDockProperty()
{
    PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this)["Dock"];
    descriptor.AddValueChanged(this, delegate(object sender, EventArgs args) { MessageBox.Show("ValueChanged!"); });

    DockPanel.SetDock(this, Dock.Top);
}

The reason is that the PropertyDescriptor points to the CLR property, not to the dependency property.

The second issue is a problem of performance. TypeDescriptor.GetProperties reflects on every call and doesn't cache the result, so its cost is O(n). Here's the result of iterating several times on the code using TypeDescriptor.

  • 1,000 iterations : 00:00:00.2811402
  • 10,000 iterations : 00:00:01.4369388
  • 100,000 iterations : 00:00:14.1194856

So what is the correct way to do it? Say hi to DependencyTypeDescriptor. Here's the code rewritten to use DependencyProperties.

DependencyPropertyDescriptor prop = DependencyPropertyDescriptor.FromProperty(ParentObject.PropProperty, obj.GetType());
            prop.AddValueChanged(obj, delegate { viewModel.RaisePropertyChanged("Prop"); });

If you execute the code in the small benchmark application we used previously, the results are completely different.

  • 1,000 iterations : 00:00:00.00
  • 10,000 iterations : 00:00:00.00
  • 100,000 iterations : 00:00:00.0312378

As you can see in the source code, I simply use a DateTime before and after the call, and everything runs on the UI thread.

And the source is stored on box.net for those that want a peek. Be aware it's a visual Studio 2008 solution and project.

Download the source.

Ads

More new WPF 3.5 things

Neil passed me some of these URLs in my comments and i'm all too happy to republish them.

Technorati Tags: , , , ,

Ads