views:

761

answers:

7

I have a WPF Window that contains a TextBox. I have implemented a Command that executes on Crtl-S that saves the contents of the window. My problem is that if the textbox is the active control, and I have newly edited text in the textbox, the latest changes in the textbox are not commited. I need to tab out of the textbox to get the changes.

In WinForms, I would typically call EndEdit on the form, and all pending changes would get commited. Another alternative is using onPropertyChange binding rather than onValidation, but I would rather not do this.

What is the WPF equivalent to EndEdit, or what is the pattern to use in this type of scenario?

Thanks,

A: 

HI, Well, while using WPF, one needs to adopt to a different mindset.

I would basically bind the TextBox's Text property to one of my properties (Model, ViewModel, Code-Behind, whatever makes you happy). So when you handle CTRL+S you just go to the clr property that is binded and continue happily with all the data you want.

Hope that help you, if you require code examples, leave me a comment. Ariel

ArielBH
+1  A: 

To avoid the issue of needing to tab away, you could simply change the UpdateSourceTrigger property of your controls' binding. Try the following:

<TextBox.Text>
    <Binding Path="MyProperty" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>

This tells WPF to update the backing object whenever the Text property is changed. This way, you don't need to worry about tabbing away. Hope this helps!

EDIT:

The accepted answer for the following SO question provides a way to automatically run validation rules for a page. You could modify it to call UpdateSource() on all BindingExpression objects instead.

Link

Pwninstein
I would preferably not have to add the updateSourceTrigger to all the textboxes in my form, one call to make sure all pending changes are 'commited' is what I am looking for. Your suggestion is like the 'OnPropertyChange' binding. It is doable, but also causes more events than I would like to see.I am looking for a generic WPF pattern to solving this type of problem. Thank you for answering.
Thies
+2  A: 

You can force specific bindings to update using code like the following:

var bindingExpression = txtInput.GetBindingExpression(TextBox.TextProperty);
bindingExpression.UpdateSource();

Doing this more generally is difficult because there is no generic way to get all bindings, nor would you necessarily want them all to updated.

That would probably work too. The accepted answer for the following SO question provides a way to automatically run validation rules for a page. I think you could modify it to call UpdateSource() on all BindingExpression objects instead. http://stackoverflow.com/questions/127477/detecting-wpf-validation-errors
Pwninstein
I am looking for a generic solution that does not have to make me change the binding on all forms. Something that commits all on-going edits.Thank you for answering.
Thies
+1  A: 

I disagree w/ArielBH. The issue here is the interplay between keyboard and logical focus, and unless you have changed all your Data Binding update triggers to PropertyChanged, you may miss some source data updates in certain scenarios (e.g. Toolbar button clicks). For instance, the default update trigger for TextBox.Text is LostFocus and clicking on a toolbar button does not blur the active TextBox focus.

If you have some mechanism to register the controls, then you could explicitly force the data binding to update the source in the same place you'd be calling EndEdit in a WinForms app. It's not neat or elegant, but it gets the job done.

If somebody has come up with a better solution, I'd be all ears as well.

micahtan
See the link I posted in my comment to commongenius' answer for an example of how one could go about forcing bindings to update. Granted, the example shown doesn't do exactly that, but could be easily modified to do just what you're suggesting. :)
Pwninstein
+1  A: 

Baed on Pwninstein answer, I have now implemented an EndEdit in my common class for WPF Views / Windows that will look for bindings and force an update on them, code below;

Code below;

private void EndEdit(DependencyObject parent)
{
    LocalValueEnumerator localValues = parent.GetLocalValueEnumerator();
    while (localValues.MoveNext())
    {
        LocalValueEntry entry = localValues.Current;
        if (BindingOperations.IsDataBound(parent, entry.Property))
        {
            BindingExpression binding = BindingOperations.GetBindingExpression(parent, entry.Property);
            if (binding != null)
            {
                binding.UpdateSource();
            }
        }
    }            

    for(int i=0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(parent, i);
        this.EndEdit(child);
    }
}

protected void EndEdit()
{
    this.EndEdit(this);
}

In my Save command, I now just call the EndEdit method, and I don't have to worry about other programmers selection of binding method.

Thies
Edited my previous answer to include my comments. Thanks! Glad that helped :)
Pwninstein
A: 

Geez I wish there was a better answer for this.

Jonathan
A: 

I believe you are supposed to declare a binding group and then reference that binding group in code. I put mine on the root Window element so it gets the bindings of all the controls on the Window.

<Window.BindingGroup>
    <BindingGroup />
</Window.BindingGroup>

this.BindingGroup.CommitEdit();
dalchri
Thanks for the feedback. It looks promising, but I need to give it a try first.
Thies