none
TextBox的Text与显示值不一致的恐怖问题 RRS feed

  • 问题

  • 问题描述:
    将一个 textBox 与自定义类中一个整型属性 Intx 双向绑定,属性中写了限制大小的逻辑
    private ing _intx;
    public int Intx()
    {get{return _intx;}
      set
      {
        _intx = value;
        if(_intx<0)_intx = 0;
        if(_intx>100)_intx = 100;
      }
    }
    为了让文本框的内容与数据同步,在 textBox.TextChanged 事件中加入了 textBox.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
    现在我打算实现方便的改变数值的功能,所以处理了 textBox.PreviewKeyDown 事件,加入了如下代码
    if(e.Key==Key.Down)textBox.Text = (Val(textBox.Text) - 1).ToString;
    if(e.Key==Key.Up)textBox.Text = (Val(textBox.Text) + 1).ToString;
    调试之,发现恐怖现象:当 textBox.Text 为0时,按向下方向键,显示值变成了-1;对于任意初始值,持续按住向下方向键,显示值最后也停在-1。然而无论是断点调试还是 Console.WriteLine() 什么的,textBox.Text 的值竟然都是0!
    按住向上方向键,不出所料的最后显示101,而 textBox.Text 的值也是100!
    求解……(绑定时没有设置Converter)
    2009年12月17日 6:44

答案

  •     private void tbKeyDown(object sender, KeyEventArgs e)
        {
            TextBox t = (TextBox)sender;
            switch (e.Key)
            {
                case Key.Down:
                    if (int.Parse(t.Text) >0) t.Text = (Convert.ToInt32(t.Text) - 1).ToString();
                    break;
                case Key.Up:
                    if(int.Parse(t.Text)<100)
                    t.Text = (Convert.ToInt32(t.Text) + 1).ToString();
                    break;
            }
        }
    原因是优先执行操作+1时候更新了绑定值  再赋值文本框盖住了绑定更新值的bug 

    我又用各种方法来操作,最后发现,只要 tbKeyDown 里面操作的是 Text 属性,就会出现这个问题,要解决问题只有直接操作数据:
    private void tbKeyDown(Object sender,KeyEventArgs e)
    {
      TextBox t = (TextBox)sender;
      switch(e.Key)
      {
        case Key.Down:md.Intx -= 1;break;
        case Key.Up:md.Intx += 1;break;
      }
    }
    也就意味着如果要实现我需要的逻辑,必须在界面元素中直接操作数据,所以数据绑定是用不了的,要让数据与界面解耦是做不到的。这样理解对吗?
    2009年12月28日 6:03

全部回复

  • 可以贴出代码 吗?
    2009年12月20日 8:58
  • 楼主你好,
    你描述的问题总的来说很好重现,但是请提供你自己写的可以运行的代码,我们更好看出问题所在了。

    谢谢。
    Jim Zhou -MSFT
    2009年12月22日 8:16
    版主
  • 前一次回复好乱,重新回复:
    数据类:

    public class MyData : System.ComponentModel.INotifyPropertyChanged
    {
        private int _intx;
        public MyData(int i)
        {
            _intx = i;
        }
        public int Intx
        {
            get { return _intx; }
            set
            {
                _intx = value;
                if (_intx < 0) _intx = 0;
                if (_intx > 100) _intx = 100;
                Notify("Intx");
            }
        }
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        protected void Notify(string propName)
        {
            if (this.PropertyChanged != null)
            {
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propName));
            }
        }
    }

    界面类:

    public class Window2 : Window
    {
        private Label label = new Label();
        private TextBox textBox = new TextBox();
        private StackPanel stackPanel = new StackPanel();
        private MyData md = new MyData(20);
        //初始化UI并创建绑定
        public Window2()
        {
            label.Width = 240;
            label.Height = 30;
            label.Content = "??";
            textBox.Width = 240;
            textBox.Height = 20;
            stackPanel.Children.Add(label);
            stackPanel.Children.Add(textBox);
            this.Content = stackPanel;
            textBox.Focus();
            Binding b = new Binding("Intx") { Source = md, Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
            textBox.SetBinding(TextBox.TextProperty, b);
            textBox.PreviewKeyDown+=new KeyEventHandler(tbKeyDown);
            textBox.TextChanged+=new TextChangedEventHandler(ttTextChanged);
        }
        //文本框响应上下方向键
        private void tbKeyDown(object sender, KeyEventArgs e)
        {
            TextBox t = (TextBox)sender;
            switch (e.Key)
            {
                case Key.Down:
                    t.Text = (Convert.ToInt32(t.Text) - 1).ToString();
                    break;
                case Key.Up:
                    t.Text = (Convert.ToInt32(t.Text) + 1).ToString();
                    break;
            }
        }
        //强制更新文本框内容,不编写这一事件的话方向键会将文本框内容改变到远离数据区域
        private void ttTextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox t = (TextBox)sender;
            t.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
        }
        //点击窗口查看数据当前值
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            label.Content = "数据当前值:" + md.Intx.ToString() + ",文本框Text属性:" + textBox.Text;
        }
    }
    数据初始值20,在文本框中按住向下方向键会减小,按住向上方向键会增加。数据的有效区域是0-100,在文本框直接输入数值会自动修正超过有效区域的输入,但按下会降低到-1,按上会升高到101,此时点击窗体可以发现textBox的显示值与Text属性不一致。
    2009年12月23日 4:09
  •     private void tbKeyDown(object sender, KeyEventArgs e)
        {
            TextBox t = (TextBox)sender;
            switch (e.Key)
            {
                case Key.Down:
                    if (int.Parse(t.Text) >0) t.Text = (Convert.ToInt32(t.Text) - 1).ToString();
                    break;
                case Key.Up:
                    if(int.Parse(t.Text)<100)
                    t.Text = (Convert.ToInt32(t.Text) + 1).ToString();
                    break;
            }
        }
    原因是优先执行操作+1时候更新了绑定值  再赋值文本框盖住了绑定更新值的bug 
    2009年12月24日 6:15
  •     private void tbKeyDown(object sender, KeyEventArgs e)
        {
            TextBox t = (TextBox)sender;
            switch (e.Key)
            {
                case Key.Down:
                    if (int.Parse(t.Text) >0) t.Text = (Convert.ToInt32(t.Text) - 1).ToString();
                    break;
                case Key.Up:
                    if(int.Parse(t.Text)<100)
                    t.Text = (Convert.ToInt32(t.Text) + 1).ToString();
                    break;
            }
        }
    原因是优先执行操作+1时候更新了绑定值  再赋值文本框盖住了绑定更新值的bug 

    我又用各种方法来操作,最后发现,只要 tbKeyDown 里面操作的是 Text 属性,就会出现这个问题,要解决问题只有直接操作数据:
    private void tbKeyDown(Object sender,KeyEventArgs e)
    {
      TextBox t = (TextBox)sender;
      switch(e.Key)
      {
        case Key.Down:md.Intx -= 1;break;
        case Key.Up:md.Intx += 1;break;
      }
    }
    也就意味着如果要实现我需要的逻辑,必须在界面元素中直接操作数据,所以数据绑定是用不了的,要让数据与界面解耦是做不到的。这样理解对吗?
    2009年12月28日 6:03
  • 可以......
    2009年12月28日 7:29