You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI 3 ListView:C++ MVVM模式下如何处理选中项

WinRT C++桌面应用中处理ListView选中项的MVVM方案

方案一:使用Microsoft.Xaml.Interactivity库(与C#逻辑一致)

你可以在C++/WinRT项目中直接使用和C#相同的交互行为库,步骤如下:

  1. 安装NuGet包:根据项目类型选择对应包——WinUI3项目安装Microsoft.Xaml.Interactivity.WinUI,传统UWP项目安装Microsoft.Xaml.Interactivity。
  2. XAML添加命名空间:
    xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"
    
  3. 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>
    
  4. 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;
        };
    }
    
    // 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);
        }
    }
    
    然后在ViewModel中使用该命令处理选中项:
    // 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逻辑:

  1. XAML配置绑定:
    <ListView 
        ItemsSource="{x:Bind MainViewModel.Items}"
        SelectedItem="{x:Bind MainViewModel.SelectedItem, Mode=TwoWay}">
        <!-- 此处添加ItemTemplate等配置 -->
    </ListView>
    
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 10:15:34