Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using IMap/IObservableMap as ItemsSource for ListView #1612

Open
Holo-Krzysztof opened this issue Nov 14, 2019 · 21 comments
Open

Using IMap/IObservableMap as ItemsSource for ListView #1612

Holo-Krzysztof opened this issue Nov 14, 2019 · 21 comments
Labels
area-XamlCompiler feature proposal New feature proposal team-Markup Issue for the Markup team

Comments

@Holo-Krzysztof
Copy link

Also posted here.

I've described the problem on StackOverflow already and also filed a docs issue before finding out that the docs are actually technically right.

To summarize, I can bind an IVector<T> to a ListView control just fine, but when I substitute it with an IMap<K,V> or IObservableMap<K,V> I get exceptions. As I've found out this is due to IMap<K,V> not implementing IIterable<IInspectable> which is what the ItemsSource property expects.

However, it is possible to use Dictionary in C# and everything works just fine, so there must be something else happening here. Do you know how to CLR handles this and how I can accomplish this in C++?

Steps to reproduce the bug

  • Create a XAML ListView and bind an IMap<K, V> to ItemsSource property using x:Bind

Expected behavior
The ListView shows key-value pairs the same way as when using a Dictionary in C#

Version Info

Windows 10 version Saw the problem?
18363.476 Yes
Device form factor Saw the problem?
Desktop Yes
@msft-github-bot msft-github-bot added the needs-triage Issue needs to be triaged by the area owners label Nov 14, 2019
@stevenbrix
Copy link
Contributor

stevenbrix commented Nov 15, 2019

Collections and generics are a notoriously difficult problem with WinRT.

