WPF文本框文本数据绑定奇怪的行为

时间:2014-02-28 07:36:42

标签: c# wpf data-binding textbox

假设我有texbox和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}" />

代码背后:

    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");

        }
    }

我想要实现的目标 - 不允许用户在文本框和文本块中输入空字符串(或空格)。如果文本为空 - 我只是恢复以前的值(由用户文本清除 - 在我的代码的情况下为“a”)。

上面的代码适用于textblock,但不适用于textbox(在文本框中按退格键后的屏幕截图):

enter image description here

此外,如果您从

中删除评论
 //else
       //_user = _user + Environment.NewLine;

一切都像魅力一样(我需要恢复以前的值,而不是使用Environment.NewLine :),当然这是

那发生了什么事?为什么文本框的行为与预期的差异很大(甚至与文本块行为不同)?

更新

我期待的是什么:

如果我在文本框中按退格键,则表达式!String.IsNullOrEmpty(value.Trim())为false。

_user未更新(仍为“a”)。

在下一行调用NotifyPropertyChanged("user")会强制绑定得到“a”(如果我在getter中触发断点,则_user等于“a”,如预期的那样。)

但正如您在屏幕截图中看到的那样 - 文本框由于某种原因是空的。

2 个答案:

答案 0 :(得分:1)

我不会称之为任何类型的错误。造成这种差异是因为TextBox可以从两个地方更改,而TextBlock只能从一个地方更改。该一个来源的规则不允许该值为空string,因此,它不会显示空的string。另一方面,TextBox没有这样的规则来阻止用户更改值。为此,您需要为TextBox.PreviewKeyDown事件添加处理程序:

<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;
}

另请注意,您无需在RelativeSource Binding中设置其中一半属性......上述内容应该相同。 TextBox.TextProperty DependencyProperty在其默认BindsTwoWayByDefault中设置了FrameworkMetadata标记,因此您无需在此使用Mode=TwoWay,只需设置AncestorType即可属性。

答案 1 :(得分:0)

我遇到过同样的问题 当人们告诉我他们无法复制时,我就会想到环境 对我来说,它不适用于.NET 3.5或.NET 4.0,但它适用于.NET 4.5 答案是在.NET 4.5上试试

这是一种设置DataContext的XAML方式 没有理由在TextBlock上使用TwoWay或UpdateSourceTrigger

    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>

在.NET 3.5上测试了上面的内容并重现了问题 在.NET 4.5上测试了上面的内容并且它正常工作

如果您尝试在setter中截断到最大长度,则可能会出现同样的问题。