IdentityMine

| Tags: Silverlight, WPF

originally posted by Josh Smith: (link) - please comment at original post

One of the pain points in MVVM development is controlling input focus from ViewModel objects. A common scenario is when a validation error occurs, and focus needs to move to the control that is bound to the property in error. This makes it easier for the user to immediately fix the validation problem.

A while ago, Dr. WPF shared a solution to the WPF Disciples that involves hijacking the VM’s IDataErrorInfo implementation and doing some hacky magic that results in focus being sent to the correct control. While a brilliant solution, I preferred finding a more formal, less hacky solution. This blog post presents the implementation that I’ve thrown together, with help from the WPF Disciples over the past few days.

In a ViewModel object, you must implement my IFocusMover interface.

public event EventHandler MoveFocus;

void RaiseMoveFocus(string focusedProperty)
{
var handler = this.MoveFocus;
if (handler != null)
{
var args = new MoveFocusEventArgs(focusedProperty);
handler(this, args);
}
}

The MoveFocus event should be raised when the VM object determines that input focus needs to be sent to the control bound to the ‘focused property.’ For example, if the FirstName property of an object is deemed invalid, you would call the RaiseMoveFocus method, passing “FirstName” as the focused property argument. In the demo application, this results in the TextBox whose Text is bound to the FirstName property to get input focus.

Now let’s shift our attention to the View to see how a control is configured to be able to receive focus. The only thing you must do is use a custom Binding object that I made, called FocusBinding. That class relies on Philipp Sumi’s BindingDecoratorBase class, which allows you to create a custom Binding that can override the all-important ProvideValue method (inherited from MarkupExtension).

public override object ProvideValue(IServiceProvider provider)
{
DependencyObject elem;
DependencyProperty prop;
if (base.TryGetTargetItems(provider, out elem, out prop))
{ FocusController.SetFocusableProperty(elem, prop); }

return base.ProvideValue(provider);
}

You use the FocusBinding in XAML like this:

The ValidatesOnDataErrors property setting is not required, but is used in the demo app to enable support for validation via the VM’s IDataErrorInfo implementation. All controls bound to VM properties that can be “focusable” use the FocusBinding, instead of a normal Binding. When the VM raises its MoveFocus event, the control whose FocusBinding’s Path references the ‘focused property’ will be given input focus.

You can download the source code here. NOTE: Rename the file extension from .DOC to .ZIP and then decompress it. Feedback is welcome!

Remember to please comment at original post: (link)

Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInPin on PinterestShare on RedditShare on TumblrEmail this to someoneDigg thisFlattr the authorShare on StumbleUpon

Comments are closed.