无法使 DependencyProperty 工作
我为 WPF TextBox 编写了一个名为“IsValid”的小附加属性,如下所示:
public enum InputTypes
{
Any,
Integer,
Double,
Float
}
/// <summary>
/// This attached property can be used to validate input for <see cref="TextBox"/>.
/// </summary>
public class IsValid : DependencyObject
{
public static readonly DependencyProperty InputProperty = DependencyProperty.Register(
"Input",
typeof(InputTypes),
typeof(IsValid),
new UIPropertyMetadata(InputTypes.Any, onInput));
public static InputTypes GetInput(DependencyObject d)
{
return (InputTypes)d.GetValue(InputProperty);
}
public static void SetInput(DependencyObject d, InputTypes value)
{
d.SetValue(InputProperty, value);
}
private static void onInput(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBox = (TextBox)d;
var value = (InputTypes)e.NewValue;
switch (value)
{
case InputTypes.Any:
textBox.PreviewTextInput -= validateInput;
textBox.PreviewKeyDown -= validateKeyDown;
break;
default:
textBox.PreviewTextInput += validateInput;
textBox.PreviewKeyDown += validateKeyDown;
break;
}
}
private static void validateInput(object sender, TextCompositionEventArgs e)
{
// enforce numeric input when configured ...
var textBox = (TextBox) sender;
var inputTypes = (InputTypes) textBox.GetValue(InputProperty);
foreach (var c in e.Text)
{
switch (inputTypes)
{
case InputTypes.Integer:
if (!char.IsDigit(c))
{
e.Handled = true;
return;
}
break;
case InputTypes.Double:
case InputTypes.Float:
if (!char.IsNumber(c))
{
e.Handled = true;
return;
}
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
private static void validateKeyDown(object sender, KeyEventArgs e)
{
// block [SPACE] when numeric input is expected ...
var textBox = (TextBox)sender;
var inputTypes = (InputTypes)textBox.GetValue(InputProperty);
if (inputTypes != InputTypes.Any && e.Key == Key.Space)
e.Handled = true;
}
}
下面是我使用它的方式:
<Window x:Class="Spike.Wpf.Controls.TestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:values="clr-namespace:Spike.Wpf.Controls.Input;assembly=Spike.Wpf.Controls"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox values:IsValid.Input="Double" />
</Grid>
然而,在(DependencyProperty
)初始化之后,IsValid
中的任何方法都不会被调用。我缺少什么?
I wrote a small attached property called "IsValid" for the WPF TextBox, like so:
public enum InputTypes
{
Any,
Integer,
Double,
Float
}
/// <summary>
/// This attached property can be used to validate input for <see cref="TextBox"/>.
/// </summary>
public class IsValid : DependencyObject
{
public static readonly DependencyProperty InputProperty = DependencyProperty.Register(
"Input",
typeof(InputTypes),
typeof(IsValid),
new UIPropertyMetadata(InputTypes.Any, onInput));
public static InputTypes GetInput(DependencyObject d)
{
return (InputTypes)d.GetValue(InputProperty);
}
public static void SetInput(DependencyObject d, InputTypes value)
{
d.SetValue(InputProperty, value);
}
private static void onInput(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBox = (TextBox)d;
var value = (InputTypes)e.NewValue;
switch (value)
{
case InputTypes.Any:
textBox.PreviewTextInput -= validateInput;
textBox.PreviewKeyDown -= validateKeyDown;
break;
default:
textBox.PreviewTextInput += validateInput;
textBox.PreviewKeyDown += validateKeyDown;
break;
}
}
private static void validateInput(object sender, TextCompositionEventArgs e)
{
// enforce numeric input when configured ...
var textBox = (TextBox) sender;
var inputTypes = (InputTypes) textBox.GetValue(InputProperty);
foreach (var c in e.Text)
{
switch (inputTypes)
{
case InputTypes.Integer:
if (!char.IsDigit(c))
{
e.Handled = true;
return;
}
break;
case InputTypes.Double:
case InputTypes.Float:
if (!char.IsNumber(c))
{
e.Handled = true;
return;
}
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
private static void validateKeyDown(object sender, KeyEventArgs e)
{
// block [SPACE] when numeric input is expected ...
var textBox = (TextBox)sender;
var inputTypes = (InputTypes)textBox.GetValue(InputProperty);
if (inputTypes != InputTypes.Any && e.Key == Key.Space)
e.Handled = true;
}
}
End here's how I've used it:
<Window x:Class="Spike.Wpf.Controls.TestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:values="clr-namespace:Spike.Wpf.Controls.Input;assembly=Spike.Wpf.Controls"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox values:IsValid.Input="Double" />
</Grid>
After the initialization (of the DependencyProperty
) none of the methods in IsValid
gets called however. What am I missing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
早些时候,您可能收到一个错误,告诉您
IsValid
需要从DependecyObject
派生,因此您添加了这一点,您应该问自己为什么会这样。答案就在这里:您尝试为
IsValid
类型的对象注册一个普通属性,将其更改为RegisterAttached
并且它应该可以工作。 (我还会删除继承并使IsValid
成为静态类)Earlier you probably got an error telling you that
IsValid
needs to derive fromDependecyObject
, so you added that, you should have asked yourself why that is. The answer is right here:You try to register a normal property for objects on type
IsValid
, change it toRegisterAttached
and it should work. (I would also remove the inheritance and makeIsValid
a static class)好的,所以问题的核心是微不足道的(请参阅接受的答案):我需要调用
DependencyProperty.RegisterAttached(...)
(而不是DependencyProperty.Register(...) 代替
只是想分享结果。我决定放弃使用简单的
enum
来指定输入类型,并决定使用标记扩展来。
这是一部分标记扩展类:
XAML 中的最终结果非常好且易于阅读...
这一切似乎都按我希望的方式工作,谢谢您的所有输入
干杯
/乔纳斯。
Ok, so the core of the problem was trivial (see accepted answer): I needed to call
DependencyProperty.RegisterAttached(...)
(as opposed toDependencyProperty.Register(...)
.Just wanted to share the result. I decided to scrap the use of a simple
enum
to specify input type and decided to use markup extensions instead.The attached property implementation now looks like this:
And here's part of the markup extension classes:
The end result, in XAML, is quite nice and easy to read...
It all seems to work as I hoped. Thanks for all input
Cheers
/Jonas