You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C++ WinRT UWP中ComboBox绑定IObservableVector<hstring>异常求助

Hey there, let's break down your C++ WinRT ComboBox binding issue step by step—this is a common pitfall when migrating from C++/CX, so I'll walk you through what's going on and how to fix it.

1. Should this scenario work as expected?

Short answer: Yes, binding a ComboBox to an observable string collection and using SelectedIndex/SelectedItem with two-way binding is supported in C++ WinRT. The hresult_no_interface exception you're hitting is due to missing interface implementations or timing issues in your code, not a limitation of the framework.

2. How to implement ItemsSource binding for string collections in C++ WinRT?

To properly bind a string collection to ComboBox.ItemsSource, follow these best practices:

  • Use the right observable collection type: single_threaded_observable_vector<T> is the correct choice, but since XAML's binding system works with IInspectable-based collections by default, you'll want to box your hstring values into IInspectable to avoid type mismatch issues.
  • Expose the collection as a public property: Make sure the collection is accessible via a property on your page or viewmodel. If you need to update the collection later, ensure the property notifies the UI of changes via INotifyPropertyChanged.
  • Leverage type-safe binding: Prefer x:Bind over Binding whenever possible—it provides compile-time checks that catch binding path errors early.

Example of creating the properly boxed collection:

// In your MainPage initialization logic
auto items = single_threaded_observable_vector<IInspectable>();
items.Append(box_value(L"One"));
items.Append(box_value(L"Two"));
items.Append(box_value(L"Three"));
m_myItems = items; // Assign to your class member variable

3. Fixes for your specific issues

Let's address each problem you're encountering:

a. Resolve the hresult_no_interface exception with two-way binding

This exception occurs because the XAML binding system expects your page/viewmodel to implement INotifyPropertyChanged when using two-way binding. Without this interface, the binding system can't listen for property changes or push updates back to your code, leading to an interface query failure.

Here's how to implement INotifyPropertyChanged correctly:

  1. Update your IDL file:
[default_interface]
runtimeclass MainPage : Windows.UI.Xaml.Controls.Page, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
    MainPage();
    Windows.Foundation.Collections.IObservableVector<Windows.Foundation.IInspectable> MyItems;
    Int32 SelectedIndex;
}
  1. Add implementation in your .h and .cpp:
// MainPage.h
private:
    IObservableVector<IInspectable> m_myItems;
    int32_t m_selectedIndex = 0;
    winrt::event<winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;

public:
    IObservableVector<IInspectable> MyItems();
    int32_t SelectedIndex();
    void SelectedIndex(int32_t value);

    // INotifyPropertyChanged required methods
    winrt::event_token PropertyChanged(winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
    void PropertyChanged(winrt::event_token const& token) noexcept;
// MainPage.cpp
IObservableVector<IInspectable> MainPage::MyItems()
{
    return m_myItems;
}

int32_t MainPage::SelectedIndex()
{
    return m_selectedIndex;
}

void MainPage::SelectedIndex(int32_t value)
{
    if (m_selectedIndex != value)
    {
        m_selectedIndex = value;
        // Notify the UI of the property change
        m_propertyChanged(*this, winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs(L"SelectedIndex"));
    }
}

winrt::event_token MainPage::PropertyChanged(winrt::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);
}
  1. Update your XAML binding:
<ComboBox x:Name="myComboBox" 
          ItemsSource="{x:Bind MyItems, Mode=OneWay}" 
          SelectedIndex="{x:Bind SelectedIndex, Mode=TwoWay}"/>

b. Fix the constructor SelectedIndex exception

Calling myComboBox().SelectedIndex(0) in the constructor fails because the ComboBox hasn't finished initializing its internal UI elements yet—critical interfaces the control uses to handle selection aren't available at that point.

Your workaround of setting SelectedIndex in the Loaded event is valid, but a cleaner approach is to rely on data binding: set your SelectedIndex property's initial value to 0 in your class (like m_selectedIndex = 0), and the binding will automatically sync once the control is ready.

c. Ensure the selected item appears correctly

By using the boxed IInspectable collection and implementing INotifyPropertyChanged, the binding system will correctly sync the SelectedIndex value between your code and the UI. The first item will be selected automatically when the page loads without manual intervention.


内容的提问来源于stack exchange,提问作者Bernd36

火山引擎 最新活动