在不清除绑定的情况下将 Silverlight 4 自定义 NumberBox 设为空白

发布于 2024-12-29 04:53:02 字数 2974 浏览 3 评论 0原文

我正在尝试创建自己的非常简单的从 TextBox 继承的 NumberBox,它验证失去焦点的输入并根据指定的小数位格式化值。一切正常,直到有人输入一些无效值。

如果值无效,我想将 NumberBox 设为空白而不是 0.0.0。将其重置为有效值(例如 0.0)将跳过我的代码中所需的字段验证检查。

我尝试了 this.Text = "" 但这会触发绑定异常“输入字符串格式不正确”

如果我尝试 this.ClearValue(TextProperty),它会清除文本框,但也会删除绑定。知道如何实现这一目标或除工具包之外更好的 NumberBox 吗?

public delegate void ValueChangedHandler(object sender, EventArgs args);
    public class NumberBox : TextBox
    {
        public event ValueChangedHandler ValueChanged;

        public NumberBox()
        {
            this.DefaultStyleKey = typeof(TextBox);
            this.LostFocus += new RoutedEventHandler(NumberBox_LostFocus);

        }

        public static readonly DependencyProperty DecimalPlacesProperty = DependencyProperty.Register(
            "DecimalPlaces",
            typeof(int),
            typeof(NumberBox),
            new PropertyMetadata(2));
        public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register(
    "MaxValue",
    typeof(double),
    typeof(NumberBox),
    new PropertyMetadata(Double.MaxValue));
        public static readonly DependencyProperty MinValueProperty = DependencyProperty.Register(
    "MinValue",
    typeof(double),
    typeof(NumberBox),
    new PropertyMetadata(0.0));

        public int DecimalPlaces
        {
            get
            {
                return (int)this.GetValue(DecimalPlacesProperty);
            }

            set
            {
                base.SetValue(DecimalPlacesProperty, value);
            }
        }
        public Double MaxValue
        {
            get
            {
                return (Double)this.GetValue(MaxValueProperty);
            }

            set
            {
                base.SetValue(MaxValueProperty, value);
            }
        }
        public Double MinValue
        {
            get
            {
                return (Double)this.GetValue(MinValueProperty);
            }

            set
            {
                base.SetValue(MinValueProperty, value);
            }
        }

        void NumberBox_LostFocus(object sender, RoutedEventArgs e)
        {
            double result;
            //if (this.Text.Trim().Length == 0)
            //    return;

            if (double.TryParse(this.Text, out result))
            {
                result = Math.Min(result, this.MaxValue);
                result = Math.Max(result, this.MinValue);

                this.Text = Math.Round(result, this.DecimalPlaces).ToString("N" + this.DecimalPlaces);
            }
            else
            {
                try
                {
                    //this.Text = Math.Min(this.MinValue, 0.0).ToString();
                    this.ClearValue(TextBox.TextProperty);
                }
                catch
                {

                }
            }
            if (ValueChanged != null)
                ValueChanged(this, EventArgs.Empty); 
        }
    }

I am trying to create my own very simple NumberBox inherited from TextBox that validates the input on lost focus and formats the value based on the specified decimal places. All works well until someone puts some invalid value.

In case of invalid value, I would like to make the NumberBox blank and not 0.0. Resetting it to a valid value like 0.0 will skip the required field validation check I have in my code.

I tried this.Text = "" but that triggers binding exception "Input String not in correct format"

If I try this.ClearValue(TextProperty), it clears the textbox but removes the binding too. Any idea how to achieve this or a better NumberBox other than the toolkit one?

