简体   繁体   English

无法让DependencyProperty工作

[英]Can't get DependencyProperty to work

I wrote a small attached property called "IsValid" for the WPF TextBox, like so: 我为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;
    }
}

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. 在初始化( DependencyProperty )之后, IsValid没有任何方法被调用。 What am I missing? 我错过了什么?

Earlier you probably got an error telling you that IsValid needs to derive from DependecyObject , so you added that, you should have asked yourself why that is. 早些时候你可能会收到一个错误,告诉你IsValid需要从DependecyObject派生,所以你补充说,你应该问问自己为什么会这样。 The answer is right here: 答案就在这里:

public static readonly DependencyProperty InputProperty = DependencyProperty.Register(...

You try to register a normal property for objects on type IsValid , change it to RegisterAttached and it should work. 您尝试为IsValid类型的对象注册一个普通属性,将其更改为RegisterAttached ,它应该工作。 (I would also remove the inheritance and make IsValid a static class) (我也会删除继承并使IsValid成为静态类)

Ok, so the core of the problem was trivial (see accepted answer): I needed to call DependencyProperty.RegisterAttached(...) (as opposed to DependencyProperty.Register(...) . 好的,所以问题的核心是微不足道的(参见接受的答案):我需要调用DependencyProperty.RegisterAttached(...) (而不是DependencyProperty.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. 我决定废弃使用简单的enum来指定输入类型,并决定使用标记扩展。

The attached property implementation now looks like this: 附加的属性实现现在看起来像这样:

public static class IsValid
{
    public static readonly DependencyProperty InputProperty = DependencyProperty.RegisterAttached(
        "Input",
        typeof(IsValidInputExtension),
        typeof(IsValid),
        new UIPropertyMetadata(onInput));

    public static IsValidInputExtension GetInput(DependencyObject d)
    {
        return (IsValidInputExtension)d.GetValue(InputProperty);
    }

    public static void SetInput(DependencyObject d, IsValidInputExtension value)
    {
        d.SetValue(InputProperty, value);
    }

    private static void onInput(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBox = (TextBox)d;
        var value = (IsValidInputExtension)e.NewValue;
        if (value == null)
        {
            textBox.PreviewTextInput -= validateInput;
            textBox.PreviewKeyDown -= validateKeyDown;
            return;
        }
        textBox.PreviewTextInput += validateInput;
        textBox.PreviewKeyDown += validateKeyDown;
    }

    private static void validateInput(object sender, TextCompositionEventArgs e)
    {
        // dispatch validation to specified markup class ...
        var textBox = (TextBox) sender;
        var markup = (IsValidInputExtension)textBox.GetValue(InputProperty);
        markup.ValidateInput(sender, e);
    }

    private static void validateKeyDown(object sender, KeyEventArgs e)
    {
        // dispatch validation to specified markup class ...
        var textBox = (TextBox)sender;
        var markup = (IsValidInputExtension)textBox.GetValue(InputProperty);
        markup.ValidateKeyDown(sender, e);
    }
}

And here's part of the markup extension classes: 这是标记扩展类的一部分:

public abstract class IsValidInputExtension : MarkupExtension
{
    internal abstract void ValidateInput(object sender, TextCompositionEventArgs e);
    internal abstract void ValidateKeyDown(object sender, KeyEventArgs e);
}

public class NumericExtension : IsValidInputExtension
{
    public double Minimum { get; set; }

    public double Maximum { get; set; }

    public uint Decimals { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    internal override void ValidateInput(object sender, TextCompositionEventArgs e)
    {
        var textBox = (TextBox) sender;
        if (isDecimalSeparator(e.Text) && Decimals == 0)
        {
            e.Handled = true;
            return;
        }

        // todo: honor Minimum and Maximum ...
    }

    private static bool isDecimalSeparator(string s)
    {
        return CultureInfo.CurrentUICulture.NumberFormat.CurrencyDecimalSeparator == s;
    }

    internal override void ValidateKeyDown(object sender, KeyEventArgs e)
    {
        // block [SPACE] when numeric input is expected ...
        e.Handled = e.Key == Key.Space;
    }
}

public class StringExtension : IsValidInputExtension
{
    public double MaximumLength { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    internal override void ValidateInput(object sender, TextCompositionEventArgs e)
    {
        // (nop)
    }

    internal override void ValidateKeyDown(object sender, KeyEventArgs e)
    {
        // todo: honor MaximumLength here
    }
}

The end result, in XAML, is quite nice and easy to read... 在XAML中,最终结果非常好,易于阅读......

<TextBox v:IsValid.Input="{v:Numeric Minimum=0, Maximum=99, Decimals=0}" />

It all seems to work as I hoped. 这一切似乎都像我希望的那样奏效。 Thanks for all input 感谢所有输入

Cheers 干杯

/Jonas /乔纳斯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 MultiTrigger:条件绑定到 DependencyProperty 不起作用 - MultiTrigger: Condition Binding to DependencyProperty doesn't work 为什么无法显示 DependencyProperty 的默认值 - why can't show the default value of DependencyProperty 无法为DependencyProperty的ICommand设置默认值 - Can't set default value for ICommand of an DependencyProperty 无法绑定到DependencyObject的DependencyProperty子级 - Can't bind to DependencyProperty child of DependencyObject WPF-绑定到自定义UserControl的DependencyProperty不起作用 - WPF - Binding to custom UserControl's DependencyProperty doesn't work 将UserControl绑定到其自己的dependencyProperty不起作用 - Binding UserControl to its own dependencyProperty doesn't work 无法将样式应用于基于DependencyProperty的RichTextBox元素 - Can't apply style to RichTextBox elements based on DependencyProperty 在没有 DependencyProperty 失败的情况下无法从 db 填充集合 - Can't populate collection from db without DependencyProperty failure 无法在WPF中绑定从DependenyObject派生的类的DependencyProperty? - Can't Bind the DependencyProperty of a Class Derived from DependenyObject in WPF? 为什么我不能使用C#将数组绑定到依赖项属性? - Why can't I binding a array to a dependencyproperty using c#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM