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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 10:25:33