【问题标题】:TextBox Not Honoring Value Returned By GetTextBox 不支持 Get 返回的值
【发布时间】:2013-02-21 17:57:42
【问题描述】:

有一个我想限制输入范围的文本框。
在这个简单的例子中,Int32 从 0 到 300。
在现实生活中,范围更复杂,除了接收并显示有效值之外,我不想让 UI 参与其中。

如果我输入 333,它会返回 300,而 300 在 TextBox 中。

问题来了:
然后,如果我为 3001 添加一个数字,则该集合分配的值为 300。
调用 get 并返回 300。
但 3001 仍在 TextBox 中。

如果我粘贴 3001,那么它会正确显示 300。
只有当单次击键达到 4(或更多)位时才会失败。

<TextBox Text="{Binding Path=LimitInt, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="60" Height="20"/>

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    private Int32 limitInt = 0;

    public MainWindow()
    {
        InitializeComponent();
    }

    public Int32 LimitInt
    {
        get { return limitInt; }
        set
        {
            if (limitInt == value) return;
            limitInt = value;
            if (limitInt < 0) limitInt = 0;
            if (limitInt > 300) limitInt = 300; 
            NotifyPropertyChanged("LimitInt");
        }
    }
}

【问题讨论】:

  • 您需要实现验证。看this blog post。
  • @MichaelPerrenoud 假装我不想使用验证。为什么 get 返回的值不是 UI 中的那个值? 301 显示 300。-1 显示 0。但 3001 显示 3001。
  • 我没有遇到同样的问题...我复制/粘贴了您的代码,当我按1 获取3001 时,它给了我300。
  • @Bob。我尝试了另一个盒子和同样的问题。 .NET 4.0 Visual Studio 2010。
  • 嗯...你是对的,我认为它是一个 .NET 的东西。我使用了 .NET 4.5,它可以工作,但在 .NET 4.0 中却不行。

标签: c# .net wpf binding textbox


【解决方案1】:

最好使用验证。

方法如下:

定义您的 XAML 以检查 PreviewTextInput。

<TextBox Text="{Binding Path=LimitInt, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" PreviewTextInput="CheckNumberValidationHandler" Width="60" Height="20"/>

然后设置您的验证处理程序:

/// <summary>
/// Check to make sure the input is valid
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CheckNumberValidationHandler(object sender, TextCompositionEventArgs e) {
    if(IsTextAllowed(e.Text)) {
    Int32 newVal;
    newVal = Int32.Parse(LimitInt.ToString() + e.Text);
    if(newVal < 0) {
        LimitInt = 0;
        e.Handled = true;
    }
    else if(newVal > 300) {
        LimitInt = 300;
        e.Handled = true;
    }
    else {
        e.Handled = false;
    }
    }
    else {
    e.Handled = true;
    }
}

/// <summary>
/// Check if Text is allowed
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
private static bool IsTextAllowed(string text) {
    Regex regex = new Regex("[^0-9]+");
    return !regex.IsMatch(text);
}

编辑:我检查过,它在 .NET 4.0 中工作:)

【讨论】:

  • 我怀疑这是正确的,所以给它一个 +1。但现在我要使用 LostFocus。在我测试之前它不能给它检查。
  • @Blam 不用担心,这确实是一个更好的方法,因为使用 PreviewTextInput 可以防止输入值,而不是在分配值后检查。
【解决方案2】:

我相信这是因为您在绑定操作的中间更改了绑定源的值。当您在绑定上使用 UpdateSourceTrigger=PropertyChanged 时,您是在告诉它在每次按键时重新评估。在这种情况下,Binding 将值推送到源,而不是尝试通过从源中提取来更新目标。

即使在您提高 NotifyPropertyChanged 之后,我想因为您正处于绑定操作的中间,Target 也不会更新。

您可以通过删除 UpdateSourceTrigger 并将其保留为默认值 (LostFocus) 来解决此问题。只要您对在用户退出后发生的情况感到满意,这样做就会起作用。

<TextBox Text="{Binding Path=LimitInt}" Width="60" Height="20"/>

(Mode=TwoWay 是 TextBox 的默认设置,因此您也可以将其删除)。

如果您想在每次按键时对其进行评估,我建议您查看蒙版编辑,并处理按键/按键,以防止将值输入到 TextBox,而不是在它们之后尝试更改它们'已被输入。

【讨论】:

  • 我不同意您的断言“不尝试通过从源中提取来更新目标”。调用 Get 并返回正确的值。 -1 正确显示为 0。301 正确显示 300。get on 3001 set 正确返回 300 但 UI 不显示 300。
  • 我还没有调试框架代码,所以我在这里推测并努力解释清楚,但我并不是说根本不会拉出Source - NotifyPropertyChanged 将强制它调用 get - 但这发生在将新值推送到 Source 的过程中,而 TextBox 仍在处理文本输入。在不逐步执行框架的情况下,我的猜测是,要么因为它处于推送操作的中间而被目标丢弃,要么目标值在推送到源时被“锁定”。
  • 谢谢。如果我选择 LostFocus,它会起作用。不是我想要的效果。我将按照 Perrenoud 的建议尝试验证。 +1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
  • 2017-01-20
  • 1970-01-01
相关资源
最近更新 更多