gpt4 book ai didi

c# - WPF 绑定(bind)到集合中多个对象的相同属性

转载 作者:行者123 更新时间:2023-11-30 14:08:42 26 4
gpt4 key购买 nike

我正在尝试使用 WPF 创建一个界面,该界面可以一次显示和修改多个选定对象的属性。我知道这一定是可能的(Visual Studio 中的属性网格可以做到)但我一直无法找到有关如何实现它的任何信息或示例。我发现了很多关于 MultiBinding 的信息,但是它的典型用例似乎是将一个 UI 字段绑定(bind)到同一对象上的多个属性,而我正试图做相反的事情——将 UI 字段绑定(bind)到同一个属性在多个对象上。

更明确地说,我想要创建的行为是这样的:

  • 如果选择了单个对象,则该对象的属性是显示
  • 如果选择了多个对象,则根据以下逻辑显示属性:
    • 如果所有选定的对象在该属性中具有相同的值,则显示该值
    • 如果所选对象在该属性中具有不同的值,则显示“[Multi]”(或类似的)
  • 输入值后,所有选定对象的绑定(bind)属性都设置为该值。

例如,这是我的一个旧的 WinForms 窗体,它做同样的事情,我或多或少试图在 WPF 中重新创建它。在那种情况下,我在没有数据绑定(bind)的情况下在代码隐藏中处理它,我不太愿意重复这种经历。

选择了一个项目:

enter image description here

选择了多个项目(元素类型、 Material 和 Beta 角属性相同,其他不同):

enter image description here

针对我的特定用例的一些其他注意事项:

  • 几乎我的应用程序的整个 UI 都需要以这种方式工作,所以越容易重复越好
  • 所选项目的数量可能在 1 到 100000 之间(尽管通常会在几十个数量级左右 - 大量选择的一些轻微延迟可能是可以的,只要它不会变得不可用)
  • 将有几种不同类型的数据我想要使其可编辑,每种都有自己的定制界面(即我实际上不想要通用的 Property Grid 解决方案)
  • 我要绑定(bind)的数据类型是在我(部分)编写但其他几个人和项目使用的单独且公开可用的库中定义的。因此,如果绝对必要,我可以修改这些类型,但我不想对它们做任何过于激烈的事情。

我目前对如何执行此操作的最佳猜测是使用 MultiBinding(或其自定义子类),跟踪基础集合中的更改,并以编程方式添加或删除对每个对象的属性的绑定(bind)MultiBinding 绑定(bind)集合,然后写一个IMultiValueConverter 来确定显示值。然而,这似乎有点麻烦,并不是 MultiBindings 的真正设计目的,互联网舆论似乎不赞成使用 MultiBindings,除非绝对必要(尽管我不完全确定为什么)。有没有更好/更直接/标准的方法来做到这一点?

最佳答案

在我看来,对象封装在这方面确实能为您提供帮助,而不是试图让 MultiBinding 做一些它实际上没有能力处理的事情。

因此,在没有看到您的代码的情况下,我将做出一些假设:

  1. 你有一个 ViewModel代表每个对象。我们称之为ObjectViewModel .
  2. 您有一个顶级 ViewModel代表您页面的状态。我们称之为PageViewModel .

ObjectViewModel可能具有以下属性:

string Name { get; set; }
string ElementType { get; set; }
string SelectionProfile { get; set; }
string Material { get; set; }
... etc

PageViewModel可能有以下内容:

// Represents a list of selected items
ObjectSelectionViewModel SelectedItems { get; }

注意新类ObjectSelectionViewModel ,它不仅代表您选择的项目,而且允许您将其绑定(bind)到它,就好像它是单个对象一样。它可能看起来像这样:

public class ObjectSelectionViewModel : ObjectViewModel
{
// The current list of selected items.
public ObservableCollection<ObjectViewModel> SelectedItems { get; }

public ObjectSelectionViewModel()
{
SelectedItems = new ObservableCollection<ObjectViewModel>();
SelectedItems.CollectionChanged += (o, e) =>
{
// Pseudo-code here
if (items were added)
{
// Subscribe each to PropertyChanged, using Item_PropertyChanged
}
if (items were removed)
{
// Unsubscribe each from PropertyChanged
}
};
}

void Item_PropertyChanged(object sender, NotifyPropertyChangedArgs e)
{
// Notify that the local, group property (may have) changed.
NotifyPropertyChanged(e.PropertyName);
}

public override string Name
{
get
{
if (SelectedItems.Count == 0)
{
return "[None]";
}
if (SelectedItems.IsSameValue(i => i.Name))
{
return SelectedItems[0].Name;
}
return string.Empty;
}
set
{
if (SelectedItems.Count == 1)
{
SelectedItems[0].Name = value;
}
// NotifyPropertyChanged for the traditional MVVM ViewModel pattern.
NotifyPropertyChanged("Name");
}
}

public override string SelectionProfile
{
get
{
if (SelectedItems.Count == 0)
{
return "[None]";
}
if (SelectedItems.IsSameValue(i => i.SelectionProfile))
{
return SelectedItems[0].SelectionProfile;
}
return "[Multi]";
}
set
{
foreach (var item in SelectedItems)
{
item.SelectionProfile = value;
}
// NotifyPropertyChanged for the traditional MVVM ViewModel pattern.
NotifyPropertyChanged("SelectionProfile");
}
}

... etc ...
}

// Extension method for IEnumerable
public static bool IsSameValue<T, U>(this IEnumerable<T> list, Func<T, U> selector)
{
return list.Select(selector).Distinct().Count() == 1;
}

你甚至可以实现 IList<ObjectViewModel>INotifyCollectionChanged在这个类上将它变成一个你可以直接绑定(bind)到的全功能列表。

关于c# - WPF 绑定(bind)到集合中多个对象的相同属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33920396/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com