WPF TextBox显示的值不等于TextBox.Text

时间:2011-04-01 18:53:43

标签: c# wpf binding textbox

我检查了大约60个国家的邮政编码。用户输入邮政编码,根据该国家/地区的规则进行检查。美国是一个例外,我可以根据已经输入的其他街道地址信息自动填充该值。在某些方面,它基本上是一种自动校正功能。问题是,如果自动填充值与之前的.Text值匹配,则永远不会重新显示 - 用户刚输入的“错误”邮政编码仍会显示!

例如,字段包含“12345”,用户删除“5”,我的属性设置器将值返回“12345”,绑定getter返回“12345”(此时我的_TextChanged事件触发)但是WPF仍显示用户编辑的文本“1234”!

如何强制WPF重新显示该值?

为了简化示例,我对ZipCode值进行了硬编码(在应用程序中,它是以单独的方法计算的):

public String ZipCode
{
    get { return _address.ZipCode; }
    set
    {
        _address.ZipCode = "12345";
        RaisePropertyChanged("ZipCode");
    }
}

这是XAML:

<TextBox Name="ZipBox" 
         Text="{Binding Path=ZipCode, UpdateSourceTrigger=PropertyChanged}"
         TextChanged="ZipBox_TextChanged" />

WPF知道字段已更改,因为它始终触发此事件。但这些方法都没有强制WPF正确显示“12345”。

private void ZipBox_TextChanged(object sender, TextChangedEventArgs e)
{
    ZipBox.InvalidateVisual();
    ZipBox.InvalidateMeasure();
    ZipBox.UpdateLayout();
}

编辑:我还创建了一个自定义静态扩展方法.Refresh(这个UIElement uiElement)调用UIElement.Dispatcher.Invoke()并且也不强制重绘。

5 个答案:

答案 0 :(得分:1)

微软论坛上的朱敏想出了一个解决方案。这是代码:

bool flagTextChanged = true;
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
  TextBox txt = sender as TextBox;
  if (flagTextChanged && txt != null)
  {
    flagTextChanged = false;
    Binding b = BindingOperations.GetBinding(txt, TextBox.TextProperty);
    if (b != null)
    {
      txt.ClearValue(TextBox.TextProperty);
      BindingOperations.SetBinding(txt, TextBox.TextProperty, b);
    }
    flagTextChanged = true;
  }
}

答案 1 :(得分:0)

你的意思是在用户手动编辑文本然后离开框后会发生这种情况吗?如果是这样,问题可能是绑定系统不想覆盖用户键入的内容,并且隐含的假设是,如果在属性上调用get,则文本框Text设置的值将与值匹配,因为在集合期间没有抛出异常。这是“魔术属性”的缺点之一,其中设置值被变异而不是经过验证,因为有许多属性的消费者假设如果setter没有抛出异常,则以下内容为真:

Instance.X = value;
Debug.Assert(Instance.X == value);

避免此问题的一个想法是设置一个标志,禁止编辑ZipCode字段(如果已自动确定)(通过绑定IsReadOnly,可能。)

答案 2 :(得分:0)

我相信如果你把一个自定义的IValueConverter除了返回传递的值之外什么都不做,那么TextBox会正确更新。

否则,您应该可以:

ZipBox.GetBindingExpression(TextBox.TextProperty).UpdateTarget();

答案 3 :(得分:0)

这是一个老问题,但它从来没有得到妥善回答,所以这是我的建议。 您需要实施INotifyPropertyChanged

取决于它是ViewModel还是Window的代码隐藏(这是一个Window示例):

public class MyWindow: Window, INotifyPropertyChanged
{
   ...
}

然后在该类中实现一个版本的INotifyPropertyChanged(那里有很多,但这是我使用的版本):

public event PropertyChangedEventHandler PropertyChanged;


private void OnPropertyChanged(string propertyName = "")
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

private bool SetField<T>(ref T field, T value, string propertyName)
{
    if (EqualityComparer<T>.Default.Equals(field, value))
    {
        return false;
    }

    field = value;
    OnPropertyChanged(propertyName);
    return true;
}

然后只需将它与属性一起使用:

private string _text;
public string Text
{
    get { return _text; }
    set { SetField(ref _text, value, "Text"); }
}

答案 4 :(得分:-3)

我对WPF并不是特别熟悉,但我做了很多网页编程。您可以尝试触发帖子来重新加载整个页面(或只是带有ajax的文本框),这应该允许您设置新值。