Over-simplifying our model for the purposes of this example, let's say we have two lists of data, ListA and ListB, both of which are of type List<string>
. From a data perspective, they are not related. ListA and ListB can be added to, removed from, or otherwise updated independently.
What we're trying to do is display them both at the same time in the same list, aligned by ordinal position.
Our first approach was to create a new ListMapping object as follows:
public class ListMapping
{
public int Index{ get; set; }
public string StringA{ get; set; }
public string StringB{ get; set; }
}
then create a List<ListMapping>
relating the strings at ordinal position 'x' of ListA and ListB and we'd initialize it like this:
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);
}
The problem with this approach is we had to manually manage this new list of ListMap objects. If an item is deleted from ListB, then we need to manually shift all the ListMapping.StringB properties up one position to 'realign' with the new ListMapping.StringA. Same thing with Insert, etc.
Our next approach was to not actually store the string values in ListMapping, just the index, and make the getters return the value directly from the underlying lists, like this...
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; } }
}
And then we'd initialize the List<ListMapping>
object like this...
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);
}
Using this design, we'd simply need to trigger property changed notifications for the StringA and StringB properties of any ListMapping with an index that would have been affected by an operation on either ListA or ListB. Definitely cleaner and no held references to the source objects, but now they had to have a reference to the List objects themselves. Plus, we still need to manually manage the overall list of ListMapping items to ensure there's at least 'maxItems' items at all times. Better, but not ideal.
I can't help but wonder if there's a way to construct an ItemsControl to have two ItemsSource properties then do something clever with its layout panel and ItemContainerGenerator, but that just seems like I'd be doing in the UI what I'm already doing in the data.
So, any thoughts on a way to solve this issue?