I have a WPF view with a TextBox, binding the Text field to a ViewModel with UpdateSourceTrigger set to PropertyChanged. In the property setter in the ViewModel, I have a simple check to prevent the text from exceeding 10 characters:
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
}
public string Name
{
get { return _Name; }
set
{
if (_Name != value)
{
if (value.Length <= 10)
{
_Name = value;
}
RaisePropertyChanged("Name");
}
}
}
If the value isn't set, I still RaisePropertyChanged (which simply fires PropertyChanged).
The problem is that when I type in the 11th character in the UI, I don't update _Name. I fire PropertyChanged, and I can see the get accessor get called and it returns the string with only 10 characters. However, my TextBox doesn't reflect this; it still shows the string with 11 characters.
On top of that, is that if on the 11th character I change the text in the setter to "ERROR", and fire property changed, the TextBox DOES update to show the altered text.
So why is it that if I alter the text in the setter back to the previous value, the UI doesn't reflect this?
I know there are alternative ways of handling max characters, but why won't this work?
This is nothing but a bug in the framework. The Text
property in the TextBox
does get your new value but the GUI is now out of sync with its own TextProperty
. This also happends for any ItemsControl
when you want to cancel a change of SelectedItem
from the ViewModel and it's really annoying.
This bug doesn't happend when you use explicit Binding
though so this can be used as a workaround.
Xaml
<TextBox Text="{Binding Path=MyName,
UpdateSourceTrigger=Explicit}"
TextChanged="TextBox_TextChanged"/>
Code behind
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
textBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
}
To verify that the TextBox GUI indeed is out of sync, just observe the value of TextBox.Text
. The TextBox
will say "123456789___0" for example while TextBlock
says "123456789".
<StackPanel>
<TextBox Name="myTextBox"
Text="{Binding Path=MyName,
UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="{Binding ElementName=myTextBox, Path=Text}"/>
</StackPanel>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With