WinUI 3 ListView:C++ MVVM模式下如何处理选中项
WinRT C++桌面应用中处理ListView选中项的MVVM方案
方案一:使用Microsoft.Xaml.Interactivity库(与C#逻辑一致)
你可以在C++/WinRT项目中直接使用和C#相同的交互行为库,步骤如下:
- 安装NuGet包:根据项目类型选择对应包——WinUI3项目安装
Microsoft.Xaml.Interactivity.WinUI,传统UWP项目安装Microsoft.Xaml.Interactivity。 - XAML添加命名空间:
xmlns:interactivity="using:Microsoft.Xaml.Interactivity" xmlns:core="using:Microsoft.Xaml.Interactions.Core" - ListView配置行为绑定:
通过InvokeCommandAction将选中事件绑定到ViewModel的命令,并传入选中项作为参数:<ListView x:Name="ItemListView" ItemsSource="{x:Bind MainViewModel.Items}"> <interactivity:Interaction.Behaviors> <core:EventTriggerBehavior EventName="SelectionChanged"> <core:InvokeCommandAction Command="{x:Bind MainViewModel.SelectItemCommand}" CommandParameter="{x:Bind ItemListView.SelectedItem, Mode=OneWay}"/> </core:EventTriggerBehavior> </interactivity:Interaction.Behaviors> <!-- 此处添加ItemTemplate等ListView配置 --> </ListView> - ViewModel实现命令逻辑:
C++/WinRT没有内置的RelayCommand,需要自己实现ICommand接口封装命令:// RelayCommand.h #pragma once #include <winrt/Windows.UI.Xaml.Input.h> #include <functional> namespace winrt::YourApp::implementation { class RelayCommand : public winrt::implements<RelayCommand, Windows::UI::Xaml::Input::ICommand> { public: RelayCommand(std::function<void(winrt::Windows::Foundation::IInspectable)> execute, std::function<bool(winrt::Windows::Foundation::IInspectable)> canExecute = nullptr); event_token CanExecuteChanged(Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable> const& handler); void CanExecuteChanged(event_token const& token) noexcept; bool CanExecute(winrt::Windows::Foundation::IInspectable const& parameter); void Execute(winrt::Windows::Foundation::IInspectable const& parameter); private: std::function<void(winrt::Windows::Foundation::IInspectable)> m_execute; std::function<bool(winrt::Windows::Foundation::IInspectable)> m_canExecute; event<Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>> m_canExecuteChanged; }; }
然后在ViewModel中使用该命令处理选中项:// RelayCommand.cpp #include "pch.h" #include "RelayCommand.h" namespace winrt::YourApp::implementation { RelayCommand::RelayCommand(std::function<void(winrt::Windows::Foundation::IInspectable)> execute, std::function<bool(winrt::Windows::Foundation::IInspectable)> canExecute) : m_execute(std::move(execute)), m_canExecute(std::move(canExecute)) {} event_token RelayCommand::CanExecuteChanged(Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable> const& handler) { return m_canExecuteChanged.add(handler); } void RelayCommand::CanExecuteChanged(event_token const& token) noexcept { m_canExecuteChanged.remove(token); } bool RelayCommand::CanExecute(winrt::Windows::Foundation::IInspectable const& parameter) { return m_canExecute ? m_canExecute(parameter) : true; } void RelayCommand::Execute(winrt::Windows::Foundation::IInspectable const& parameter) { if (m_execute) m_execute(parameter); } }// MainViewModel.h #include "RelayCommand.h" #include "YourItemType.h" // 你的数据项类型 namespace winrt::YourApp::implementation { struct MainViewModel : MainViewModelT<MainViewModel> { MainViewModel(); Windows::UI::Xaml::Input::ICommand SelectItemCommand(); void HandleItemSelection(winrt::Windows::Foundation::IInspectable const& selectedItem); // 此处添加Items等其他属性 private: winrt::Windows::UI::Xaml::Input::ICommand m_selectItemCommand; }; }// MainViewModel.cpp #include "pch.h" #include "MainViewModel.h" namespace winrt::YourApp::implementation { MainViewModel::MainViewModel() { m_selectItemCommand = winrt::make<RelayCommand>( std::bind(&MainViewModel::HandleItemSelection, this, std::placeholders::_1) ); } Windows::UI::Xaml::Input::ICommand MainViewModel::SelectItemCommand() { return m_selectItemCommand; } void MainViewModel::HandleItemSelection(winrt::Windows::Foundation::IInspectable const& selectedItem) { // 将参数转换为你的数据类型 auto item = selectedItem.as<YourItemType>(); // 执行选中项的业务逻辑 } }
方案二:直接绑定SelectedItem到ViewModel属性(更简洁的MVVM方式)
不需要处理事件,直接将ListView的选中项绑定到ViewModel的属性,当选中项变化时自动触发ViewModel逻辑:
- XAML配置绑定:
<ListView ItemsSource="{x:Bind MainViewModel.Items}" SelectedItem="{x:Bind MainViewModel.SelectedItem, Mode=TwoWay}"> <!-- 此处添加ItemTemplate等配置 --> </ListView> - ViewModel实现属性与通知:
确保ViewModel实现INotifyPropertyChanged接口,用于属性变化通知:// MainViewModel.h #include "YourItemType.h" #include <winrt/Windows.UI.Xaml.Data.h> namespace winrt::YourApp::implementation { struct MainViewModel : MainViewModelT<MainViewModel>, winrt::implements<MainViewModel, Windows::UI::Xaml::Data::INotifyPropertyChanged> { MainViewModel(); winrt::YourItemType SelectedItem(); void SelectedItem(winrt::YourItemType const& value); // INotifyPropertyChanged接口实现 event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler); void PropertyChanged(event_token const& token) noexcept; private: winrt::YourItemType m_selectedItem; event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged; void RaisePropertyChanged(hstring const& propertyName) { m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs(propertyName)); } void OnSelectedItemChanged(winrt::YourItemType const& item); }; }// MainViewModel.cpp #include "pch.h" #include "MainViewModel.h" namespace winrt::YourApp::implementation { MainViewModel::MainViewModel() {} winrt::YourItemType MainViewModel::SelectedItem() { return m_selectedItem; } void MainViewModel::SelectedItem(winrt::YourItemType const& value) { if (m_selectedItem != value) { m_selectedItem = value; RaisePropertyChanged(L"SelectedItem"); OnSelectedItemChanged(value); } } event_token MainViewModel::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) { return m_propertyChanged.add(handler); } void MainViewModel::PropertyChanged(event_token const& token) noexcept { m_propertyChanged.remove(token); } void MainViewModel::OnSelectedItemChanged(winrt::YourItemType const& item) { // 处理选中项变化的业务逻辑 } }
注意事项
- 方案二中必须实现
INotifyPropertyChanged接口,否则属性变化无法通知UI。 - 确保项目已启用C++/WinRT支持,且NuGet包版本与项目框架匹配。
内容的提问来源于stack exchange,提问作者Stefano Piovesan
相关产品推荐
相关产品推荐

