gpt4 book ai didi

c# - BindingList 投影包装器

转载 作者:太空宇宙 更新时间:2023-11-03 11:49:59 25 4
gpt4 key购买 nike

有没有一种简单的方法来创建一个 BindingList 包装器(带投影),它会随着原始列表的更新而更新?

例如,假设我有一个可变的数字列表,我想在 ComboBox 中将它们表示为十六进制字符串。使用这个包装器我可以做这样的事情:

BindingList<int> numbers = data.GetNumbers();
comboBox.DataSource = Project(numbers, i => string.Format("{0:x}", i));

我可以将列表包装到一个新的 BindingList 中,处理所有源事件,更新列表并再次触发这些事件,但我觉得已经有更简单的方法了。

最佳答案

我刚刚偶然发现了这个问题,我意识到我可能会发布我最终得到的代码。

因为我想要一个快速的解决方案,所以我做了一个穷人的实现。它作为现有源列表的包装器工作,但它创建一个完整的项目列表并根据需要更新它。起初我希望我可以在访问项目时即时进行投影,但这需要从头开始实现整个 IBindingList 接口(interface)。

作用:对源列表的任何更新也会更新目标列表,因此绑定(bind)控件将得到正确更新。

它不做什么:当目标列表更改时,它不会更新源列表。那将需要一个倒投影功能,而我并不需要那个功能。因此必须始终在源列表中添加、更改或删除项目。

用法示例 如下。假设我们有一个数字列表,但我们想在数据网格中显示它们的平方值:

// simple list of numbers
List<int> numbers = new List<int>(new[] { 1, 2, 3, 4, 5 });

// wrap it in a binding list
BindingList<int> sourceList = new BindingList<int>(numbers);

// project each item to a squared item
BindingList<int> squaredList = new ProjectedBindingList<int, int>
(sourceList, i => i*i);

// whenever the source list is changed, target list will change
sourceList.Add(6);
Debug.Assert(squaredList[5] == 36);

这里是源代码:

public class ProjectedBindingList<Tsrc, Tdest> 
: BindingList<Tdest>
{
private readonly BindingList<Tsrc> _src;
private readonly Func<Tsrc, Tdest> _projection;

public ProjectedBindingList(
BindingList<Tsrc> source,
Func<Tsrc, Tdest> projection)
{
_projection = projection;
_src = source;
RecreateList();
_src.ListChanged += new ListChangedEventHandler(_src_ListChanged);
}

private void RecreateList()
{
RaiseListChangedEvents = false;
Clear();

foreach (Tsrc item in _src)
this.Add(_projection(item));

RaiseListChangedEvents = true;
}

void _src_ListChanged(object sender, ListChangedEventArgs e)
{
switch (e.ListChangedType)
{
case ListChangedType.ItemAdded:
this.InsertItem(e.NewIndex, Proj(e.NewIndex));
break;

case ListChangedType.ItemChanged:
this.Items[e.NewIndex] = Proj(e.NewIndex);
break;

case ListChangedType.ItemDeleted:
this.RemoveAt(e.NewIndex);
break;

case ListChangedType.ItemMoved:
Tdest movedItem = this[e.OldIndex];
this.RemoveAt(e.OldIndex);
this.InsertItem(e.NewIndex, movedItem);
break;

case ListChangedType.Reset:
// regenerate list
RecreateList();
OnListChanged(e);
break;

default:
OnListChanged(e);
break;
}
}

Tdest Proj(int index)
{
return _projection(_src[index]);
}
}

我希望有人会觉得这很有用。

关于c# - BindingList 投影包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2369857/

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