@Holo-Krzysztof the CLR wraps (or implements, I don't remember) the collection with one that implements the IBindableIterable interface (and any other IBindable* interface).

I'm fairly certain the CX projection layer does this as well, but I'd have to double check. Does your issue reproduce there as well, or is it specific to cpp/winrt?

@jevansaks
Copy link
Member

There's an email thread going about this with @kennykerr to try to figure out what we should do. .NET implements IEnumerable<KeyValuePair<...>> on its Dictionary type so C++/WinRT could implement similar for consistency. @kennykerr if you agree this is on cppwinrt can we create the issue over in that repo?

@jevansaks jevansaks added the team-Markup Issue for the Markup team label Nov 15, 2019
@kennykerr
Copy link

We already have an issue for this: microsoft/cppwinrt#418

The main unknown is this:

.NET implements IEnumerable<KeyValuePair<...>> on its Dictionary type so C++/WinRT could implement similar for consistency

What exactly C++/WinRT should implement is the question and one that only the Xaml team can definitively answer. C++/WinRT already implements IMap<K, V>, IOberservableMap<K, V>, and IIterable<IKeyValuePair<K, V>>. IEnumerable<...> is a .NET type and thus not something that C++/WinRT can implement. So without that information, I have no actionable data to keep the issue open.

You can find the C++/WinRT implementation here.

Feel free to suggest an implementation that will satisfy Xaml.

@MikeHillberg
Copy link
Contributor

.Net implements IEnumerable<KeyValuePair<K,V>>, which projects to WinRT as IIterable<IKeyValuePair<K,V>>. It also implements IEnumerable, which projects as IIterable.

Could e.g. winrt::impl::observable_map similarly implement IIterable? It means that observable_map in this case needs to implement an adapter that's a pass-through for instance types, and does boxing for value types.

@kennykerr
Copy link

Could e.g. winrt::impl::observable_map similarly implement IIterable?

IIterable of what? IIterable is a generic/parameterized interface. Do you mean IIterable<IInspectable>? Then what is the IInspectable?

@MikeHillberg
Copy link
Contributor

Sorry, yes, I meant IIterable. Generalizing to the IIterable case, when T is an instance type the IInspectable is the T instance. When T is a value type, IInspectable is a boxed T.

@kennykerr
Copy link

Sure, that's what we do for vectors already - box the value. The question is what to do with associative containers where there is a key and a value. How do we box the pair such that Xaml will accept it?

@stevenbrix
Copy link
Contributor

Do you mean IIterable< IInspectable >? Then what is the IInspectable?

@kennykerr I would imagine you are correct here in that it is IIterable<IInspectable*>. In this case the IInspectable is the IKeyValuePair<X,Y>, I don't think there needs to be any special boxing since the IKeyValuePair already is an IInspectable

@kennykerr
Copy link

Sure, we can do that. 👍

@MikeHillberg
Copy link
Contributor

Right, the ListView doesn't have to understand the properties of the item type, the DataTemplate takes care of that.

@kennykerr
Copy link

Forgive me for being skeptical, but if the ListView doesn't know how to handle generics like IIterable<IKeyValuePair<K, V>> and I must provide IIterable<IInspectable>, what makes the DataTemplate able to unpack an IInspectable that's actually an IKeyValuePair<K, V>? Does the IIterable<IInspectable> maybe need to iterate over IInspectable values that are actually IKeyValuePair<IInspectable, IInspectable> rather than IKeyValuePair<K, V>?

@MikeHillberg
Copy link
Contributor

One mechanism the DataTemplate has is reflection (if you're using {Binding} in a C# app). And in fact in a C# app, even if the ItemsSource isn't a C# collection, ListView runs the ItemsSource through C# to get it to reflect. So this scenario still works.

The other mechanism the DataTemplate has is code gen (if your're using {x:Bind}, or optionally when using {Binding} in a C++ app).

There's almost enough information for Xaml to solve this ItemsSource problem with code gen though, and solve this and another problem ...

Today, you do the following to show a list of people's names:

<ListView ItemsSource="{x:Bind People}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Person">
            <TextBlock Text="{x:Bind Name}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

To the reader, the x:DataType is redundant; you could figure this out by looking at the type of the People collection property (it's an IIterable<Person> or IEnumerable<Person>). The Xaml language doesn't understand this though, because the language doesn't understand ListView; ItemsSource and ItemTemplate are just two properties, there's nothing statically available to understand the connection.

Potentially though the language could define some metadata to set on the ListView properties, to make that connection. Then the x:DataType wouldn't be necessary, and it could generate code to do the extraction of items from the ItemsSource.

@kennykerr
Copy link

kennykerr commented Nov 16, 2019

Here is a simple implementation that implements IIterable<IInspectable>, as has been suggested by the Xaml team. If someone can test this against Xaml and confirm that this provides the desired behavior then we can update C++/WinRT to do the same.

https://gist.github.com/kennykerr/6eace7378a1a06b5e2f21da127be102a

@Holo-Krzysztof
Copy link
Author

cppwinrtMapBinding

The default output is slightly weird (compared to C# which stringifies the KeyValuePair), but it does work. Usually there's a DataTemplate and controls are binding to more specific properties anyway, so it should be ok.

Thanks a lot for the fix and the quick responses!

@danzil
Copy link

danzil commented Nov 18, 2019

Yeah, thanks for the quick response @kennykerr!

@danzil danzil closed this as completed Nov 18, 2019
@msft-github-bot msft-github-bot removed the needs-triage Issue needs to be triaged by the area owners label Nov 18, 2019
@danzil danzil added the bug Something isn't working label Nov 18, 2019
@kennykerr
Copy link

@Holo-Krzysztof are you actually able to retrieve the key and value from the pairs within the data template?

@msft-github-bot msft-github-bot added the needs-triage Issue needs to be triaged by the area owners label Nov 21, 2019
@Holo-Krzysztof
Copy link
Author

I just tried, and I'm not quite sure how to do that since there is no concrete type I can set on DataTemplate's x:DataType.

If there was a way to just get the boxed value the container returns I think I could use function bindings to cast from IInspectable to IKeyValuePair and retrieve the data I want, but x:Object as data type is not supported in UWP XAML.

Is there a way to tell the DataTemplate to give me an IInspectable?

@jevansaks
Copy link
Member

I'm going to reopen this issue just so that @danzil sees this discussion when he gets back. :)

@jevansaks jevansaks reopened this Nov 25, 2019
@danzil
Copy link

danzil commented Nov 25, 2019

@Holo-Krzysztof there's currently no way to pass the "item" to a function binding in the same scope. Nor there is a way to pass a generic type into x:DataType. The only way to make this work is if the items in the collection you set in ItemsSource are castable to a non generic type that you can pass into x:DataType. We have a work item to add support for accessing "item" in function binding parameters and also one to allow the use of generics, although that one is more complicated. We could keep this issue to enable support for this scenario.

@danzil danzil added area-XamlCompiler feature proposal New feature proposal and removed bug Something isn't working needs-triage Issue needs to be triaged by the area owners labels Nov 25, 2019
@lawabider
Copy link

lawabider commented Jan 16, 2020

Has anyone been able to display the Key and Value in a ListView? I'm not sure if my XAML is correct. I can only get a stringification of the KeyValuePair:
image

My XAML is:
image

Also the changes (e.g. Clear()) don't seem to be showing up on the UI.

@PankajBhojwani
Copy link

Are there any plans to resolve this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-XamlCompiler feature proposal New feature proposal team-Markup Issue for the Markup team
Projects
None yet
Development

No branches or pull requests

9 participants