【问题标题】:WPF controls with "invalid" values具有“无效”值的 WPF 控件
【发布时间】:2012-04-25 09:25:32
【问题描述】:

我正在创建一个自动完成框,它使用有效值列表(对象,而不是字符串)。对象直接绑定,框(文本框和下拉部分)使用 DisplayMemberPath 来确定要显示为文本的内容。

我希望用户能够输入文本 - 如果文本与有效值之一不匹配,我希望它保留在框中并在视觉上被标记为无效。

现在,当我绑定到视图模型时,显然我需要为这个无效值设置一些东西。我尝试将值设置为 DependencyProperty.UnsetValue。这将作为 null 返回到 VM。

如果我以后想“清除”我的表单,我将 VM 属性设置为 null,但这当然不会过滤到控件,因为值没有改变。

我希望属性系统会注意到新值为 null 而旧值为 UnsetValue 并因此触发事件。

我是否遗漏了一些明显的东西?

谢谢

【问题讨论】:

    标签: .net wpf .net-4.0 dependency-properties


    【解决方案1】:

    您可以为无效值创建自己的标记对象,而不是设置对 WPF 框架具有特殊含义的 DependencyProperty.UnsetValue,例如

    public static Object Dummy = new Object();
    

    您可能应该使用与您的有效值相同的类,而不是 Object。现在,当您重置 VM 时,该值会真正发生变化,而 WPF 会注意到差异。

    【讨论】:

    • 您的答案是 - 令人沮丧 - 可能是最接近解决方案的答案。 UnsetValue 应该意味着当从绑定源提供 null 时,它会被重新应用。但是,这不会发生,将 UnsetValue 渲染为与 null 完全相同,这完全违背了它的目的(根据 MSDN)。
    • 还有一个特殊值 Binding.DoNothing,但这也对你没有帮助,因为据我了解,你希望 VM 属性发生变化,所以 VM 知道有一个无效值,不是吗?
    • 不,如果存在无效值,VM 应该只有 null。但是我希望 CONTROL 知道它是否具有无效值,并在将其重置为 null 时将其清除。我认为如果在内部将 DP 设置为 UnsetValue,然后从 VM 将其设置为 null,这将通过属性更改来实现,但事实并非如此。这使得 UnsetValue 在我的 POV 中完全无用。
    【解决方案2】:

    一种简单且独立于验证框架的方法是让 VM 完成这项工作。

    例如

    public class MyVM : MyBaseVM
    {
        private ObservableCollection<Object> _items
            = new ObservableCollection<Object>();
        public ObservableCollection<Object> Items
        {
            get
            {
                return _items;
            }
        }
    
        private string _text;
        public string Text
        {
            get
            {
                return _text;
            }
            set
            {
                _text = value;
                Validate();
    
                if (_isValid)
                    _model.Text = value;
    
                NotifyPropertyChanged("Text");
            }
        }
    
        private bool _isValid = true;
        public bool IsValid
        {
            get
            {
                return _isValid;
            }
            private set
            {
                _isValid = value;
                NotifyPropertyChanged("IsValid");
            }
        }
    
        private void Validate()
        {
            IsValid = _items.Any(i =>
                i.ToString().ToLower() == _text.ToLower().Trim());
        }
    }
    

    【讨论】:

    • 但我需要所有可能使用此控件的属性的所有这些代码,此外我直接绑定到一个对象并使用显示成员路径而不是绑定到字符串:(跨度>
    • @Steve 您可以使用每个属性的相同类创建一个子虚拟机。还请重构您的问题,使条件更加透明。
    • 谢谢,我更新了问题。是的,看起来这是唯一的出路。不幸的是,虽然我使用 UnsetValue 可能会产生一些结果,所以我不必过度设计视图模型。
    猜你喜欢
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 2013-07-28
    • 2012-04-11
    • 1970-01-01
    • 2015-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多