2014-02-14

Fixing WPF Default Button That Doesn't Trigger Converter

I have a textbox on a WPF form. The textbox has a converter attached to it. I also have an OK button on the form, with the IsDefault property set to true. There is a particular problem with this scenario, because the converter is normally triggered when the textbox loses the focus. However, if the user presses "Enter" rather than clicking the button, the focus is still in the textbox, so the converter never gets triggered. Since the converter hasn't been triggered, the property bound to the textbox still retains its original value, which is what the OK button commits.

Here is a little hack to get around this problem. The idea is that when Enter gets pressed, and it triggers the button click event, you set the focus to the button. This causes the LostFocus event to trigger the converter. Then you go about your business. The example below uses Caliburn.Micro, but the theory would work in other environments. The one small drawback to coding it this way is that the ViewModel has to know about the control, which makes MVVM purists queasy. I don't think this is a terrible violation of the MVVM model. It is still testable by passing null to the Ok method.

[View File]

<Button x:Name="Ok"
    cal:Message.Attach="[Event Click]=[Action Ok($source)]"
    Content="OK"
    IsDefault="True"
    MinWidth="75" />

[ViewModel File]
 
public void Ok(System.Windows.UIElement button)
{
    if (button != null)
    {
        button.Focus();
    }

    // other stuff goes here

    this.findDateDialog.TryClose(true);
}

The Click action passes the Ok button to the Ok method, which sets the focus to it. If you just click the button with the mouse, then it already has the focus, which is a no-op.

If you know a better way of doing this, let me know in the comments.

No comments :

Post a Comment