C++ WinRT UWP XAML 数据绑定 ItemsSource 和 SelectedIndex 到 IObservableVector<hstring> 不起作用
C++ WinRT UWP XAML Data binding ItemsSource and SelectedIndex to IObservableVector<hstring> does not work
我正在使用 Visual Studio 2019 16.4.3,Microsoft.Windows.CppWinRT 2.0.200117.5,Windows 10 1809 Pro,目标是 10.0.17763.0。
我正在尝试将 C++/CX 应用移植到 C++ WinRT。我正在使用组合框的 ItemsSource
、SelectedIndex
和 SelectedItem
属性的数据绑定,但我 运行 遇到了问题。
对于 ItemsSource
我绑定了一个 IObservableVector<String>
。 属性 使用 IObservableVector<hstring>
实现并使用 single_threaded_observable_vector(std::vector<hstring>({L"One", L"Two", L"Three"}))
初始化
启动应用程序时出现以下异常:
在 BlankCppWinRT.exe 中的 0x766B19B2 抛出异常:Microsoft C++ 异常:winrt::hresult_no_interface 在内存位置 0x03AED210。发生
这应该有效吗?如何将 ItemsSource
数据绑定到字符串集合?这适用于 C# 和 C++/CX。 C++ WinRT 中的等价物是什么?
当我删除到 SelectedIndex
的双向绑定时,应用程序启动并在组合框中显示三个字符串,并带有一个空的选定项。但是当我尝试通过 myComboBox().SelectedIndex(0);
(在构造函数中)在代码中设置选定的索引时,我遇到了同样的异常。而同一行在页面的 Loaded
处理程序中起作用。
详情如下。
有什么想法吗?
异常调用堆栈:
KernelBase.dll!_RaiseException@16() Unknown
vcruntime140d_app.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 133 C++
> BlankCppWinRT.exe!winrt::throw_hresult(const winrt::hresult result) Line 4623 C++
BlankCppWinRT.exe!winrt::check_hresult(const winrt::hresult result) Line 4700 C++
BlankCppWinRT.exe!winrt::impl::as<winrt::Windows::Foundation::IReference<winrt::hstring>,winrt::impl::abi<winrt::Windows::Foundation::IUnknown,void>::type>(winrt::impl::abi<winrt::Windows::Foundation::IUnknown,void>::type * ptr) Line 1941 C++
BlankCppWinRT.exe!winrt::Windows::Foundation::IUnknown::as<winrt::Windows::Foundation::IReference<winrt::hstring>>() Line 2026 C++
BlankCppWinRT.exe!winrt::unbox_value<winrt::hstring>(const winrt::Windows::Foundation::IInspectable & value) Line 2872 C++
BlankCppWinRT.exe!winrt::impl::convertible_observable_vector<winrt::hstring,std::vector<winrt::hstring,std::allocator<winrt::hstring>>>::IndexOf(const winrt::Windows::Foundation::IInspectable & value, unsigned int & index) Line 2547 C++
BlankCppWinRT.exe!winrt::impl::produce<winrt::impl::convertible_observable_vector<winrt::hstring,std::vector<winrt::hstring,std::allocator<winrt::hstring>>>,winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IInspectable>>::IndexOf(void * value, unsigned int * index, bool * winrt_impl_result) Line 566 C++
Windows.UI.Xaml.dll!DirectUI::ItemCollection::IndexOf(IInspectable * value, unsigned int * index, unsigned char * found) Line 139 C++
Windows.UI.Xaml.dll!DirectUI::ItemsControl::IsHostForItemContainer(Windows::UI::Xaml::IDependencyObject * pContainer, unsigned char * pIsHost) Line 1939 C++
Windows.UI.Xaml.dll!DirectUI::ComboBox::IsHostForItemContainer(Windows::UI::Xaml::IDependencyObject * pContainer, unsigned char * pIsHost) Line 1239 C++
Windows.UI.Xaml.dll!DirectUI::ItemContainerGenerator::ItemFromContainerImpl(Windows::UI::Xaml::IDependencyObject * container, IInspectable * * returnValue) Line 767 C++
Windows.UI.Xaml.dll!DirectUI::ItemContainerGeneratorGenerated::ItemFromContainer(Windows::UI::Xaml::IDependencyObject * pContainer, IInspectable * * ppReturnValue) Line 222 C++
这是我的 XAML 代码:
<Page
x:Class="BlankCppWinRT.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BlankCppWinRT"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Loaded="OnLoaded">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Margin="8" Width="160" x:Name="myButton" Click="ClickHandler">Click Me</Button>
<ComboBox Margin="8" Width="160" x:Name="myComboBox" ItemsSource="{x:Bind Path=BoxItems}" SelectedIndex="{x:Bind Path=SelectedBoxItemIndex, Mode=TwoWay}"/>
</StackPanel>
</Page>
这是 .idl 文件:
namespace BlankCppWinRT
{
[bindable]
[default_interface]
runtimeclass MainPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
MainPage();
Windows.Foundation.Collections.IObservableVector<String> BoxItems{get;};
Int32 SelectedBoxItemIndex;
protected void RaisePropertyChanged(String propertyName);
}
}
这个MainPage.h:
#pragma once
#include "MainPage.g.h"
namespace winrt::BlankCppWinRT::implementation
{
struct MainPage : MainPageT<MainPage>
{
MainPage();
Windows::Foundation::Collections::IObservableVector<hstring> BoxItems();
int32_t SelectedBoxItemIndex();
void SelectedBoxItemIndex(int32_t value);
void ClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
void RaisePropertyChanged(hstring const& propertyName);
winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
void PropertyChanged(winrt::event_token const& token) noexcept;
void OnLoaded(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
protected:
template<typename T>
bool SetProperty(T& storage, const T& value, const hstring& propertyName)
{
if (storage == value)
return false;
storage = value;
RaisePropertyChanged(propertyName);
return true;
}
private:
event<winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
private:
Windows::Foundation::Collections::IObservableVector<hstring> m_boxItems;
int m_selectedBoxItemIndex{};
};
}
namespace winrt::BlankCppWinRT::factory_implementation
{
struct MainPage : MainPageT<MainPage, implementation::MainPage>
{
};
}
这是MainPage.cpp:
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"
using namespace winrt;
using namespace Windows::UI::Xaml;
namespace winrt::BlankCppWinRT::implementation
{
MainPage::MainPage()
: m_boxItems{single_threaded_observable_vector(std::vector<hstring>({L"One", L"Two", L"Three"}))}
{
InitializeComponent();
//causes exception
//myComboBox().SelectedIndex(0);
}
Windows::Foundation::Collections::IObservableVector<hstring> MainPage::BoxItems()
{
return m_boxItems;
}
int32_t MainPage::SelectedBoxItemIndex()
{
return m_selectedBoxItemIndex;
}
// data binding to SelectedBoxItemIndex causes exception
void MainPage::SelectedBoxItemIndex(int32_t value)
{
SetProperty(m_selectedBoxItemIndex, value, L"SelectedBoxItemIndex");
}
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
myButton().Content(box_value(L"Clicked"));
SelectedBoxItemIndex(2);
}
void MainPage::RaisePropertyChanged(hstring const& propertyName)
{
m_propertyChanged(*this, PropertyChangedEventArgs(propertyName));
}
winrt::event_token MainPage::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
return m_propertyChanged.add(handler);
}
void MainPage::PropertyChanged(winrt::event_token const& token) noexcept
{
m_propertyChanged.remove(token);
}
void MainPage::OnLoaded(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
// works
myComboBox().SelectedIndex(0);
}
}
作为权宜之计,您可以转到 Windows.Foundation.Collections.h 来覆盖 IndexOf() 方法。当 unbox_value 失败时,捕获 hresult_no_interface 异常和 return false。更详细的可以参考这个thread.
bool IndexOf(Windows::Foundation::IInspectable const& value, uint32_t& index) const
{
//return IndexOf(unbox_value<T>(value), index);
try
{
return IndexOf(unbox_value<T>(value), index);
}
catch (hresult_no_interface const&)
{
return false; // unbox_value failed, "value" wasn't even a boxed T
}
}
我正在使用 Visual Studio 2019 16.4.3,Microsoft.Windows.CppWinRT 2.0.200117.5,Windows 10 1809 Pro,目标是 10.0.17763.0。
我正在尝试将 C++/CX 应用移植到 C++ WinRT。我正在使用组合框的 ItemsSource
、SelectedIndex
和 SelectedItem
属性的数据绑定,但我 运行 遇到了问题。
对于 ItemsSource
我绑定了一个 IObservableVector<String>
。 属性 使用 IObservableVector<hstring>
实现并使用 single_threaded_observable_vector(std::vector<hstring>({L"One", L"Two", L"Three"}))
启动应用程序时出现以下异常:
在 BlankCppWinRT.exe 中的 0x766B19B2 抛出异常:Microsoft C++ 异常:winrt::hresult_no_interface 在内存位置 0x03AED210。发生
这应该有效吗?如何将 ItemsSource
数据绑定到字符串集合?这适用于 C# 和 C++/CX。 C++ WinRT 中的等价物是什么?
当我删除到 SelectedIndex
的双向绑定时,应用程序启动并在组合框中显示三个字符串,并带有一个空的选定项。但是当我尝试通过 myComboBox().SelectedIndex(0);
(在构造函数中)在代码中设置选定的索引时,我遇到了同样的异常。而同一行在页面的 Loaded
处理程序中起作用。
详情如下。
有什么想法吗?
异常调用堆栈:
KernelBase.dll!_RaiseException@16() Unknown
vcruntime140d_app.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 133 C++
> BlankCppWinRT.exe!winrt::throw_hresult(const winrt::hresult result) Line 4623 C++
BlankCppWinRT.exe!winrt::check_hresult(const winrt::hresult result) Line 4700 C++
BlankCppWinRT.exe!winrt::impl::as<winrt::Windows::Foundation::IReference<winrt::hstring>,winrt::impl::abi<winrt::Windows::Foundation::IUnknown,void>::type>(winrt::impl::abi<winrt::Windows::Foundation::IUnknown,void>::type * ptr) Line 1941 C++
BlankCppWinRT.exe!winrt::Windows::Foundation::IUnknown::as<winrt::Windows::Foundation::IReference<winrt::hstring>>() Line 2026 C++
BlankCppWinRT.exe!winrt::unbox_value<winrt::hstring>(const winrt::Windows::Foundation::IInspectable & value) Line 2872 C++
BlankCppWinRT.exe!winrt::impl::convertible_observable_vector<winrt::hstring,std::vector<winrt::hstring,std::allocator<winrt::hstring>>>::IndexOf(const winrt::Windows::Foundation::IInspectable & value, unsigned int & index) Line 2547 C++
BlankCppWinRT.exe!winrt::impl::produce<winrt::impl::convertible_observable_vector<winrt::hstring,std::vector<winrt::hstring,std::allocator<winrt::hstring>>>,winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IInspectable>>::IndexOf(void * value, unsigned int * index, bool * winrt_impl_result) Line 566 C++
Windows.UI.Xaml.dll!DirectUI::ItemCollection::IndexOf(IInspectable * value, unsigned int * index, unsigned char * found) Line 139 C++
Windows.UI.Xaml.dll!DirectUI::ItemsControl::IsHostForItemContainer(Windows::UI::Xaml::IDependencyObject * pContainer, unsigned char * pIsHost) Line 1939 C++
Windows.UI.Xaml.dll!DirectUI::ComboBox::IsHostForItemContainer(Windows::UI::Xaml::IDependencyObject * pContainer, unsigned char * pIsHost) Line 1239 C++
Windows.UI.Xaml.dll!DirectUI::ItemContainerGenerator::ItemFromContainerImpl(Windows::UI::Xaml::IDependencyObject * container, IInspectable * * returnValue) Line 767 C++
Windows.UI.Xaml.dll!DirectUI::ItemContainerGeneratorGenerated::ItemFromContainer(Windows::UI::Xaml::IDependencyObject * pContainer, IInspectable * * ppReturnValue) Line 222 C++
这是我的 XAML 代码:
<Page
x:Class="BlankCppWinRT.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BlankCppWinRT"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Loaded="OnLoaded">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Margin="8" Width="160" x:Name="myButton" Click="ClickHandler">Click Me</Button>
<ComboBox Margin="8" Width="160" x:Name="myComboBox" ItemsSource="{x:Bind Path=BoxItems}" SelectedIndex="{x:Bind Path=SelectedBoxItemIndex, Mode=TwoWay}"/>
</StackPanel>
</Page>
这是 .idl 文件:
namespace BlankCppWinRT
{
[bindable]
[default_interface]
runtimeclass MainPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
MainPage();
Windows.Foundation.Collections.IObservableVector<String> BoxItems{get;};
Int32 SelectedBoxItemIndex;
protected void RaisePropertyChanged(String propertyName);
}
}
这个MainPage.h:
#pragma once
#include "MainPage.g.h"
namespace winrt::BlankCppWinRT::implementation
{
struct MainPage : MainPageT<MainPage>
{
MainPage();
Windows::Foundation::Collections::IObservableVector<hstring> BoxItems();
int32_t SelectedBoxItemIndex();
void SelectedBoxItemIndex(int32_t value);
void ClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);
void RaisePropertyChanged(hstring const& propertyName);
winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
void PropertyChanged(winrt::event_token const& token) noexcept;
void OnLoaded(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
protected:
template<typename T>
bool SetProperty(T& storage, const T& value, const hstring& propertyName)
{
if (storage == value)
return false;
storage = value;
RaisePropertyChanged(propertyName);
return true;
}
private:
event<winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
private:
Windows::Foundation::Collections::IObservableVector<hstring> m_boxItems;
int m_selectedBoxItemIndex{};
};
}
namespace winrt::BlankCppWinRT::factory_implementation
{
struct MainPage : MainPageT<MainPage, implementation::MainPage>
{
};
}
这是MainPage.cpp:
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"
using namespace winrt;
using namespace Windows::UI::Xaml;
namespace winrt::BlankCppWinRT::implementation
{
MainPage::MainPage()
: m_boxItems{single_threaded_observable_vector(std::vector<hstring>({L"One", L"Two", L"Three"}))}
{
InitializeComponent();
//causes exception
//myComboBox().SelectedIndex(0);
}
Windows::Foundation::Collections::IObservableVector<hstring> MainPage::BoxItems()
{
return m_boxItems;
}
int32_t MainPage::SelectedBoxItemIndex()
{
return m_selectedBoxItemIndex;
}
// data binding to SelectedBoxItemIndex causes exception
void MainPage::SelectedBoxItemIndex(int32_t value)
{
SetProperty(m_selectedBoxItemIndex, value, L"SelectedBoxItemIndex");
}
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
myButton().Content(box_value(L"Clicked"));
SelectedBoxItemIndex(2);
}
void MainPage::RaisePropertyChanged(hstring const& propertyName)
{
m_propertyChanged(*this, PropertyChangedEventArgs(propertyName));
}
winrt::event_token MainPage::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
return m_propertyChanged.add(handler);
}
void MainPage::PropertyChanged(winrt::event_token const& token) noexcept
{
m_propertyChanged.remove(token);
}
void MainPage::OnLoaded(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
// works
myComboBox().SelectedIndex(0);
}
}
作为权宜之计,您可以转到 Windows.Foundation.Collections.h 来覆盖 IndexOf() 方法。当 unbox_value 失败时,捕获 hresult_no_interface 异常和 return false。更详细的可以参考这个thread.
bool IndexOf(Windows::Foundation::IInspectable const& value, uint32_t& index) const
{
//return IndexOf(unbox_value<T>(value), index);
try
{
return IndexOf(unbox_value<T>(value), index);
}
catch (hresult_no_interface const&)
{
return false; // unbox_value failed, "value" wasn't even a boxed T
}
}