Saturday, June 18, 2011

WPF Hyperlinks and the IsEnabled mystery

A colleague of mine started using a control I made in which there was a Hyperlink. Well, the purpose of it was not complex, I just needed a text that can be clicked. A Hyperlink sounded like the only solution out of the box, since there is no LinkButton control in the standard WPF controls. That aside, after I finish writing this blog post, I will write myself a LinkButton control to use in these situations instead, since Hyperlink seems to have several design flaws. It's not even a control, but a flow element.

What my colleague reported is that the Hyperlink would not get enabled in certain situations and we've come to the conclusion that after the initialization of the control, the IsEnabled property on the Hyperlink does not change when an ancestor control changes its enabledness. The only way to force it is to actually bind it to an ancestor IsEnabled.

Here is the scenario: You place several items in a XAML file. They are a text in a Hyperlink, in a TextBlock (since Hyperlinks cannot be directly part of a Panel, first design flaw), in a StackPanel. The text in the text block will appear as a clickable link. Set the StackPanel to IsEnabled="False" and the text will appear as disabled. Now, add a ToggleButton and bind its IsChecked property to the StackPanel IsEnabled property. Click the button and the StackPanel will get disabled, but not the hyperlink. Start with a disabled StackPanel, the link will be disabled, click the button and the hyperlink will stay disabled. The solution: set on the Hyperlink, inline or via a style, IsEnabled="{Binding IsEnabled,RelativeSource={RelativeSource AncestorType={x:FrameworkElement}}}". Now that is ugly.

As a sideline, whenever you see a WPF element inexplicably disabled and you use Snoop on it and try to set IsEnabled to true and you can't, there is probably one of two situations:
  1. A parent of the control is disabled
  2. The control is implementing ICommandSource and its Command property is set on an ICommand that returns false on its CanExecute method


Bill Reiss said...

Wow this one has been driving me crazy all day thanks for the tip!

Anonymous said...

OMG...I thought I was going crazy. Thanks for the help!

Anonymous said...

Very helpful, thought I was going mad >_<