代码之家  ›  专栏  ›  技术社区  ›  Jesper Larsen-Ledet

如何使绑定尊重DependencyProperty值强制?

  •  11
  • Jesper Larsen-Ledet  · 技术社区  · 17 年前

    我有一个控件,它具有DependencyProperty和强制值回调。 此属性绑定到模型对象的属性。

    当将Control属性设置为导致强制的值时,绑定将推送 非强制的 模型对象的值。控件的属性值被正确强制。

    我怎样才能把胶订好 强制的 模型对象的值?

    void Initialize()
    {
        UIObject ui = new UIObject();
        ModelObject m = new ModelObject();
        m.P = 4;
    
        Binding b = new Binding("P");
        b.Source = m;
        b.Mode = BindingMode.TwoWay;
        Debug.WriteLine("SetBinding");
        // setting the binding will push the model value to the UI
        ui.SetBinding(UIObject.PProperty, b);
    
        // Setting the UI value will result in coercion but only in the UI.
        // The value pushed to the model through the binding is not coerced.
        Debug.WriteLine("Set to -4");
        ui.P = -4;
    
        Debug.Assert(ui.P == 0);
        // The binding is TwoWay, the DP value is coerced to 0.
        Debug.Assert(m.P == 0); // Not true. This will be -4. Why???
    }
    
    class UIObject : FrameworkElement
    {
        public static readonly DependencyProperty PProperty =
            DependencyProperty.Register("P", typeof(int), typeof(UIObject), 
            new FrameworkPropertyMetadata(
                new PropertyChangedCallback(OnPChanged), 
                new CoerceValueCallback(CoerceP)));
    
        public int P
        {
            get { return (int)GetValue(PProperty); }
            set { SetValue(PProperty, value); }
        }
    
        private static void OnPChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Debug.WriteLine(typeof(UIObject) + ".P changed from " + e.OldValue + " to " + e.NewValue);
        }
    
        private static object CoerceP(DependencyObject sender, object value)
        {
            int p = (int)value;
            if (p < 0)
            {
                Debug.WriteLine(typeof(UIObject) + ".P coerced from " + p + " to 0");
                p = 0;
            }
            return p;
        }
    }
    
    class ModelObject
    {
        private int p;
        public int P
        {
            get
            {
                Debug.WriteLine(this + ".P returned " + this.p);
                return this.p;
            }
            set
            {
                Debug.WriteLine(this + ".P changed from +" + this.p + " to " + value);
                this.p = value;
            }
        }
    }
    
    3 回复  |  直到 9 年前
        1
  •  1
  •   Steven    17 年前

    我不认为强制回调是双向的。一个解决方法是在强制回调中更新模型的值。

        2
  •  2
  •   HolisticElastic    16 年前

    我认为这就是强制-正确值的整个概念,不会触发任何其他依赖项的修改。您可以使用下面的代码而不是本机强制机制:

    OnPChanged(/* ... */)
    {
        // ...
        var coercedP = CoerceP(P);
        if (P != coercedP)
            P = coercedP;
        // ...
    }
    

    Hth.

        3
  •  0
  •   Smagin Alexey    9 年前

    这里是扩展方法,您可以在其中设置目标对象的值

    public static void SetTargetValue<T>(this FrameworkElement element, DependencyProperty dp, T value)
        {
            var binding = BindingOperations.GetBinding(element, dp);
            if (binding == null) return;
            var name = binding.Path.Path;
            var splits = name.Split('.');
            var target = element.DataContext;
            for (var i = 0; i < splits.Length; i++)
            {
                PropertyInfo property;
                if (i == splits.Length - 1)
                {
                    property = target.GetType().GetProperty(splits[i]);
                    property.SetValue(target, value);
                }
                else
                {
                    property = target.GetType().GetProperty(splits[i]);
                    target = property.GetValue(target);
                }
            }
        }
    

    所以,在这个方法中,使用绑定,可以将值设置为source。当然,源路径可以有很多名称-property1.property2.property3等等。 在强制方法中,只需调用此方法:

    private static object CoerceProperty(DependencyObject d, object baseValue)
        {
            if (!Check)
            {
                var sender = (FrameworkElement)d;
                sender.SetTargetValue(MyPropertyProperty, myValue);
                return needValue;
            }
            return baseValue;
        }