Updating bound WPF control without tabbing out

I've had an opportunity to do WPF development professionally (as opposed to hobby-tier) for the first time over the last year or so, & while the improvements over WinForms are staggering (and as a lifelong web developer, also familiar), there's plenty that's not intuitive.

One thing that bears a little explanation is this scenario, which I expect would be fairly common.

Scenario

I have a data entry form following the MVP pattern (that's Model-View-Presenter, very similar to MVC in the web world), with text boxes & other controls bound to a C# object. It has a toolbar with a Save button & other buttons on it. The user enters some text, clicks Save, & it's sent to the server to be saved. That's it.

Problem

When I enter data into the text boxes, then click Save, it was ignoring my changes to the last text box I typed into. If I tab out of that text box, then clicked Save, it saved it fine, but what user is going to think to do that? My application should work the way the user would expect; entering data into a form & saving it shouldn't require training specific to one application.

Fortunately, I'm not the only one that had this problem. Like in the question, I knew I could solve this by adding UpdateSourceTrigger=PropertyChanged to my text box's binding, but I didn't want to do that--that didn't play well with the event handler with some fairly complex validation logic I had for one of the text boxes, nor the formatting for another. I didn't want to choose between text formatting & validation working correctly, and save working intuitively.

The accepted answer states this happens because the Save button doesn't take focus away from the text box, but only when the Save button is in a toolbar. When I took it out of the toolbar, it received focus & everything worked great. But the toolbar, and thus the button within it, has a different FocusManager.FocusScope, so the last text box retains focus even though the Save button gets focused as well. I considered changing this behavior, but again, if this is the standard users are used to for WPF apps, I can understand the benefits & wouldn't want to mess with that streamlined experience.

Solution

The answer lists several ways to fix the behavior. The one I chose, which felt the least like a hack & worked for this user control, was to manually force the update. When the save button is clicked, I call Keyboard.FocusedElement as TextBox, then TextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource() (with all the requisite null checks, of course), then retrieve the data from the bound object to send to the server. It worked like a charm, and was easy to centralize in my base control class, though at first glance it looks like it'd be specific to each type of control you want to have this behavior--TextBox, ComboBox, etc. But in my application, there would only be a handful anyway, so that's just a different code path to get the BindingExpression for each--three lines of code for each control type.

No Comments