出于本示例的目的,过度简化了我们的模型,假设我们有两个数据列表 ListA 和 ListB,它们的类型都是List<string>
。从数据的角度来看,它们是不相关的。ListA 和 ListB 可以独立添加、删除或更新。
我们要做的是在同一个列表中同时显示它们,按序号位置对齐。
我们的第一种方法是创建一个新的 ListMapping 对象,如下所示:
public class ListMapping
{
public int Index{ get; set; }
public string StringA{ get; set; }
public string StringB{ get; set; }
}
然后在 ListA 和 ListB 的序数位置“x”处创建一个List<ListMapping>
关联的字符串,我们将像这样初始化它:
var MappedList = new List<ListMapping>();
var maxItems = Math.Max(ListA.Count, ListB.Count);
for(int index = 0; index < maxItems; index++)
{
var lm = new ListMapping(){
Index = index,
StringA = (index < ListA.Count) ? ListA[index] : null;
StringB = (index < ListB.Count) ? ListB[index] : null;
}
MappedList.Add(lm);
}
这种方法的问题是我们必须手动管理这个新的 ListMap 对象列表。如果从 ListB 中删除了一个项目,那么我们需要手动将所有 ListMapping.StringB 属性上移一个位置以与新的 ListMapping.StringA“重新对齐”。与插入等相同。
我们的下一个方法是实际上不将字符串值存储在 ListMapping 中,只存储索引,并让 getter 直接从底层列表返回值,就像这样......
public class ListMapping
{
public int Index{ get; set; }
public string StringA{ get{ (Index < ListA.Count) ? ListA[Index] : null; } }
public string StringB{ get{ (Index < ListB.Count) ? ListB[Index] : null; } }
}
然后我们会List<ListMapping>
像这样初始化对象......
var MappedList = new List<ListMapping>();
var maxItems = Math.Max(ListA.Count, ListB.Count);
for(int index = 0; index < maxItems; index++)
{
var lm = new ListMapping(){
Index = index
}
MappedList.Add(lm);
}
使用这种设计,我们只需要触发任何 ListMapping 的 StringA 和 StringB 属性的属性更改通知,其索引可能会受到 ListA 或 ListB 上的操作的影响。绝对更干净,没有对源对象的引用,但现在他们必须引用 List 对象本身。另外,我们仍然需要手动管理 ListMapping 项目的整体列表,以确保始终至少有 'maxItems' 个项目。更好,但并不理想。
我不禁想知道是否有一种方法可以构造一个 ItemsControl 以具有两个 ItemsSource 属性,然后用它的布局面板和 ItemContainerGenerator 做一些聪明的事情,但这似乎就像我会在 UI 中做我已经在做的事情在数据中。
那么,关于解决这个问题的方法有什么想法吗?