I have a DataGrid that shows items and a details form that allows editing of individual items. (Editing in the grid itself makes accidental changes more likely.) I have a Save button that updates the data. This Save button is only enabled if the data has
been changed.
I tried to accomplish this via TwoWay binding. Unfortunately the events are not handled in the order that suits my needs. Am I doing something wrong?
The core code (DataContext = ViewModel):
void PeopleGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Person selectedPerson = PeopleGrid.SelectedItem as Person;
ViewModel.CurrentPersonIndex = PeopleGrid.SelectedIndex;
ViewModel.CurrentPerson = selectedPerson.Copy();
}
...
public class Person : IComparable, INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
...
NameTextBox.TextChanged += new TextChangedEventHandler(NameTextBox_TextChanged);
The problem I face is that AdjustSaveButton() is called BEFORE the Name setter and hence SaveButton.IsEnabled remains false upon the first change in the NameTextBox. Upon the second change the setter has been called once, and hence SaveButton.IsEnabled is set
to true. That's obviously one key stroke too late ...
Thanks you! Are you sure this applies to Silverlight? On the Internet I see GetBindingExpression in the context of WPF but not Silverlight.
You would do me a favor if you elaborated on why it makes sense that the binding happens only after the TextChanged event handler is executed. In my scenario that does not seem to be helpful. Or maybe I should take a different approach?
marcschluper
Member
56 Points
48 Posts
Why is TextChanged event for TextBox called BEFORE the ViewModel is updated (via TwoWay binding)?...
Jun 22, 2009 09:07 PM | LINK
I have a DataGrid that shows items and a details form that allows editing of individual items. (Editing in the grid itself makes accidental changes more likely.) I have a Save button that updates the data. This Save button is only enabled if the data has been changed.
I tried to accomplish this via TwoWay binding. Unfortunately the events are not handled in the order that suits my needs. Am I doing something wrong?
The core code (DataContext = ViewModel):
void PeopleGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Person selectedPerson = PeopleGrid.SelectedItem as Person;
ViewModel.CurrentPersonIndex = PeopleGrid.SelectedIndex;
ViewModel.CurrentPerson = selectedPerson.Copy();
}
...
public class Person : IComparable, INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
...
NameTextBox.TextChanged += new TextChangedEventHandler(NameTextBox_TextChanged);
...
void NameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
AdjustSaveButton();
}
private void AdjustSaveButton()
{
Person originalPerson = ViewModel.People[ViewModel.CurrentPersonIndex];
SaveButton.IsEnabled = (originalPerson.CompareTo(ViewModel.CurrentPerson) > 0);
}
Some related XAML:
<data:DataGrid x:Name="PeopleGrid" ItemsSource="{Binding People}" />
<TextBox x:Name="NameTextBox" Text="{Binding CurrentPerson.Name, Mode=TwoWay}" />
The problem I face is that AdjustSaveButton() is called BEFORE the Name setter and hence SaveButton.IsEnabled remains false upon the first change in the NameTextBox. Upon the second change the setter has been called once, and hence SaveButton.IsEnabled is set to true. That's obviously one key stroke too late ...
Thanks!
TextBox.TextChanged Button.IsEnabled
Klinger
Participant
1676 Points
300 Posts
Re: Why is TextChanged event for TextBox called BEFORE the ViewModel is updated (via TwoWay bindi...
Jun 24, 2009 10:22 PM | LINK
I have had this issue before too. The actual binding happens only after the TextChanged event handler is executed.
What makes sense to me now that I understand it better.
You can do the following to force the binding to happen:
var tb = sender as TextBox;
var be = tb.GetBindingExpression(TextBox.TextProperty);
if (be != null)
{
be.UpdateSource();
}
AdjustSaveButton();
Klinger
marcschluper
Member
56 Points
48 Posts
Re: Why is TextChanged event for TextBox called BEFORE the ViewModel is updated (via TwoWay bindi...
Jun 25, 2009 02:18 AM | LINK
Thanks you! Are you sure this applies to Silverlight? On the Internet I see GetBindingExpression in the context of WPF but not Silverlight.
You would do me a favor if you elaborated on why it makes sense that the binding happens only after the TextChanged event handler is executed. In my scenario that does not seem to be helpful. Or maybe I should take a different approach?
Klinger
Participant
1676 Points
300 Posts
Re: Why is TextChanged event for TextBox called BEFORE the ViewModel is updated (via TwoWay bindi...
Jun 25, 2009 03:53 AM | LINK
Yes, it works on Silverlight.
Regarding the TextChanged event.
The way I see TextChanged event is independent of the binding itself.
TextChanged means that the control property Text has changed.
It may ot may not have a binding expression attached to it.
And, because you know that the text has been changed we can all sort of
things just before the binding is actually executed.
Maybe we are missing an event here. BindingExecuted?
This behavior does not goes well with MVVM I have to agree.
Klinger
marcschluper
Member
56 Points
48 Posts
Re: Why is TextChanged event for TextBox called BEFORE the ViewModel is updated (via TwoWay bindi...
Jun 25, 2009 02:29 PM | LINK
Must be Silverlight 3 then. Will check solution at home tonight. Thanks!
Brauliod
Contributor
2448 Points
744 Posts
Re: Why is TextChanged event for TextBox called BEFORE the ViewModel is updated (via TwoWay bindi...
Sep 29, 2009 12:48 PM | LINK
Well.. encapsulated in a user control the workaround...
public class TextBoxChangeExt : System.Windows.Controls.TextBox{
public TextBoxChangeExt(){
this.TextChanged += new TextChangedEventHandler(TextBoxChangeExt_TextChanged);}
void TextBoxChangeExt_TextChanged(object sender, TextChangedEventArgs e){
// based on // http://betaforums.silverlight.net/forums/t/103695.aspx TextBox txCtl = (TextBox)sender;if (txCtl != null){
var be = txCtl.GetBindingExpression(TextBox.TextProperty); if (be != null){
be.UpdateSource();
}
}
}
}
Book: Mastering LOB Development for Silverlight 5: A Case Study in Action