我正在尝试使用WPF创建一个界面,该界面可以一次显示和修改多个选定对象的属性 . 我知道这一定是可能的(Visual Studio中的属性网格可以做到),但我无法找到有关如何实现它的任何信息或示例 . 我已经在MultiBinding上找到了很多信息,但是规范的用例似乎是将一个UI字段绑定到同一个对象上的多个属性,而我正在尝试相反 - 将UI字段绑定到同一个属性在多个对象上 .
更明确一点,我想要创建的行为是这样的:
-
如果选择单个对象,则显示该对象的属性
-
如果选择了多个对象,则会根据以下逻辑显示属性:
-
如果所有选定对象在该属性中具有相同的值,则显示该值
-
如果所选对象在该属性中具有不同的值,则显示'[Multi]'(或类似)
-
输入值时,所有选定对象都将bound属性设置为该值 .
举例来说,这是我的一个旧的WinForms形式,它做同样的事情,我或多或少尝试在WPF中重新创建 . 在那种情况下,我在没有数据绑定的代码隐藏中处理它,这是一种我并不特别渴望重复的经验 .
选择一个项目:
选择了多个项目(元素类型,材质和Beta角度属性相同,其他不同):
我特定用例的其他一些注意事项:
-
几乎我的应用程序的整个UI都需要以这种方式工作,因此更容易重复更好
-
所选项目的数量范围可以从1-100000(尽管通常会在几十个左右) - 如果不会变得无法使用,那么巨大选择的一些轻微延迟可能是正常的
-
我将会有几种不同类型的数据实际上需要一个通用的Property Grid解决方案
-
我绑定的数据类型是在一个单独的,可公开使用的库中定义的,我(部分)编写但是其他几个人和项目使用 . 所以,如果我必须这样做,我可以修改这些类型,但我不想对它们做太过激烈的事情 .
我目前关于如何执行此操作的最佳猜测是使用MultiBinding(或其自定义子类),跟踪基础集合中的更改,并以编程方式将对每个对象的属性的绑定添加或移除到MultiBinding Bindings集合,然后编写一个IMultiValueConverter来确定显示值 . 然而,这似乎是一个小提琴,不是真正的MultiBindings设计和互联网意见似乎不喜欢使用MultiBindings除了绝对必要的地方(虽然我不完全确定为什么) . 这样做有更好/更直接/标准的方式吗?
4 回答
在我看来,对象封装在这里真的会帮助你,而不是试图让MultiBinding做一些它没有真正能够处理的东西 .
所以,在没有看到你的代码的情况下,我会做出几个假设:
您有一个代表每个对象的
ViewModel
. 我们称之为ObjectViewModel
.您有一个代表页面状态的顶级
ViewModel
. 我们称之为PageViewModel
.ObjectViewModel
可能具有以下属性:和
PageViewModel
可能包含以下内容:请注意新类
ObjectSelectionViewModel
,它不仅代表您选择的项目,还允许您绑定它,就好像它是单个对象一样 . 它可能看起来像这样:您甚至可以在此类上实现
IList<ObjectViewModel>
和INotifyCollectionChanged
,将其转换为可以直接绑定的功能齐全的列表 .这个功能不是WPF开箱即用的,但有一些选项如何实现:
使用一些第三方控件,支持一次编辑多个对象,例如PropertyGrid from Extended WPF Toolkit
创建与对象具有相同属性但包装对象集合的包装器对象 . 然后绑定到这个包装类 .
优点是它很简单 . 缺点是您需要为要编辑的每个类创建包装器 .
3.您可以使用自定义
TypeDescriptor
来创建通用包装类 . 在您的自定义TypeDescriptor
重写GetProperties()方法,所以它将返回相同属性作为您的对象 . 您还需要使用重写的GetValue
和SetValue
方法创建自定义PropertyDescriptor
,以便它可以与您的对象集合进行编辑像这样的东西应该工作(在ViewModel中):
然后将
SomeProperty
绑定到必须显示/编辑其值的任何内容,您就完成了 .我不认为您可以按照您希望它们开箱即用的方式进行绑定 . 但是,您可以通过在类型的包装类中处理它来使PropertyChanged事件对您有利 . 在下面的代码中,MultiEditable类处理EditItem属性的PropertyChanged事件 . 如果您有一个用户正在编辑梁的属性的表单,您需要将表单上的输入控件绑定到EditItem的属性 . 您将需要覆盖_EditItem_PropertyChanged,如图所示,从那里您可以更新所选项目的属性,因为EditItem的属性已更改 . 不要忘记取消处理事件 .
编辑:我忘了添加代码来检查所有属性是否与某个值相同 . 这很容易做 - 只需检查集合并比较所有项目的属性与EditItem的相同属性 . 如果它们都是相同的返回true,否则“Multi”或任何你需要的 . 您还可以在代码中引用MultiEditable - 只需更新EditItem属性,所选项目和视觉效果都将更新 .