Reputation: 3399
Assume I have with texbox and textblock:
<TextBox Name="textBox1"
Text="{Binding Path=user,
RelativeSource={RelativeSource FindAncestor,
AncestorType=my:MainWindow, AncestorLevel=1},
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Name="textBlock1"
Text="{Binding Path=user,
RelativeSource={RelativeSource FindAncestor,
AncestorType=my:MainWindow, AncestorLevel=1},
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Code behind:
private string _user = "a";
public string user
{
get
{
return _user;
}
set
{
if (!String.IsNullOrEmpty(value.Trim()))
_user = value;
//else
//_user = _user + Environment.NewLine;
NotifyPropertyChanged("user");
}
}
What I'm trying to achieve - is not allow user to enter empty string (or whitespace) in textbox and textblock. If text is empty - i simply restore previous value (cleared by user text - "a" in case of my code).
Code above works perfectly for textblock, but not for textbox (screenshot after pressing backspace inside textbox):
Moreover if you remove comment from
//else
//_user = _user + Environment.NewLine;
everything works like a charm (exept for I need to restore previous value, not value with Environment.NewLine :) of course)
So what's happening? Why behavior of textbox differs much from expected (and even differs from textblock behavior)?
UPDATE:
What I'm expecting:
If I press backspace in textbox my expression !String.IsNullOrEmpty(value.Trim())
is false.
_user
is not updated (it is still "a").
Calling NotifyPropertyChanged("user")
on the next line should force binding to get "a" (and _user
equals "a" as expected if I touggle breakpoint in getter).
But as you can see on a screenshot - textbox is empty for some reason.
Upvotes: 1
Views: 2329
Reputation: 69985
I wouldn't call that a bug of any kind. The difference is caused because the TextBox
can be changed from two places, whereas the TextBlock
can only be changed from one. That one source has a rule that won't allow the value to be an empty string
and so, it won't show an empty string
. The TextBox
on the other hand has no such rule to stop the user from changing the value. For that, you'd need to add a handler to the TextBox.PreviewKeyDown
event:
<TextBox Name="textBox1" Text="{Binding Path=user, RelativeSource={RelativeSource
AncestorType=my:MainWindow}, UpdateSourceTrigger=PropertyChanged}"
PreviewKeyDown="TextBox_PreviewKeyDown"/>
...
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (((TextBox)sender).Text.Trim().Length == 1 &&
(e.Key == Key.Delete || e.Key == Key.Back)) e.Handled = true;
}
Also note that you didn't need to set half of those properties in your RelativeSource Binding
... the above should work just the same. The TextBox.TextProperty DependencyProperty
has the BindsTwoWayByDefault
flag set in its default FrameworkMetadata
, so you don't need to use Mode=TwoWay
here and you only need to set the AncestorType
property.
Upvotes: 1
Reputation: 45106
I have had this same problem
When people told me they could not reproduce it led me to think environment
For me it does not work on .NET 3.5 or .NET 4.0 but it does work on .NET 4.5
The answer is try it on .NET 4.5
This is a XAML way to set DataContext
No reason for TwoWay or UpdateSourceTrigger on a TextBlock
DataContext="{Binding RelativeSource={RelativeSource self}}"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation="Vertical">
<TextBox Text="{Binding TextNoEmpty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="{Binding TextNoEmpty, Mode=OneWay}"/>
</StackPanel>
</Grid>
Tested the above on .NET 3.5 and it reproduced the problem
Tested the above on .NET 4.5 and it worked properly
Would probably have same problem if you tried to truncate to a maximum length in the setter.
Upvotes: 0