A while back Dr. WPF graced us with his clever hack of controlling input
focus from VM objects. It involved hijacking the VM's IDataErrorInfo
implementation, and doing all sorts of evil-genius stuff to make the input
caret move to the correct element. Today while I was *trying* to read a
great novel, I couldn't stop thinking about another way to control input
focus from a viewmodel object.
I put the novel down and did a quick spike of the idea. The source code is
attached (rename it from .DOC to .ZIP since gmail is terrified of ZIP files
for some reason). Here's the general idea...
Implement this interface on your VM class:
/// <summary>
/// Implemented by a ViewModel that needs to control
/// where input focus is in a View.
/// </summary>
public interface IFocusController
{
/// <summary>
/// Raised when the input focus should move to
/// a control whose 'active' dependency property
/// is bound to the specified property.
/// </summary>
event EventHandler<MoveFocusEventArgs> MoveFocus;
}
Next, in your VM object (which might implement IDataErrorInfo), do something
like this to support a Save button:
public ICommand SaveCommand
{
get { return new RelayCommand(this.Save); }
}
void Save()
{
if (this.HasError)
{
// The Error property knows which property is invalid.
this.RaiseMoveFocus(this.Error);
}
else
{
// Save to database...
System.Windows.MessageBox.Show("Saved");
}
}
bool HasError
{
get { return _validatedProperties.Any(prop =>
!String.IsNullOrEmpty(this[prop])); }
}
public event EventHandler<MoveFocusEventArgs> MoveFocus;
void RaiseMoveFocus(string focusedProperty)
{
var handler = this.MoveFocus;
if (handler != null)
{
handler(this, new MoveFocusEventArgs(focusedProperty));
}
}
Lastly, in your View, use my terribly(?) named attached property to specify
which DP on your elements is bound to the validated property of the VM, for
example:
<TextBox
Text="{Binding Path=FirstName, ValidatesOnDataErrors=True}"
*local:FocusControl.ValidatedProperty="TextBox.Text"*
/>
I'm not sure that I like this approach yet. It's a pretty important topic,
so I thought I'd share this out amongst the Disciples for feedback.
Thanks,
Josh