14

I have a WPF window for editing database information, which is represented using an Entity Framework object. When the user closes the window, I'd like to notice in the Closing event whether the information has changed and show a message box offering to save the changes to the database.

Unfortunately, changes to the currently focused edit aren't assigned to the binding source until the edit loses focus, which happens at some point after the Closing event has been processed.

Ideally, there would be a routine which commits all changes in the view hierarchy that I could call before checking to see if my entity has been modified. I've also looked for information on programmatically clearing the focus in the control with focus, but can't figure out how to do it.

My question is, how is this typically handled?

Zach Johnson
  • 23,678
  • 6
  • 69
  • 86
Finley Lee
  • 143
  • 1
  • 1
  • 4

6 Answers6

26

In WPF you can change a Binding to update the source on modification, rather than on losing the focus. This is done by setting the UpdateSourceTrigger property to PropertyChanged:

Value="{Binding Path=MyProperty, UpdateSourceTrigger=PropertyChanged}"
sourcenouveau
  • 29,356
  • 35
  • 146
  • 243
  • Best answer, as it is pure MVVM, and don't involve messing around with events. Nevertheless unsatisfying, that this isn't the default trigger, as it seems like the most intuitive two-way-binding behavior to me... – M463 Sep 15 '15 at 13:13
  • This won't work when you have a converter that corrects the value, after leaving the keyboard focus. For example, when my ConvertBack cuts trailing zeros from a number (converts "5.80" to "5.8"), I won't be able to write "5.801", because the converter prevents me from writing a zero. After PropertyChanged, text in TextBox will change from "5.80" to "5.8". – marbel82 Oct 17 '21 at 14:23
8

This should get you pretty close:



private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    ForceDataValidation();
}


private static void ForceDataValidation()
{
    TextBox textBox = Keyboard.FocusedElement as TextBox;

    if (textBox != null)
    {
        BindingExpression be = textBox.GetBindingExpression(TextBox.TextProperty);
        if (be != null && !textBox.IsReadOnly && textBox.IsEnabled)
        {
            be.UpdateSource();
        }
    }

}


Donnelle
  • 5,689
  • 3
  • 27
  • 31
  • 1
    I also checked to see if the textbox had edits: `if ((textBox != null) && (textBox.CanUndo)) {...}` – jhr May 17 '16 at 15:21
6

Maybe you need to remove the focus from the current element

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    FocusManager.SetFocusedElement(this, null);
}
Nuno Cruz
  • 61
  • 1
  • 2
1

Assuming that there is more than one control in the tab sequence, the following solution appears to be complete and general (just cut-and-paste)...

Control currentControl = System.Windows.Input.Keyboard.FocusedElement as Control;

if (currentControl != null)
{
    // Force focus away from the current control to update its binding source.
    currentControl.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    currentControl.Focus();
}
Luís Cruz
  • 14,780
  • 16
  • 68
  • 100
Dave the Rave
  • 181
  • 1
  • 3
0

Also look at the sugestions in this post

Community
  • 1
  • 1
rudigrobler
  • 17,045
  • 12
  • 60
  • 74
0

The easiest way is to set the focus somewhere. You can set the focus back immediately, but setting the focus anywhere will trigger the LostFocus-Event on any type of control and make it update its stuff:

IInputElement x = System.Windows.Input.Keyboard.FocusedElement;
DummyField.Focus();
x.Focus();

Another way would be to get the focused element, get the binding element from the focused element, and trigger the update manually. An example for TextBox and ComboBox (you would need to add any control type you need to support):

TextBox t = Keyboard.FocusedElement as TextBox;
if ((t != null) && (t.GetBindingExpression(TextBox.TextProperty) != null))
  t.GetBindingExpression(TextBox.TextProperty).UpdateSource();
ComboBox c = Keyboard.FocusedElement as ComboBox;
if ((c != null) && (c.GetBindingExpression(ComboBox.TextProperty) != null))
  c.GetBindingExpression(ComboBox.TextProperty).UpdateSource();
Sam
  • 28,421
  • 49
  • 167
  • 247