从WPF窗口检索所有数据绑定

4
我有一个WPF窗体,上面有很多控件。其中许多(但不是全部)控件都绑定到底层对象。在某些时候,例如按下保存按钮时,我需要检查所有控件的验证规则。有没有一种程序化的方法来做到这一点,而不需要硬编码一个要验证的控件列表?我希望即使另一个开发人员添加了另一个控件和另一个绑定,它也能继续工作,而不必更新一些要刷新的绑定列表。
简而言之,是否有任何方法从WPF窗口中检索所有数据绑定的集合?

这个问题比较模糊,所以我不能确定。但是,任何遇到类似情况的人可能想要考虑使用 BindingGroup 来组织相关的绑定,以便可以完成一次性验证。 - Peter Duniho
2个回答

8
尝试使用以下示例。我没有完全测试它,因此可能存在问题。此外,性能可能值得怀疑。也许其他人可以帮助加快速度。但无论如何,它似乎能够解决问题。
注意:然而,这个方法的限制是它可能无法捕获在样式或数据模板中定义的绑定。我不确定。需要更多测试。
总之,该解决方案基本上有三个部分:
1. 使用VisualTreeHelper遍历整个可视树。 2. 对于可视树中的每个项,获取所有依赖属性。 Reference。 3. 使用BindingOperations.GetBindingBase获取每个属性的绑定。
GetBindingsRecursive函数:
void GetBindingsRecursive(DependencyObject dObj, List<BindingBase> bindingList)
        {
            bindingList.AddRange(DependencyObjectHelper.GetBindingObjects(dObj));

            int childrenCount = VisualTreeHelper.GetChildrenCount(dObj);
            if (childrenCount > 0)
            {
                for (int i = 0; i < childrenCount; i++)
                { 
                    DependencyObject child = VisualTreeHelper.GetChild(dObj, i);
                    GetBindingsRecursive(child, bindingList);
                }
            }
        }

DependencyObjectHelper类:

public static class DependencyObjectHelper
    {
        public static List<BindingBase> GetBindingObjects(Object element)
        {
            List<BindingBase> bindings = new List<BindingBase>();
            List<DependencyProperty> dpList = new List<DependencyProperty>();
            dpList.AddRange(GetDependencyProperties(element));
            dpList.AddRange(GetAttachedProperties(element));

            foreach (DependencyProperty dp in dpList)
            {
                BindingBase b = BindingOperations.GetBindingBase(element as DependencyObject, dp);
                if (b != null)
                {
                    bindings.Add(b);
                }
            }

            return bindings;
        }

        public static List<DependencyProperty> GetDependencyProperties(Object element)
        {
            List<DependencyProperty> properties = new List<DependencyProperty>();
            MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(element);
            if (markupObject != null)
            {
                foreach (MarkupProperty mp in markupObject.Properties)
                {
                    if (mp.DependencyProperty != null)
                    {
                        properties.Add(mp.DependencyProperty);
                    }
                }
            }

            return properties;
        }

        public static List<DependencyProperty> GetAttachedProperties(Object element)
        {
            List<DependencyProperty> attachedProperties = new List<DependencyProperty>();
            MarkupObject markupObject = MarkupWriter.GetMarkupObjectFor(element);
            if (markupObject != null)
            {
                foreach (MarkupProperty mp in markupObject.Properties)
                {
                    if (mp.IsAttached)
                    {
                        attachedProperties.Add(mp.DependencyProperty);
                    }
                }
            }

            return attachedProperties;
        }
    }

使用示例:

List<BindingBase> bindingList = new List<BindingBase>();
GetBindingsRecursive(this, bindingList);

foreach (BindingBase b in bindingList)
{
     Console.WriteLine(b.ToString());
}

为什么要使用VisualTreeHelper而不是LogicalTreeHelper?有具体的原因吗? - John Leidegren
在我的情况下,我需要使用LogicalTreeHelper,否则我的树中并没有找到所有的UIElement。我不太了解Visual/LogicalTreeHelper,无法解释这一点,但我想让其他人知道。 - Michael Repucci
方法GetAttachedProperties几乎是重复的,似乎没有返回附加属性的绑定。 - ManIkWeet

6

.NET 4.5及以上版本提供了更好的解决方案:

foreach (BindingExpressionBase be in BindingOperations.GetSourceUpdatingBindings(element))
{
    be.UpdateSource();
}

2
这并不完全做相同的事情,因为它只返回处于特定状态的绑定。你不能使用它来查找所有绑定。 - John Leidegren

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接