C++ Win32桌面应用如何访问Toast通知的进度组件?
Win32 C++ Toast进度条绑定更新解决方案
问题背景
开发Win32 C++桌面应用时,Toast通知中的进度条无法通过数据绑定实现动态更新。原代码将NotificationData绑定到Toast根组件,而非具体的progress元素,导致属性更新无法生效。
原Toast XML定义
<toast> <visual> <binding template='ToastGeneric'> <text>Backup in progress</text> <progress title='Working folder' value='0' status='Starting backup...' valueStringOverride='0/1 files' /> </binding> </visual> </toast>
原C++显示代码
HRESULT CreateNotificationData(ABI::Windows::UI::Notifications::INotificationData** pData) { if (!pData) return E_INVALIDARG; *pData = nullptr; IInspectable* pInstance; HRESULT hr = ::RoActivateInstance(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_UI_Notifications_NotificationData).Get(), &pInstance); if (FAILED(hr)) return hr; hr = pInstance->QueryInterface(pData); pInstance->Release(); return hr; } bool ShowProgress(const std::wstring toastContent) { if (!toastContent.length()) return false; // build the XML from the Toast content ::CComPtr<ABI::Windows::Data::Xml::Dom::IXmlDocument> pDoc; HRESULT hr = DesktopNotificationManagerCompat::CreateXmlDocumentFromString(toastContent.c_str(), &pDoc); if (FAILED(hr)) return false; // create the notifier. Classic Win32 apps MUST use the Compat method to create the notifier ::CComPtr<ABI::Windows::UI::Notifications::IToastNotifier> pNotifier; hr = DesktopNotificationManagerCompat::CreateToastNotifier(&pNotifier); if (FAILED(hr)) return false; // create the Toast notification (using helper method from Compat library) ::CComPtr<ABI::Windows::UI::Notifications::IToastNotification> pToast; hr = DesktopNotificationManagerCompat::CreateToastNotification(pDoc, &pToast); if (FAILED(hr)) return false; // get the IToastNotification4 interface, which contains the required data binding functions ::CComPtr<ABI::Windows::UI::Notifications::IToastNotification4> pToastData; hr = pToast->QueryInterface(ABI::Windows::UI::Notifications::IID_IToastNotification4, (void**)&pToastData); if (FAILED(hr)) return false; // create a notification data instance ::CComPtr<ABI::Windows::UI::Notifications::INotificationData> pNotificationData; hr = CreateNotificationData(&pNotificationData); if (FAILED(hr)) return false; // get the values map from the Toast ::CComPtr<__FIMap_2_HSTRING_HSTRING> pValues; hr = pNotificationData->get_Values(&pValues); if (FAILED(hr)) return false; // create the values to bind HSTRING pValue; ::WindowsCreateString(L"value", 5, &pValue); HSTRING pValueVal; ::WindowsCreateString(L"0.1", 3, &pValueVal); HSTRING pStatus; ::WindowsCreateString(L"status", 6, &pStatus); HSTRING pStatusVal; ::WindowsCreateString(L"Test test test", 14, &pStatusVal); boolean replaced; // add the values in the Toast values map as a key/value pair value pValues->Insert(pValue, pValueVal, &replaced); pValues->Insert(pStatus, pStatusVal, &replaced); ::WindowsDeleteString(pValue); ::WindowsDeleteString(pValueVal); ::WindowsDeleteString(pStatus); ::WindowsDeleteString(pStatusVal); // set the sequence number to 1 in order to refresh the interface (need to be increased // every time the Toast should be refreshed) hr = pNotificationData->put_SequenceNumber(1); if (FAILED(hr)) return false; // set the data to bind in the Toast hr = pToastData->put_Data(pNotificationData); if (FAILED(hr)) return false; // show the Toast hr = pNotifier->Show(pToast); if (FAILED(hr)) return false; return true; }
解决步骤
1. 修改Toast XML,为progress元素添加ID
要将数据绑定到具体的progress组件,必须给它指定唯一id属性,用于后续在NotificationData中定位:
<toast> <visual> <binding template='ToastGeneric'> <text>Backup in progress</text> <!-- 添加id属性,用于数据绑定定位 --> <progress id='backupProgress' title='Working folder' value='0' status='Starting backup...' valueStringOverride='0/1 files' /> </binding> </visual> </toast>
2. 修改NotificationData的键名格式
NotificationData中的键名需要遵循[progress-id].[属性名]的格式,才能将值绑定到指定progress元素的对应属性。修改代码中添加键值对的部分:
// 修改键名,指定对应的progress元素id HSTRING pValueKey; ::WindowsCreateString(L"backupProgress.value", 21, &pValueKey); HSTRING pValueVal; ::WindowsCreateString(L"0.1", 3, &pValueVal); HSTRING pStatusKey; ::WindowsCreateString(L"backupProgress.status", 22, &pStatusKey); HSTRING pStatusVal; ::WindowsCreateString(L"Test test test", 14, &pStatusVal); // 可选:更新valueStringOverride HSTRING pValueStrKey; ::WindowsCreateString(L"backupProgress.valueStringOverride", 35, &pValueStrKey); HSTRING pValueStrVal; ::WindowsCreateString(L"1/10 files", 10, &pValueStrVal); boolean replaced; pValues->Insert(pValueKey, pValueVal, &replaced); pValues->Insert(pStatusKey, pStatusVal, &replaced); pValues->Insert(pValueStrKey, pValueStrVal, &replaced); // 释放HSTRING资源 ::WindowsDeleteString(pValueKey); ::WindowsDeleteString(pValueVal); ::WindowsDeleteString(pStatusKey); ::WindowsDeleteString(pStatusVal); ::WindowsDeleteString(pValueStrKey); ::WindowsDeleteString(pValueStrVal);
3. 后续进度更新的注意事项
- 保留Toast标识:若需多次更新进度,需通过
IToastNotification2接口设置Toast的Tag和Group属性,确保后续更新能定位到同一个通知 - 递增SequenceNumber:每次更新必须将
NotificationData的SequenceNumber递增,否则系统会忽略更新请求 - 复用Notifier实例:保存
IToastNotifier实例,后续更新时调用其Update方法而非Show,避免重复创建新通知
内容的提问来源于stack exchange,提问作者Jean-Milost Reymond
相关产品推荐
相关产品推荐

