首页 > 解决方案 > 将 IObservableMap 绑定到 ItemsControl(例如 ListView)

问题描述

我无法使用 C++/WinRT 将 IObservableMap 绑定到 ListView。我的 MainPage.xaml 看起来像这样:

<ListView ItemsSource="{x:Bind TestCollection}">
</ListView>

whereTestCollection是带有签名的方法winrt::Windows::Foundation::Collections::IObservableMap<hstring, hstring> TestCollection()

ItemsSource但是,在运行应用程序时,当将属性设置为TestCollectionwith时,它会在 XAML 设置代码中崩溃HRESULT: 0x80070057 (E_INVALIDARG),这并没有真正告诉我太多,只是它不喜欢将地图作为参数。

我已经就此事咨询了文档,并在这里提出了与 MS 文档有关的问题,因为它们是矛盾的。总结一下:

ItemsSource 属性文档说:

The ItemsSource property value must implement one of these interfaces:
IIterable<IInspectable>
IBindableIterable

第一个 IObservableMap 实际上是根据 C++/WinRT 标头实现的,而 C++/WinRT 文档说:

If you want to bind a XAML items control to your collection, then you can. 
But be aware that to correctly set the ItemsControl.ItemsSource property, you need to set it to a value of type IVector of IInspectable (or of an interoperability type such as IBindableObservableVector).

当用 IObservableVector 替换 IObservableMap 时,一切都按预期工作。
我还尝试在 C# 中使用(不可观察的)字典做同样的事情,它工作得很好,这让我有点困惑。CLR 如何做到这一点?是在某处将 Dictionary 转换为 IVector 吗?它不适用于 C++ 中的 IMap,因此必须进行某种转换,对吧?

编辑:在大量浪费时间和汇编级调试Windows.UI.Xaml.dll之后,我发现了以下内容:

有没有办法让这个工作?
我曾考虑过制作一个自定义集合,但这意味着我需要同时实现这两种方法IIterable<IKeyValuePair<K,V>>,并且IIterable<IInspectable>我已经尝试了一段时间,但这会使编译器感到困惑,因为它有两种First()方法,而且我不知道该选择哪一种不知道该怎么办。
同样,CLR 如何解决这个问题?

标签: uwp-xamlc++-winrt

解决方案


字典,它工作得很好,这让我有点困惑。CLR 如何做到这一点?

在 C# 中Dictionary<TKey,TValue> 实现 IEnumerable<KeyValuePair<TKey,TValue>>

对于 C++/CX,有Platform::Collections::Map这个集合还实现了所有必要的接口。

对于 C++/WinRT,有winrt::observable_map_base struct。这也实现了所有必要的接口。

来自文档的示例实现:

...
#include <iostream>
using namespace winrt;
using namespace Windows::Foundation::Collections;
...
struct MyObservableMap :
    implements<MyObservableMap, IObservableMap<winrt::hstring, int>, IMap<winrt::hstring, int>, IMapView<winrt::hstring, int>, IIterable<IKeyValuePair<winrt::hstring, int>>>,
    winrt::observable_map_base<MyObservableMap, winrt::hstring, int>
{
    auto& get_container() const noexcept
    {
        return m_values;
    }

    auto& get_container() noexcept
    {
        return m_values;
    }

private:
    std::map<winrt::hstring, int> m_values{
        { L"AliceBlue", 0xfff0f8ff }, { L"AntiqueWhite", 0xfffaebd7 }
    };
};
IObservableMap<winrt::hstring, int> map{ winrt::make<MyObservableMap>() };

for (auto const& el : map)
{
    std::wcout << el.Key().c_str() << L", " << std::hex << el.Value() << std::endl;
}

IIterator<IKeyValuePair<winrt::hstring, int>> it{ map.First() };
while (it.HasCurrent())
{
    std::wcout << it.Current().Key().c_str() << L", " << std::hex << it.Current().Value() << std::endl;
    it.MoveNext();
}

推荐阅读