40

I have a TextBox and a ToolBar with a Button. If I'm typing in the TextBox and I click the Button I want the TextBox to lose Focus so the binding gets updated. I don't want to add a UpdateSourceTrigger=PropertyChanged to my TextBox. But instead when I click on the Button I reset Focus to the main window so what ever I'm on loses Focus and updates the bindings.

I've tried adding a OnClick to the button with the following, but it doesn't seem to work:

    private void Button_Click(object sender, RoutedEventArgs e) {
        FocusManager.SetFocusedElement(this, null);
    }

Any tips would be appreciated.

Thanks, Raul

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
HaxElit
  • 3,983
  • 7
  • 34
  • 43

4 Answers4

40

I encountered a similar issue. I need to unfocus a textbox when enter is pressed. I end up with this code:

var scope = FocusManager.GetFocusScope(elem); // elem is the UIElement to unfocus
FocusManager.SetFocusedElement(scope, null); // remove logical focus
Keyboard.ClearFocus(); // remove keyboard focus

I think it is cleaner than creating dummy controls and it is reusable. I'm not confident with this solution though. But it seems work well.

Dudu
  • 1,264
  • 13
  • 14
  • 3
    This worked for me when nothing else would force a DatePicker to parse the entered text on clicking the save button in toolbar. The code below uses the view (MVVM) as this.owner, called from ViewModel. var t =(DependencyObject)FocusManager.GetFocusedElement(this.Owner); var scope = FocusManager.GetFocusScope(t); FocusManager.SetFocusedElement(scope, null); – Dave Apr 09 '13 at 19:50
27

The problem is that the toolbar places your button in a different FocusManager.FocusScope. That means that both the Button and the TextBox can receive logical focus at the same time, each in its own scope. This is normally a good thing, since you usually don't want to lose focus in your main window area when you select menu items and ToolBar buttons, but in your case it is preventing what you are doing from working.

Although you could override the FocusManager.IsFocusScope property on the toolbar and get the effect you want, this is probably not the best plan since it would make all the other toolbar buttons also steal focus from your main window area.

Instead you could use one of several easy solutions:

  • Put your button outside the Toolbar
  • Add a Focusable="true" control to your main window area and focus it when the button is clicked
  • Manually force the update by calling textBox.GetBindingExpression(TextBox.TextProperty).UpdateSource()
  • Temporarily set Focusable="true" on a control in the main window, set focus to it, then immediately set Focusable="false" again
Ray Burns
  • 62,163
  • 12
  • 140
  • 141
  • I've tried a Keyboard.Focus(mainWindow); but that doesn't seem to be changing the focus either. It remains on the textbox or what ever element was selected. For now I just explicitly force the element to UpdateSource() but it doesn't seem like a long term sustainable solution. I'll try adding a ghost control to set focus to. – HaxElit Jan 14 '10 at 15:44
  • 1
    `Keyboard.Focus(mainWindow)` will only work if "mainWindow" is Focusable (by default it isn't) and if it is in the same `FocusScope` as the `TextBox`. Try creating a `Focusable="true"` control in the same container as the TextBox and focusing that. The other control can be a simple ``. Since `Control` has no default template it will be invisible. – Ray Burns Jan 15 '10 at 17:53
  • 2
    Thanks for mentioning `FocusManager.IsFocusScope`. In my specific scenario, I *wanted* to steal focus from my main window area, so I just set `FocusManager.IsFocusScope="False"` on my Toolbar. – Aphex Sep 29 '11 at 21:25
1

I had an issue leaving a calendar and needing to click a button twice (WPF, .Net 5.0), I tried some of the suggested solutions above but no luck, however this worked - quoted from someone on the Microsoft site:

"My solution to this problem was to insert into the main form, but it's probably overkill."

protected override void OnPreviewMouseUp(MouseButtonEventArgs e)
{
  base.OnPreviewMouseUp(e);
  if (Mouse.Captured is Calendar || Mouse.Captured is System.Windows.Controls.Primitives.CalendarItem)
  {
    Mouse.Capture(null);
  }
}
unstuck
  • 27
  • 3
0

My button was staying focused even though I have style triggers as App resource for mouse over true/false and isfocused true/false. Tried all of the above and thanks to new feature in Vis Studio which gives access to Github examples, found this snippet e.Handled = true;

On all my buttonClick methods I use FocusManager.SetFocusedElement(FocusManager.GetFocusScope(xaml button name), null);Keyboard.ClearFocus();

My problem button had focus when I return to a tab control screen due to different FocusManager.FocusScope as mentioned by Ray Burns above The Tab has focus and the button on the Tab screen also has focus. By adding e.Handled = true; to the buttonClick method it leaves the focus on the Tab which is what I required.

user3763081
  • 43
  • 2
  • 8