Это меня поставило в тупик. Я нашел код , опубликованный Рэй Бернсом , чтобы создать DependencyProperty для TextBox, который позволяет вам ограничить, какие символы могут быть удалены пользователем. Я немного изменил его, чтобы вместо этого ограничить, какие символы могут быть вставлены , и использовал это для создания текстовых полей, которые принимают только числовой ввод (плюс десятичную точку).
Это прекрасно работает для ввода текста с клавиатуры, вставки, перетаскивания и т. Д. Единственная проблема возникает при настройке текста с помощью кода. Там он позволяет вводить нечисловой текст, что само по себе не является проблемой. Проблема заключается в том, что если после этого вы проверяете значение свойства Text TextBox, оно говорит, что это пустая строка.
Вот код, демонстрирующий, что я имею в виду. Простое окно 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 /3223453/kak-otsledit-kakoi-simvol-udalen-v-textbox-v-wpf#3223466.
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;
}
});
}
}
Если вы попытаетесь набрать текстовый блок, вы увидите, что он работает почти так же, как и ожидалось, и что нажатие кнопки «Проверить значение» точно отражает текст; однако, если вы нажмете кнопку «Ввести текст», а затем нажмите кнопку «Проверить значение», вы увидите, что приложение считает, что свойство Text в TextBox представляет собой пустую строку (даже несмотря на то, что в пользовательском интерфейсе текст четко виден). Если вы каким-либо образом измените текст в пользовательском интерфейсе (скажем, удалите символ), а затем нажмите «Проверить значение», теперь он распознает правильный текст.
Может кто-нибудь пролить свет на то, почему это происходит? Возможно, я упускаю что-то явно очевидное, но я просто не могу понять это.
Заранее спасибо!
Jeff