2010-09-08 78 views
3

这一个让我难住。我发现一些code posted by Ray Burns为TextBox创建DependencyProperty,允许您限制用户可以删除哪些字符。我对其进行了一些修改,以限制插入的哪些字符可以插入,并用它来创建仅接受数字输入(加上小数点)的文本框。WPF中的TextBox.Text属性的奇怪情况

这很适合通过键盘输入文本,粘贴,拖放等。唯一的问题是通过代码设置文本时出现的问题。在那里它允许输入非数字文本,这本身并不是真正的问题。问题是,如果您在完成后检查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="."></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的Text属性是一个空字符串(即使它具有在UI中清晰可见的文本)。如果您以任何方式修改UI中的文本(例如删除一个字符),然后单击检查值,它现在会识别正确的文本。

任何人都可以阐明为什么发生这种情况?我可能会错过显而易见的东西,但我似乎无法弄清楚。

在此先感谢!

杰夫

回答

2

您需要在您的 SetUnrestrictedText方法也做了一个 obj.SetValue(TextProperty, value),我想。

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

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

如果你想要的是对的DependencyObject到过滤掉分配入代码,拒绝无效字符,并保持有效的,那么你需要一个不同的测试比if (added.Any(ch => !allowedChars.Contains(ch)))

+0

感谢您的回复,Rob!不幸的是,添加该行代码后行为没有改变。 – JTennessen 2010-09-09 14:37:16

+1

Rob,我意识到这让我花了不可思议的时间来回答这个问题,但我终于有机会在VS2010中使用.NET 4进行尝试了,而且我也和你一样。显然,不管是什么原因导致这个问题已经在.NET 4中改变了。感谢您的提示! – JTennessen 2012-04-11 22:02:22