3
votes

I have a search screen with some textboxes and a Search button as the default. If I type in a textbox and I CLICK the button, everything's great. But if I press enter within a text box, the button command fires but the binding on whatever text box I was in does NOT fire and so my criteria doesn't make it to the view model to get filtered on.

I know one fix is to set the bindings on the text boxes to PropertyChanged, but this seems like way overkill. I might have logic in the viewmodel doing stuff and I don't want that to trigger on every single keystroke.

What I really want is a way for the button itself to either trigger a focus change or somehow trigger binding. Or to have the textbox trigger binding if focus is lost OR I press enter OR a command is executed from anywhere

3

3 Answers

4
votes

One way to do this is with a BindingGroup.

http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.bindinggroup.aspx

If your TextBox(es) and Button are both contained within a Grid (for example), you would add a BindingGroup like this:

<Grid>
    <Grid.BindingGroup>
        <BindingGroup Name="bindingGroup1"/>
    </Grid.BindingGroup>

Then you could add a Click event handler to your button and call CommitEdit() on the BindingGroup (which the Button and TextBox inherit from the Grid):

private void button1_Click(object sender, RoutedEventArgs e)
{
    (sender as FrameworkElement).BindingGroup.CommitEdit();
}

The Button.Click event fires before the CommandBinding, so any databound TextBox or any other databound controls within that BindingGroup should be updated before your view model command gets executed.

1
votes

I've had the exact scenario you just mentioned. The trick I use is an attached behavior that sits on a control and listens for the PreviewKeyDown event. It checks if enter is being pressed. If so it forces the control to lose focus, thus causing the binding to fire before the command executes.

1
votes

A simpler approach (rather than using a binding group) is to use the default button's click event to set the focus to itself. As this happens before the command is executed it means the ViewModel is updated in time.

private void button1_Click(object sender, RoutedEventArgs e)
{
    (sender as Button).Focus()
}

And if you really hate code behind, you could always write an attached property...