A collection unifying two collections into a single one by acting as a wrapping collection.
| Capability | Priority |
| :---------- | :------- |
| Allow to "merge" two IList into one | Must |
| Implement IList (IVector) interface | Must |
// Indexing works the following way:
// if(index < FirstSource.Count()) -> indexing in FirstSource
// else: index -= FirstSource.Count() -> indexing in SecondSource
//
class MergedCollection<T> : IVector<T>
{
public IInspectable FirstSource;
public IInspectable SecondSource;
// Appends to second collection
public void Append(T element)
{
SecondSource.Append(element);
}
public void Append(T element, bool appendFirstCollection)
{
if(appendFirstCollection)
{
FirstSource.Append(element);
}
else
{
SecondSource.Append(element);
}
}
// Clears both collections
Clear();
// See indexing above
GetAt(UInt32 index)
{
if(index < FirstSource.Count())
{
return FirstSource.GetAt(index);
}
else
{
return SecondSource.GetAt(index - FirstSource.Count());
}
}
// See indexing above
GetMany(UInt32 startIndex, T[] items)
// Should we support this?
GetView()
// Indexing behaves the same as explained above
IndexOf(T element, UInt32)
{
int index = FirstSource.IndexOf(element)
if(index == -1)
{
index = SecondSource.IndexOf(element);
if(index != -1)
{
index += FirstSource.Count();
}
}
return index;
}
// See indexing above
InsertAt(UInt32 index, T element)
// See indexing above
RemoveAt(UInt32 index)
// See indexing above
RemoveAtEnd()
// See indexing above
ReplaceAll(T[] items)
// See indexing above
SetAt(UInt32 index, T element)
}
FirstSource and SecondSource needs to be Inspectable similar to ItemsSource and support the same things supported by InspectingDataSource.
Would it be fine for MergedCollection to be IInspectable too? Or should it be an IVector?
MergedCollection needs to implement one of the interfaces (apart from Iterable, because we dont want to copy) InspectingDataSource understands so that it can be fed in as ItemsSource for a Repeater.
// Indexing behaves the same as explained above
IndexOf(T element, UInt32)
{
int index = FirstSource.IndexOf(element)
if(index == -1)
{
index = SecondSource.IndexOf(element);
}
if(index != -1)
{
index += FirstSource.Count();
}
return index;
}
If the specified element is part of [FirstSource], we get its index back (say index 0 for first element). Later, since that index is != -1, we add 'n' to it, where 'n' is the number of elements of [FirstSource]. So in this case we would return '0 + n = n' as the index when in fact we should return '0'.
Possible fix:
// Indexing behaves the same as explained above
IndexOf(T element, UInt32)
{
int index = FirstSource.IndexOf(element)
if(index != -1)
{
return index;
}
index = SecondSource.IndexOf(element);
if(index != -1)
{
index += FirstSource.Count();
}
return index;
}
Wait, so we would need to try to cast FirstSource/SecondSource into different interfaces just like ItemsSourceView?
Wait, so we would need to try to cast FirstSource/SecondSource into different interfaces just like ItemsSourceView?
Perhaps you can use the logic in ItemsSourceView ? Create an ItemsSourceView for Source1 and Source2 and then use the API's from that. I think for the API's that ItemsSourceView does not cover, you can throw not implemented since they will not be used by ItemsRepeater.
Good catch @FelixDev updated the proposal.
Wait, so we would need to try to cast FirstSource/SecondSource into different interfaces just like ItemsSourceView?
Perhaps you can use the logic in ItemsSourceView ? Create an ItemsSourceView for Source1 and Source2 and then use the API's from that. I think for the API's that ItemsSourceView does not cover, you can throw not implemented since they will not be used by ItemsRepeater.
Seems like the best approach here.
Should it be index that combine two collections, or it better to be IndexPath with 2 groups?
I don't think ItemsRepeater or ItemsSourceView support indexing using IndexPath.
And since we try to act as one collection, I think having two indices may be a bit counterintuitive.
SelectionModel supports. This collection purposed to be source for selection model
we combine two collections that are source for two different items repeater, but shares one selection model. So this class is for this selection model
Right. This is merging two collections into one, so no IndexPath's. It is all in one collection. IndexPath's come into play only when we nest collections together for grouping scenarios.
So every time when selection change we will need to calculate in which collection it was raised...
Another example:
we have MenuItems and FooterMenuItems merged in one collection.
We select Item in Footer menu.
Than we add item to MenuItems. And of course we need to keep item in footer menu selected
In case of integer index we will need to update selected index in selection model
In case of indexPath we don't
If we use IndexPath, we would lose support for the ItemsRepeater wouldn't we?
Source1 is source for Menu ItemsRepeater
Source2 is source for FooterMenu ItemsRepeater
MergedCollection is source for SelectionModel.
There is two items repeaters in BottomMenu implementation. but they should share common selection model because only one item can be selected in NavigationView
@ad1Dima are you proposing that we could create a vector that contains two items, first one is Source1 and second is Source2 and give the uber vector to SelectionModel instead of trying to merge them ? NavigationView internally will have to deal with index paths anyway. If we go down that route, we don't need a merged collection. @ojhad do you foresee any issues with that approach ?
Yes we should support SelectionModel in some way. The big question is, what are the minimum things we need to support?
We could of course support both versions, that is normal index and using IndexPath.
are you proposing that we could create a vector that contains two items
Perhaps this would be best decision
are you proposing that we could create a vector that contains two items
may be this would be better decision
That does sound simpler. The difference is that SelectionModel will have one more level that NavigationView needs to expect and account for. Maybe that is a relatively simple change?
So is this proposal still relevant or should we close it?
That does sound simpler. The difference is that SelectionModel will have one more level that NavigationView needs to expect and account for. Maybe that is a relatively simple change?
I'll try this tomorrow. It is midnight in Siberia :-)
@ojhad fyi
Is this similar to what CompositeCollection did in WPF? Should it have a similar name/API for upgrade path scenarios?
And what about observable scenarios?
The main idea was to have two collections merged into one since for the FooterItems in NavigationView, we could internally have used that. Since that however was not further considered, we might just provide a WinUI compatible version for composite collection, agreed.
Regarding observable, I think we should probably support it? I am not entirely sure how that would behave though, especially with multiple collections and not just two.
@michael-hawker This is the same idea as CompositeCollection and would make sense to see/match the APIs if we end up doing this. The proposal was initially created to serve NavigationView as @chingucoding mentions, but a different solution was chosen. If we did this, it would support observable cases as well. The merged collection would listen to collection changed on each collection and raise INCC itself.
Thanks for the info @ranjeshj, I've definitely seen a couple of different types of ObservableCollection wrappers that could be useful for developers. I'm working on one now in the Toolkit for one of our controls, so it could make sense to provide some solutions in the Toolkit package for now and look if any would make sense for WinUI in the future.
Most helpful comment
I'll try this tomorrow. It is midnight in Siberia :-)