public delegate void ValueChangedHandler(object sender, EventArgs args);
    public class NumberBox : TextBox
    {
        public event ValueChangedHandler ValueChanged;

        public NumberBox()
        {
            this.DefaultStyleKey = typeof(TextBox);
            this.LostFocus += new RoutedEventHandler(NumberBox_LostFocus);

        }

        public static readonly DependencyProperty DecimalPlacesProperty = DependencyProperty.Register(
            "DecimalPlaces",
            typeof(int),
            typeof(NumberBox),
            new PropertyMetadata(2));
        public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register(
    "MaxValue",
    typeof(double),
    typeof(NumberBox),
    new PropertyMetadata(Double.MaxValue));
        public static readonly DependencyProperty MinValueProperty = DependencyProperty.Register(
    "MinValue",
    typeof(double),
    typeof(NumberBox),
    new PropertyMetadata(0.0));

        public int DecimalPlaces
        {
            get
            {
                return (int)this.GetValue(DecimalPlacesProperty);
            }

            set
            {
                base.SetValue(DecimalPlacesProperty, value);
            }
        }
        public Double MaxValue
        {
            get
            {
                return (Double)this.GetValue(MaxValueProperty);
            }

            set
            {
                base.SetValue(MaxValueProperty, value);
            }
        }
        public Double MinValue
        {
            get
            {
                return (Double)this.GetValue(MinValueProperty);
            }

            set
            {
                base.SetValue(MinValueProperty, value);
            }
        }

        void NumberBox_LostFocus(object sender, RoutedEventArgs e)
        {
            double result;
            //if (this.Text.Trim().Length == 0)
            //    return;

            if (double.TryParse(this.Text, out result))
            {
                result = Math.Min(result, this.MaxValue);
                result = Math.Max(result, this.MinValue);

                this.Text = Math.Round(result, this.DecimalPlaces).ToString("N" + this.DecimalPlaces);
            }
            else
            {
                try
                {
                    //this.Text = Math.Min(this.MinValue, 0.0).ToString();
                    this.ClearValue(TextBox.TextProperty);
                }
                catch
                {

                }
            }
            if (ValueChanged != null)
                ValueChanged(this, EventArgs.Empty); 
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

迷爱 2025-01-05 04:53:02

直接设置属性或调用 ClearValue 实际上会覆盖 TextProperty 上的任何内容,这可能是 BindingExpression。您真正想做的只是设置值,而不真正更改其中的内容。听起来很混乱,整个 DependencyProperty 子系统也是如此。基本上将 ClearValue 替换为以下内容

this.SetValue(TextProperty, String.Empty)

您可以找到解释 依赖属性简介强制绑定更新。两者都适用于 WPF,但相关。但 UpdateTarget 在 Silverlight 中不起作用(解决方案即将推出)。

也就是说,这种方法仍然存在缺陷。也就是说,您的源(您绑定到的对象)仍将具有最新的有效值,即使根据您的 UI 该值为 。要解决此问题,如果您使用的是 WPF,您只需调用 UpdateTarget 从源获取最新的有效值并更新您的目标(文本框)。 Silverlight 不支持这一点,但是有一个讨厌的方法可以绕过这个限制:重新设置绑定。

您的代码将如下所示,而不是 ClearValue:

this.SetBinding(TextProperty, this.GetBindingExpression(TextProperty).ParentBinding);
if (double.TryParse(this.Text, out result))
{
    result = Math.Min(result, this.MaxValue);
    result = Math.Max(result, this.MinValue);
    this.Text = Math.Round(result, this.DecimalPlaces).ToString("N" + this.DecimalPlaces);
}

最后一个块与方法的开头重复,因为我们可能需要在获得最新的有效值后重新格式化字符串。可能值得创建一种方法来做到这一点。

希望这有帮助。

米格尔

Setting the property directly or calling ClearValue actually overrides whatever is on the TextProperty, which could be, a BindingExpression. What you really want to do is just set the value, without really changing what's in there. Sounds confusing and the whole DependencyProperty subsystem is. Basically replace ClearValue for the following

this.SetValue(TextProperty, String.Empty)

You could find an explanation Introduction to Dependency Properties and Force a binding to update. Both are for WPF, but relevant. UpdateTarget doesn't work in Silverlight though (solution coming).

That said, this approach still has a flaw. That's that your source (the object you bind to) will still have the latest valid value, even when according to your UI the value is . To fix this, if you were in WPF you would simply call UpdateTarget to get the latest valid value from the source and update your target (textbox). Silverlight doesn't support this, but there's a nasty way around this limitation: re-setting the binding.

Instead of ClearValue your code will look like this:

this.SetBinding(TextProperty, this.GetBindingExpression(TextProperty).ParentBinding);
if (double.TryParse(this.Text, out result))
{
    result = Math.Min(result, this.MaxValue);
    result = Math.Max(result, this.MinValue);
    this.Text = Math.Round(result, this.DecimalPlaces).ToString("N" + this.DecimalPlaces);
}

The last block is duplicated with the start of your method since we might need to reformat the string after we get the latest valid value. It might be worth creating a method to do this.

Hope this helps.

Miguel

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文