uwp-xaml - 将 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
但是,在运行应用程序时,当将属性设置为TestCollection
with时,它会在 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
之后,我发现了以下内容:
- ItemsSource 方法的实现做了一个
QueryInterface
forIIterable<IInspectable>
- 参数化接口的 IID 是根据插入的类型参数生成的
- 即使你实现
IIterable<IKeyValuePair<K,V>>
了IInspectable
这并不意味着你实现了IIterable<IInspectable>
- 我头疼
有没有办法让这个工作?
我曾考虑过制作一个自定义集合,但这意味着我需要同时实现这两种方法IIterable<IKeyValuePair<K,V>>
,并且IIterable<IInspectable>
我已经尝试了一段时间,但这会使编译器感到困惑,因为它有两种First()
方法,而且我不知道该选择哪一种不知道该怎么办。
同样,CLR 如何解决这个问题?
解决方案
字典,它工作得很好,这让我有点困惑。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();
}
推荐阅读
- android - intent.setType("application/pdf") 允许选择任何文件
- regex - 匹配列表列表的字符串并将它们导出到 Excel
- scala - 将流值添加到 Scala 中的现有 Map
- javascript - 理解时间参数的问题
- jquery - 应用 data-parsley-errors-messages-disabled 属性时,Select2 无法与 Parsley.js 一起使用
- php - 使用隐藏注释代码将 Laravel 5.2 升级到 5.3
- javascript - 更改html文档时保存注入svg文件
- matlab - 八度:将辅助 y 轴添加到现有绘图
- node.js - 节点库(在 TS 中创建):导出避免重复的正确方法 - 准备好发布了吗?
- sql - EXASOL:将查询生成的表数据转换为 json 数据(用于创建图形)