WPF中TextBox.Text属性的奇怪情况

时间:2010-09-08 22:29:22

标签: wpf text textbox

这个让我难过。我找到了一些code posted by Ray Burns来为TextBox创建DependencyProperty,允许您限制用户可以删除哪些字符。我修改了一下来改为限制哪些字符可以插入,并用它来创建只接受数字输入(加上小数点)的TextBox。

这非常适合通过键盘输入文本,粘贴,拖放等。唯一的问题是通过代码设置文本时。在那里它允许输入非数字文本,这本身并不是真正的问题。问题是,如果在执行此操作后检查TextBox的Text属性的值,则表示它是一个空字符串。

这里有一些代码来证明我的意思。一个简单的WPF窗口:

<Window x:Class="TestApp.Test"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:TestApp"
        Title="Test" Height="125" Width="200">
    <Canvas>
        <TextBox x:Name="txtTest" Canvas.Left="10" Canvas.Top="10" Width="100" my:TextBoxRestriction.RestrictInsertTo=".0123456789"></TextBox>
        <Button Canvas.Left="10" Canvas.Top="40" Click="Button_Click">Enter Text</Button>
        <Button Canvas.Left="75" Canvas.Top="40" Click="Button_Click_1">Check Value</Button>
    </Canvas>
</Window>

它的代码隐藏:

using System;
using System.Windows;

namespace TestApp
{
    public partial class Test : Window
    {
        public Test()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            txtTest.Text = "Test";
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(txtTest.Text, "Length = " + txtTest.Text.Length.ToString());
        }
    }
}

我修改雷的课程:

using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace TestApp
{
    //Based on code by Ray Burns at https://stackoverflow.com/questions/3051590/how-to-track-which-character-is-deleted-in-textbox-in-wpf/3056168#3056168.
    public class TextBoxRestriction : DependencyObject
    {
        //RestrictInsertTo: Set this to the characters that may be inserted.
        public static string GetRestrictInsertTo(DependencyObject obj)
        {
            return (string)obj.GetValue(RestrictInsertToProperty);
        }

        public static void SetRestrictInsertTo(DependencyObject obj, string value)
        {
            obj.SetValue(RestrictInsertToProperty, value);
        }

        public static readonly DependencyProperty RestrictInsertToProperty = DependencyProperty.RegisterAttached("RestrictInsertTo", typeof(string), typeof(TextBoxRestriction), new PropertyMetadata
        {
            PropertyChangedCallback = (obj, e) =>
            {
                var box = (TextBox)obj;

                box.TextChanged += (obj2, changeEvent) =>
                {
                    var oldText = GetUnrestrictedText(box);
                    var allowedChars = GetRestrictInsertTo(box);

                    if (box.Text == oldText || allowedChars == null) return;

                    foreach (var change in changeEvent.Changes)
                    {
                        if (change.AddedLength > 0)
                        {
                            string added = box.Text.Substring(change.Offset, change.AddedLength);

                            if (added.Any(ch => !allowedChars.Contains(ch)))
                            {
                                var ss = box.SelectionStart;
                                var sl = box.SelectionLength;

                                box.Text = oldText;
                                box.SelectionStart = ss;
                                box.SelectionLength = sl;
                            }
                        }
                    }

                    SetUnrestrictedText(box, box.Text);
                };
            }
        });

        //UnrestrictedText: Bind or access this property to update the Text property bypassing all restrictions.
        public static string GetUnrestrictedText(DependencyObject obj)
        {
            return (string)obj.GetValue(UnrestrictedTextProperty);
        }

        public static void SetUnrestrictedText(DependencyObject obj, string value)
        {
            obj.SetValue(UnrestrictedTextProperty, value);
        }

        public static readonly DependencyProperty UnrestrictedTextProperty = DependencyProperty.RegisterAttached("UnrestrictedText", typeof(string), typeof(TextBoxRestriction), new PropertyMetadata
        {
            DefaultValue = "",
            PropertyChangedCallback = (obj, e) =>
            {
                var box = (TextBox)obj;

                box.Text = (string)e.NewValue;
            }
        });
    }
}

如果您尝试键入TextBox,您会看到它的工作方式与预期相同,并且单击“检查值”按钮可以准确地反映文本;但是,如果单击“输入文本”按钮,然后单击“检查值”按钮,您将看到应用程序认为TextBox的Text属性为空字符串(即使UI中的文本清晰可见)。如果以任何方式修改UI中的文本(例如删除一个字符),然后单击“检查值”,它现在可以识别正确的文本。

任何人都可以解释为什么会这样吗?我可能会遗漏一些显而易见的东西,但我似乎无法弄明白。

提前致谢!

杰夫

1 个答案:

答案 0 :(得分:2)

我认为您还需要在obj.SetValue(TextProperty, value)方法中执行SetUnrestrictedText

<击>

这是第一个猜测。如果不是这样的话,我会更深入地研究它,没有其他人回复。

我尝试使用我的机器上的示例代码VS2010,.NET 4.附加属性每次都会重置TextBox的Text属性。我尝试了几种无效输入的变种。

如果你想要的是DependencyObject 过滤掉代码中的赋值,拒绝无效字符并保留有效字符,那么你需要一个不同于if (added.Any(ch => !allowedChars.Contains(ch)))的测试。 / p>