9

我有一个名为 MyComponent 的类,它有一个名为 BackgroundProperty 的 DependencyProperty。

public class MyComponent
{
    public MyBackground Background
    {
        get { return (MyBackground)GetValue(BackgroundProperty); }
        set { SetValue(BackgroundProperty, value); }
    }
    public static readonly DependencyProperty BackgroundProperty =
        DependencyProperty.Register("Background", typeof(MyBackground),
            typeof(MyComponent), new FrameworkPropertyMetadata(default(MyBackground), new PropertyChangedCallback(OnPropertyChanged)));
}

MyBackground 是一个派生自 DependencyObject 的类,它有一些 DependencyProperties。

public class MyBackground : DependencyObject
{
    public Color BaseColor
    {
        set { SetValue(BaseColorProperty, value); }
        get { return (Color)GetValue(BaseColorProperty); }
    }
    public static readonly DependencyProperty BaseColorProperty =
        DependencyProperty.Register("BaseColor", typeof(Color),
            typeof(MyBackground ), new UIPropertyMetadata(Colors.White));

    [...]
}

现在,我想要的是当来自 MyBackground 的属性发生更改时,通知 MyComponent MyBackground 已更改,并调用名为 OnPropertyChanged 的​​ PropertyChangedCallback。

4

4 回答 4

3

请耐心等待一秒钟,因为您似乎正试图违背 WPF 的原则。由于您似乎正在编写与显示逻辑相关的代码,因此使相关DependencyObjects 相互交互的典型方法是通过绑定。

例如,如果MyComponent是某种类型的控件并且它使用其Background中的属性ControlTemplate,您将使用TemplateBinding引用该Background属性和任何重要子属性的 a。

由于 1) 您可能已经知道,并且 2) 您没有使用模板或没有可用的模板,因此您可以在代码中设置绑定,以便对Background属性的更改做出反应。如果您提供有关您的OnPropertyChanged方法的更多详细信息,我可以提供一些示例代码。

于 2013-10-14T14:06:35.997 回答
3

执行您所描述的一种方法是从Freezable而不是 DependencyObject 派生。当 Freezable 的属性更改任何引用该 Freezable 的 DO 的 PropertyChangedCallback 时,将调用 MyComponent 的 Background 属性的回调。在这种情况下, e.OldValue 和 e.NewValue 将是相同的引用。在 WPF 内部,事件 args 上有一些标志,表明它是子对象更改。

这就是框架对画笔之类的东西所做的事情,因此如果说 SolidColorBrush 的 Color 属性发生更改,则可以使元素无效。如果一个对象永远不会改变(或者你想让它成为线程安全的),那么可以冻结该对象(即使其不可变)。

顺便说一句,我可能会避免使用背景作为属性的名称。大多数开发人员会假设它是 Brush 类型,因为框架在它的几个元素(例如控件、边框)上使用该命名属性。

于 2013-10-17T16:34:18.620 回答
2

听起来您想使用 DependencyPropertyDescriptor 和 AddValueChanged。

这是一篇关于它的文章:http: //www.codeproject.com/Articles/34741/Change-Notification-for-Dependency-Properties.aspx

..可能还有更好的实现:http ://agsmith.wordpress.com/2008/04/07/propertydescriptor-addvaluechanged-alternative/

于 2010-07-29T23:17:09.203 回答
1

这是我为 WPF 编写的一个小型静态扩展方法类——它允许您注册一个 EventHandler 或一个 Action 回调来更改任何 DependencyObject 上的任何 DependencyProperty。不需要更改依赖对象。

它还可以防止递归(即,如果您在回调期间更改相同的属性等)

它利用了 @ScottBilas 链接到的 DependencyPropertyDescriptor。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;

namespace BrainSlugs83.Writes.Too.Much.Code
{
    public static class WpfExtensions
    {
        public static void OnPropertyChanged<T>(this T obj, DependencyProperty prop, Action<T> callback) where T : DependencyObject
        {
            if (callback != null)
            {
                obj.OnPropertyChanged(prop, new EventHandler((o, e) =>
                {
                    callback((T)o);
                }));
            }
        }

        public static void OnPropertyChanged<T>(this T obj, DependencyProperty prop, EventHandler handler) where T : DependencyObject
        {
            var descriptor = DependencyPropertyDescriptor.FromProperty(prop, typeof(T));
            descriptor.AddValueChanged(obj, new EventHandler((o, e) =>
            {
                if (handler != null)
                {
                    if (o == null) { handler(o, e); }
                    else
                    {
                        lock (PreventRecursions)
                        {
                            if (IsRecursing(obj, prop)) { return; }
                            SetIsRecursing(obj, prop, true);
                        }

                        try
                        {
                            handler(o, e);
                        }
                        finally
                        {
                            SetIsRecursing(obj, prop, false);
                        }
                    }
                }
            }));
        }

        #region OnPropertyChanged Recursion Prevention

        private static readonly Dictionary<object, List<DependencyProperty>> PreventRecursions = new Dictionary<object, List<DependencyProperty>>();

        private static bool IsRecursing(object obj, DependencyProperty prop)
        {
            lock (PreventRecursions)
            {
                List<DependencyProperty> propList = null;
                if (PreventRecursions.ContainsKey(obj))
                {
                    propList = PreventRecursions[obj];
                }

                return propList == null ? false : propList.Contains(prop);
            }
        }

        private static void SetIsRecursing(object obj, DependencyProperty prop, bool value)
        {
            lock (PreventRecursions)
            {
                List<DependencyProperty> propList = null;
                if (PreventRecursions.ContainsKey(obj))
                {
                    propList = PreventRecursions[obj];
                }

                if (propList == null)
                {
                    if (!value) { return; }

                    propList = PreventRecursions[obj] = new List<DependencyProperty>();
                }

                if (value)
                {
                    if (!propList.Contains(prop))
                    {
                        propList.Add(prop);
                    }
                }
                else
                {
                    while (propList.Contains(prop))
                    {
                        propList.Remove(prop);
                    }

                    if (!propList.Any())
                    {
                        propList = PreventRecursions[obj] = null;
                    }
                }
            }
        }

        #endregion

        public static bool IsInDesignMode(this DependencyObject obj)
        {
            try
            {
                return DesignerProperties.GetIsInDesignMode(obj);
            }
            catch { /* do nothing */ }

            return false;
        }
    }
}
于 2013-11-25T06:07:16.240 回答