Click here to Skip to main content
15,887,214 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I belive I saw this problem in WinForms also with the text changed event but I maybe mistaken. Regardless I want to know how (or if it can be) solved in WPF. Note I am using an MVVM pattern.

Say I have a TextBox in the view bound to a value 'Value' in its view model.

As the end user types or changes the text code is not fired. It is only when the mouse goes to another component (e.g. textbox or listbox.. really anyting) that the value is updated in the viewModel.
This can of course create problems. Say this 'Value' is saved to some file when the user presses 'Ctrl+S'. The value has not yet grabbed what is in the textbox so it is the old value. The user then thinks they saved new data but really did nothing but save old over old.

So How does one handle this without telling his end users [CLICK HERE] before saving?

EDIT (Addid code samples)
The main view is bound as such in the App.xaml.cs
<pre lang="cs">private void OnStartup(object sender, StartupEventArgs e)
        {
            // Create the ViewModel and expose it using the View's DataContext
            MainWindow view = new MainWindow();
            view.DataContext = new MainViewModel();
            view.Show();
        }




All others are bound in a resource that is pulled in by the main view. Their binding is as such,

XML
<DataTemplate DataType="{x:Type viewModels:Example_vm}">
    <views:Example_v/>
</DataTemplate>



The object that has the Textbox is as follows:
XML
<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Column="0" Text="{Binding Path=Name}"/>
        <TextBox Grid.Column="1" Text="{Binding Path=Value, Mode=TwoWay}"/>
    </Grid>



And its bounded code is:

C#
#region Value
        public string Value
        {
            get { return _settingNode.Attribute(Setting_Properties.Value).Value; }
            set
            {
                if (_settingNode.Attribute(Setting_Properties.Value).Value == value)
                    return;
                _settingNode.Attribute(Setting_Properties.Value).SetValue(value);

                this.RaisePropertyChanged("Value");
                this.RaisePropertyChanged("Node");
            }
        }
        #endregion //Value

        <pre lang="cs">#region Name
public string Name
{
    get { return _settingNode.Attribute(Setting_Properties.Name).Value; }
    set
    {
        if (_settingNode.Attribute(Setting_Properties.Name).Value == value)
            return;
        _settingNode.Attribute(Setting_Properties.Name).SetValue(value);

        this.RaisePropertyChanged("Name");
        this.RaisePropertyChanged("Node");
    }
}
#endregion //Name


_settingNode is an XElement that contains the data needed.
Posted
Updated 12-Jul-10 4:00am
v2

Since this is WPF, the solution is fairly simple:

XML
<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Column="0" Text="{Binding Path=Name}"/>
        <TextBox Grid.Column="1" Text="{Binding Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>


The issue is that you are leaving the UpdateSourceTrigger Property of the BindingExpression to its default value, which is LostFocus, instead of using the PropertyChanged.

If you are willing to achieve this same functionality in Silverlight, check my article about it Updating Source on PropertyChanged on Silverlight[^]

For more info about BindingExpressions I recommend the WPF Binding CheatSheet version 1.1[^]

Hope this helps you.
Best regards.
Raul Mainardi Neto
 
Share this answer
 
Comments
[no name] 12-Jul-10 10:51am    
Reason for my vote of 5
Simple and Correct!
Also insight into additional info on binding.
[no name] 12-Jul-10 10:52am    
That did it!
Thank you!
Thanks for the links also. I will check them out.
This is not a problem at all. It's by design. The event you want, fires when the value has been updated, not while it is updating. Keypress type events are what you use to track your data WHILE the user is typing.
 
Share this answer
 
Comments
[no name] 8-Jul-10 17:28pm    
Well its a problem when my end users are saving data thinking it was changed and it wasn't.

I do not believe KeyPress type events will work with mvvm pattern.
I guess in MVVM youre using some databinding to TextBox. Am I right? If so. Try use Mode=TwoWay in Binding expression. If not, haven't to many to do with WPF but found two events firing properly: KeyDown(can be bit messy firing on any key you pressed, and TextChanged event. As Christian said, you can update your source in this event.
 
Share this answer
 
v2
Comments
[no name] 9-Jul-10 10:10am    
You are correct about the databinding. TwoWay does not solve the issue. I am not able to update the source with those events because there is no way (that I know of) to incorporate them in the pattern.

My DataContext of the view is entirely bound to another object. Therefore the events can fire and update some meaningless varaible in code behind that is not used. I need the variable in the ViewModel to get update prior to the save occurring.
helianthus87 12-Jul-10 8:51am    
"My DataContext of the view is entirely bound to another object."
Could you paste some piece of code where DataContext of view and TextBox is set? Whole view .xaml would be the best ;) There might be a problem when youre setting context for entire view, then TextBox loosing its context and derrives main context from parent.
[no name] 12-Jul-10 10:00am    
I updated the original question to have some code as an example.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900