TextBox并不总是更新

Hac*_*rth 5 c# wpf mvvm

我有以下TextBox:

<TextBox Text="{Binding SearchString,
               UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
Run Code Online (Sandbox Code Playgroud)

绑定到以下属性:

private string _searchString;
public string SearchString
{
    get 
    { 
        return _searchString; 
    }
    set
    {
        value = Regex.Replace(value, "[^0-9]", string.Empty);             
        _searchString = value;
        DoNotifyPropertyChanged("SearchString");
    }
}
Run Code Online (Sandbox Code Playgroud)

该类继承自实现的基类 INotifyPropertyChanged

public event PropertyChangedEventHandler PropertyChanged;
protected void DoNotifyPropertyChanged(string propertyName)
{
    if (PropertyChanged != null) 
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
Run Code Online (Sandbox Code Playgroud)

我只想要一个快速而肮脏的方法来禁止非整数文本框的非数字字符(我知道它不完整,只是为了演示).我不想仅仅通知有非法文本或任何内容,我想立即丢弃所有不允许输入的字符.

但是,TextBox表现得很奇怪.我仍然可以输入我想要的任何文字,它将显示为输入,例如"1aaa".即使在此示例中已将属性正确清除为"1",文本框仍显示"1aaa".只有当我输入一个会导致_searchString更改的实际数字时,它才会更新显示的文本,例如当我有"1aaa2"时它会正确地更新为"12".这是怎么回事?

Rac*_*hel 3

这听起来像是特定于视图的逻辑,所以我认为没有理由不使用视图背后的代码来控制它。就我个人而言,我会使用丢弃任何非数字字符的PreviewKeyDownon来实现这种行为。TextBox

拥有可以重用的通用控件(例如自定义控件)可能不会有什么坏处,NumbersOnlyTextBox或者AttachedProperty可以附加到您的控件TextBox以指定它只允许数字。

事实上,我记得创建了一个附加属性,允许您为文本框指定正则表达式,并且它将字符输入限制为该正则表达式。我有一段时间没有使用它了,所以你可能想测试它或者可能更新它,但这里是代码。

// When set to a Regex, the TextBox will only accept characters that match the RegEx
#region AllowedCharactersRegex Property

/// <summary>
/// Lets you enter a RegexPattern of what characters are allowed as input in a TextBox
/// </summary>
public static readonly DependencyProperty AllowedCharactersRegexProperty =
    DependencyProperty.RegisterAttached("AllowedCharactersRegex",
                                        typeof(string), typeof(TextBoxProperties),
                                        new UIPropertyMetadata(null, AllowedCharactersRegexChanged));

// Get
public static string GetAllowedCharactersRegex(DependencyObject obj)
{
    return (string)obj.GetValue(AllowedCharactersRegexProperty);
}

// Set
public static void SetAllowedCharactersRegex(DependencyObject obj, string value)
{
    obj.SetValue(AllowedCharactersRegexProperty, value);
}

// Events
public static void AllowedCharactersRegexChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    var tb = obj as TextBox;
    if (tb != null)
    {
        if (e.NewValue != null)
        {
            tb.PreviewTextInput += Textbox_PreviewTextChanged;
            DataObject.AddPastingHandler(tb, TextBox_OnPaste);
        }
        else
        {
            tb.PreviewTextInput -= Textbox_PreviewTextChanged;
            DataObject.RemovePastingHandler(tb, TextBox_OnPaste);
        }
    }
}

public static void TextBox_OnPaste(object sender, DataObjectPastingEventArgs e)
{
    var tb = sender as TextBox;

    bool isText = e.SourceDataObject.GetDataPresent(DataFormats.Text, true);
    if (!isText) return;

    var newText = e.SourceDataObject.GetData(DataFormats.Text) as string;
    string re = GetAllowedCharactersRegex(tb);
    re = "[^" + re + "]";

    if (Regex.IsMatch(newText.Trim(), re, RegexOptions.IgnoreCase))
    {
        e.CancelCommand();
    }
}

public static void Textbox_PreviewTextChanged(object sender, TextCompositionEventArgs e)
{
    var tb = sender as TextBox;
    if (tb != null)
    {
        string re = GetAllowedCharactersRegex(tb);
        re = "[^" + re + "]";

        if (Regex.IsMatch(e.Text, re, RegexOptions.IgnoreCase))
        {
            e.Handled = true;
        }
    }
}

#endregion // AllowedCharactersRegex Property
Run Code Online (Sandbox Code Playgroud)

它会像这样使用:

<TextBox Text="{Binding SearchString, UpdateSourceTrigger=PropertyChanged}" 
         local:TextBoxHelpers.AllowedCharactersRegex="[0-9]" />
Run Code Online (Sandbox Code Playgroud)

但至于为什么它不会更新 UI。UI 知道该值实际上并未更改,因此在收到 PropertyChange 通知时无需重新评估绑定。

为了解决这个问题,您可以尝试暂时将该值设置为其他值,然后再将其设置为正则表达式值,并发出通知PropertyChange以便 UI 重新评估绑定,但老实说,这并不是一个真正理想的解决方案。

private string _searchString;
public string SearchString
{
    get 
    { 
        return _searchString; 
    }
    set
    {
        value = Regex.Replace(value, "[^0-9]", string.Empty);    

        // If regex value is the same as the existing value,
        // change value to null to force bindings to re-evaluate
        if (_searchString == value)
        {
            _searchString = null;
            DoNotifyPropertyChanged("SearchString");
        }

        _searchString = value;
        DoNotifyPropertyChanged("SearchString");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Rachel:我不确定它是否*确实*像那样工作(是的,它是“StackOverflowException”而不是无限循环),但我建议通过绑定来调用属性设置器是不直观的覆盖绑定的值。无论技术限制如何,这可能都是它这样做的充分理由。(我想知道强制“DependencyProperty”中的值是否有助于解决此问题?) (2认同)