Aracılığıyla paylaş


Win32 uygulamasında pencere öğesi sağlayıcısı uygulama (C++/WinRT)

Bu makale , IWidgetProvider arabirimini uygulayan basit bir pencere öğesi sağlayıcısı oluşturma işleminde size yol gösterir. Bu arabirimin yöntemleri, pencere öğesini tanımlayan verileri istemek veya pencere öğesi sağlayıcısının bir pencere öğesindeki kullanıcı eylemine yanıt vermesini sağlamak için pencere öğesi konağı tarafından çağrılır. Pencere öğesi sağlayıcıları tek bir pencere öğesini veya birden çok pencere öğesini destekleyebilir. Bu örnekte iki farklı pencere öğesi tanımlayacağız. Uyarlamalı Kartlar çerçevesi tarafından sağlanan bazı biçimlendirme seçeneklerini gösteren bir örnek hava durumu pencere öğesidir. İkinci pencere öğesi, kullanıcı pencere öğesinde görüntülenen bir düğmeye her tıkladığınızda artan bir sayaç tutarak kullanıcı eylemlerini ve özel pencere öğesi durumu özelliğini gösterir.

Basit bir hava durumu pencere öğesinin ekran görüntüsü. Pencere öğesi, hava durumuyla ilgili bazı grafik ve verilerin yanı sıra orta büyüklükteki pencere öğesinin şablonunun görüntülendiğini gösteren bazı tanılama metinlerini gösterir.

Basit bir sayma pencere öğesinin ekran görüntüsü. Pencere öğesi, artırılacak sayısal değeri ve Artım etiketli bir düğmeyi içeren bir dizenin yanı sıra küçük boyutlu pencere öğesi şablonunun görüntülendiğini gösteren bazı tanılama metinlerini gösterir.

Makaledeki bu örnek kod, Windows Uygulama SDK'sı için Widget Örneği'den uyarlanmıştır. C# kullanarak pencere öğesi sağlayıcısı uygulamak için bkz. Win32 uygulamasında pencere öğesi sağlayıcısı uygulama (C#).

Önkoşullar

  • Cihazınızda geliştirici modu etkinleştirilmiş olmalıdır. Daha fazla bilgi için bkz. Geliştiriciler için ayarlar.
  • Evrensel Windows Platformu geliştirme iş yüküyle Visual Studio 2022 veya üzeri. İsteğe bağlı açılan listeden C++ (v143) bileşenini eklediğinizden emin olun.

Yeni bir C++/WinRT win32 konsol uygulaması oluşturma

Visual Studio'da yeni bir proje oluşturun. Yeni bir proje oluştur iletişim kutusunda, dil filtresini "C++" ve platform filtresini Windows olarak ayarlayın, ardından Windows Konsol Uygulaması (C++/WinRT) proje şablonunu seçin. Yeni projeyi "ExampleWidgetProvider" olarak adlandırın. İstendiğinde, uygulamanın hedef Windows sürümünü 1809 veya sonraki bir sürüme ayarlayın.

Windows Uygulama SDK'sı ve Windows Uygulama Kitaplığı NuGet paketlerine başvuru ekleme

Bu örnek en son kararlı Windows Uygulama SDK'sı NuGet paketini kullanır. Çözüm Gezgini Başvurular'a sağ tıklayın ve NuGet paketlerini yönet...seçin. NuGet paket yöneticisinde Gözat sekmesini seçin ve "Microsoft.WindowsAppSDK" araması yapın. Sürüm açılan listesinden en son kararlı sürümü seçin ve ardından Yüklebutonuna tıklayın.

Bu örnek, Windows Uygulama Kitaplığı NuGet paketini de kullanır. Çözüm Gezgini Başvurular'a sağ tıklayın ve NuGet paketlerini yönet...seçin. NuGet paket yöneticisinde Gözat sekmesini seçin ve "Microsoft.Windows.ImplementationLibrary" araması yapın. Sürüm açılan listesinden en son sürümü seçin ve Yükleöğesine tıklayın.

Önceden derlenmiş başlık dosyası pch.h'ye aşağıdaki ekleme yönergelerini ekleyin.

//pch.h 
#pragma once
#include <wil/cppwinrt.h>
#include <wil/resource.h>
...
#include <winrt/Microsoft.Windows.Widgets.Providers.h>

Uyarı

WinRT üst bilgilerinden önce wil/cppwinrt.h üst bilgisini eklemeniz gerekir.

Pencere öğesi sağlayıcı uygulamasının doğru şekilde kapatılmasını yönetmek için winrt::get_module_lockadlı modül kilidinin özel bir sürümüne ihtiyacımız vardır. main.cpp dosyamızda tanımlanacak signalLocalServerShutdown yöntemini önceden bildiririz ve uygulamanın çıkışını belirten bir olay ayarlarız. Aşağıdaki kodu, diğer dahil etmelerden önce, #pragma once yönergesinin hemen altına pch.h dosyanıza ekleyin.

//pch.h
#include <stdint.h>
#include <combaseapi.h>

// In .exe local servers the class object must not contribute to the module ref count, and use
// winrt::no_module_lock, the other objects must and this is the hook into the C++ WinRT ref counting system
// that enables this.
void SignalLocalServerShutdown();

namespace winrt
{
    inline auto get_module_lock() noexcept
    {
        struct service_lock
        {
            uint32_t operator++() noexcept
            {
                return ::CoAddRefServerProcess();
            }

            uint32_t operator--() noexcept
            {
                const auto ref = ::CoReleaseServerProcess();

                if (ref == 0)
                {
                    SignalLocalServerShutdown();
                }
                return ref;
            }
        };

        return service_lock{};
    }
}


#define WINRT_CUSTOM_MODULE_LOCK

Pencere öğesi işlemlerini yönetmek için bir WidgetProvider sınıfı ekleyin.

Visual Studio'da, Çözüm Gezgini menüsünden projeye sağ tıklayın veSınıfekle-seçeneğini seçin. Sınıf Ekle iletişim kutusunda sınıfı "WidgetProvider" olarak adlandırın ve Ekledüğmesine tıklayın.

IWidgetProvider arabirimini uygulayan bir sınıf bildirme

IWidgetProvider arabirimi, pencere öğesi sağlayıcısıyla işlemleri başlatmak için pencere öğesi konağı tarafından çağrılacak yöntemleri tanımlar. WidgetProvider.h dosyasındaki boş sınıf tanımını aşağıdaki kodla değiştirin. Bu kod , IWidgetProvider arabirimini uygulayan bir yapı bildirir ve arabirim yöntemleri için prototipler bildirir.

// WidgetProvider.h
struct WidgetProvider : winrt::implements<WidgetProvider, winrt::Microsoft::Windows::Widgets::Providers::IWidgetProvider>
{
    WidgetProvider();

    /* IWidgetProvider required functions that need to be implemented */
    void CreateWidget(winrt::Microsoft::Windows::Widgets::Providers::WidgetContext widgetContext);
    void DeleteWidget(winrt::hstring const& widgetId, winrt::hstring const& customState);
    void OnActionInvoked(winrt::Microsoft::Windows::Widgets::Providers::WidgetActionInvokedArgs actionInvokedArgs);
    void OnWidgetContextChanged(winrt::Microsoft::Windows::Widgets::Providers::WidgetContextChangedArgs contextChangedArgs);
    void Activate(winrt::Microsoft::Windows::Widgets::Providers::WidgetContext widgetContext);
    void Deactivate(winrt::hstring widgetId);
    /* IWidgetProvider required functions that need to be implemented */

    
};

Ayrıca, özel bir yöntem olan UpdateWidget, sağlayıcımızdan pencere öğesi konağına güncelleştirmeler gönderecek bir yardımcı yöntem ekleyin.

// WidgetProvider.h
private: 

void UpdateWidget(CompactWidgetInfo const& localWidgetInfo);

Etkinleştirilmiş pencere öğelerini takip etmeye hazırlan

Pencere öğesi sağlayıcısı tek bir pencere öğesini veya birden çok pencere öğesini destekleyebilir. Pencere öğesi konağı, pencere öğesi sağlayıcısıyla bir işlem başlattığında, işlemle ilişkili pencere öğesini tanımlamak için bir kimlik numarası aktarır. Her pencere öğesinin, özel verileri depolamak için kullanılabilecek ilişkili bir adı ve durum değeri de vardır. Bu örnekte, sabitlenmiş her pencere öğesinin kimliğini, adını ve verilerini depolamak için basit bir yardımcı yapı bildireceğiz. Pencere öğeleri, aşağıdaki Etkinleştir ve Devre Dışı Bırak bölümünde açıklanan etkin bir durumda da olabilir ve boole değeri olan her pencere öğesi için bu durumu takip edeceğiz. Aşağıdaki tanımı WidgetProvider.h dosyasına, WidgetProvider yapısı bildiriminin üzerine ekleyin.

// WidgetProvider.h
struct CompactWidgetInfo
{
    winrt::hstring widgetId;
    winrt::hstring widgetName;
    int customState = 0;
    bool isActive = false;
};

WidgetProvider.h içindeki WidgetProvider bildiriminin içine, her girişin anahtarı olarak pencere öğesi kimliğini kullanarak etkin pencere öğelerinin listesini koruyacak bir harita üyesi ekleyin.

// WidgetProvider.h
#include <unordered_map>
struct WidgetProvider : winrt::implements<WidgetProvider, winrt::Microsoft::Windows::Widgets::Providers::IWidgetProvider>
{
...
    private:
        ...
        static std::unordered_map<winrt::hstring, CompactWidgetInfo> RunningWidgets;

        

Widget şablonu JSON dizelerini tanımlama

Bu örnekte, her pencere öğesi için JSON şablonlarını tanımlamak üzere bazı statik dizeler bildirilecektir. Kolaylık sağlamak için, bu şablonlar WidgetProvider sınıf tanımının dışında bildirilen yerel değişkenlerde depolanır. Şablonlar için genel bir depolama alanına ihtiyacınız varsa, bunlar uygulama paketinin bir parçası olarak eklenebilir: Paket Dosyalarına Erişme. Pencere öğesi şablonu JSON belgesi oluşturma hakkında bilgi için bkz. Uyarlamalı Kart Tasarımcısı ile pencere öğesi şablonu oluşturma.

En son sürümde, Windows pencere öğeleri uygulayan uygulamalar Pencere Öğeleri Panosu'nda pencere öğeleri için görüntülenen üst bilgiyi özelleştirerek varsayılan sunuyu geçersiz kılabilir. Daha fazla bilgi için bkz. Pencere öğesi üst bilgisi alanını özelleştirme.

Uyarı

En son sürümde, Windows pencere öğelerini uygulayan uygulamalar, sağlayıcıdan Pencere Öğeleri Panosu'na geçirilen JSON yükünde Uyarlamalı Kart şema biçiminde içerik sağlamak yerine pencere öğesi içeriğini belirtilen URL'den sunulan HTML ile doldurmayı seçebilir. Pencere öğesi sağlayıcılarının yine de Uyarlamalı Kart JSON yükü sağlaması gerekir, bu nedenle bu kılavuzdaki uygulama adımları web pencere öğeleri için geçerlidir. Daha fazla bilgi için bkz. Web pencere öğesi sağlayıcıları.

// WidgetProvider.h
const std::string weatherWidgetTemplate = R"(
{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": "AdaptiveCard",
    "version": "1.0",
    "speak": "<s>The forecast for Seattle January 20 is mostly clear with a High of 51 degrees and Low of 40 degrees</s>",
    "backgroundImage": "https://messagecardplayground.azurewebsites.net/assets/Mostly%20Cloudy-Background.jpg",
    "body": [
        {
            "type": "TextBlock",
            "text": "Redmond, WA",
            "size": "large",
            "isSubtle": true,
            "wrap": true
        },
        {
            "type": "TextBlock",
            "text": "Mon, Nov 4, 2019 6:21 PM",
            "spacing": "none",
            "wrap": true
        },
        {
            "type": "ColumnSet",
            "columns": [
                {
                    "type": "Column",
                    "width": "auto",
                    "items": [
                        {
                            "type": "Image",
                            "url": "https://messagecardplayground.azurewebsites.net/assets/Mostly%20Cloudy-Square.png",
                            "size": "small",
                            "altText": "Mostly cloudy weather"
                        }
                    ]
                },
                {
                    "type": "Column",
                    "width": "auto",
                    "items": [
                        {
                            "type": "TextBlock",
                            "text": "46",
                            "size": "extraLarge",
                            "spacing": "none",
                            "wrap": true
                        }
                    ]
                },
                {
                    "type": "Column",
                    "width": "stretch",
                    "items": [
                        {
                            "type": "TextBlock",
                            "text": "°F",
                            "weight": "bolder",
                            "spacing": "small",
                            "wrap": true
                        }
                    ]
                },
                {
                    "type": "Column",
                    "width": "stretch",
                    "items": [
                        {
                            "type": "TextBlock",
                            "text": "Hi 50",
                            "horizontalAlignment": "left",
                            "wrap": true
                        },
                        {
                            "type": "TextBlock",
                            "text": "Lo 41",
                            "horizontalAlignment": "left",
                            "spacing": "none",
                            "wrap": true
                        }
                    ]
                }
            ]
        }
    ]
})";

const std::string countWidgetTemplate = R"(
{                                                                     
    "type": "AdaptiveCard",                                         
    "body": [                                                         
        {                                                               
            "type": "TextBlock",                                    
            "text": "You have clicked the button ${count} times"    
        },
        {
             "text":"Rendering Only if Medium",
             "type":"TextBlock",
             "$when":"${$host.widgetSize==\"medium\"}"
        },
        {
             "text":"Rendering Only if Small",
             "type":"TextBlock",
             "$when":"${$host.widgetSize==\"small\"}"
        },
        {
         "text":"Rendering Only if Large",
         "type":"TextBlock",
         "$when":"${$host.widgetSize==\"large\"}"
        }                                                                    
    ],                                                                  
    "actions": [                                                      
        {                                                               
            "type": "Action.Execute",                               
            "title": "Increment",                                   
            "verb": "inc"                                           
        }                                                               
    ],                                                                  
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.5"                                                
})";

IWidgetProvider yöntemlerini uygulama

Sonraki birkaç bölümde IWidgetProvider arabiriminin yöntemlerini uygulayacağız. Bu yöntem uygulamalarından birkaçında çağrılan yardımcı UpdateWidget yöntemi bu makalenin devamında gösterilecektir. Arayüz yöntemlerine geçmeden önce, pencere öğesi sağlayıcısı API'lerini WidgetProvider.cpp ad alanına çekmek ve önceki adımda bildirdiğimiz haritaya erişim izni vermek için ekleme yönergelerinden sonra, aşağıdaki satırları öğesine ekleyin.

Uyarı

IWidgetProvider arabiriminin geri çağırma yöntemlerine geçirilen nesnelerin yalnızca geri çağırma içinde geçerli olacağı garanti edilir. Geri çağırma bağlamı dışındaki davranışları tanımsız olduğundan, bu nesnelere yönelik başvuruları depolamamalısınız.

// WidgetProvider.cpp
namespace winrt
{
    using namespace Microsoft::Windows::Widgets::Providers;
}

std::unordered_map<winrt::hstring, CompactWidgetInfo> WidgetProvider::RunningWidgets{};

WidgetOluştur

Kullanıcı, uygulamanızın pencere öğelerinden birini pencere öğesi konağına sabitlediğinde, pencere öğesi konağı CreateWidget çağırır. İlk olarak, bu yöntem ilişkili pencere öğesinin kimliğini ve adını alır ve etkin pencere öğelerinin koleksiyonuna yardımcı yapımız CompactWidgetInfo'nun yeni bir örneğini ekler. Ardından, UpdateWidget yardımcı yönteminde kapsüllenen pencere öğesi için ilk şablonu ve verileri gönderiyoruz.

// WidgetProvider.cpp
void WidgetProvider::CreateWidget(winrt::WidgetContext widgetContext)
{
    auto widgetId = widgetContext.Id();
    auto widgetName = widgetContext.DefinitionId();
    CompactWidgetInfo runningWidgetInfo{ widgetId, widgetName };
    RunningWidgets[widgetId] = runningWidgetInfo;
    
    // Update the widget
    UpdateWidget(runningWidgetInfo);
}

DeleteWidget

Kullanıcı uygulamanızın widget'larından birini widget konağından kaldırdığında, widget konağı DeleteWidget çağırır. Bu durumda, ilgili pencere öğesini etkin pencere öğeleri listemizden kaldıracağız, böylece bu pencere öğesi için başka güncelleştirme göndermeyeceğiz.

// WidgetProvider.cpp
void WidgetProvider::DeleteWidget(winrt::hstring const& widgetId, winrt::hstring const& customState)
{
    RunningWidgets.erase(widgetId);
}

OnActionInvoked

Kullanıcı pencere öğesi şablonunuzda tanımladığınız bir eylemle etkileşime geçtiğinde pencere öğesi konağı OnActionInvoked öğesini çağırır. Bu örnekte kullanılan sayaç widget'ı için, widget'ın JSON şablonunda fiili değeri "inc" olan bir eylem tanımlandı. Pencere öğesi sağlayıcısı kodu, kullanıcı etkileşimine yanıt olarak hangi eylemin gerçekleştirileceğini belirlemek için bu fiili değerini kullanır.

...
    "actions": [                                                      
        {                                                               
            "type": "Action.Execute",                               
            "title": "Increment",                                   
            "verb": "inc"                                           
        }                                                               
    ], 
...

OnActionInvoked yönteminde, yönteme geçirilen WidgetActionInvokedArgs'in Fiil özelliğini kontrol ederek fiil değerini alın. Fiil "inc" ise, pencere öğesi için özel durumdaki sayıyı artıracağımızı biliyoruz. WidgetActionInvokedArgs öğesinden WidgetContext nesnesini ve ardından güncelleştirilmekte olan pencere öğesinin kimliğini almak için WidgetId değerini alın. Etkinleştirilmiş pencere öğeleri haritamızda belirtilen ID'ye sahip girdiyi bulun ve ardından artış sayısını depolamak için kullanılan özel durum değerini güncelleyin. Son olarak, updateWidget yardımcı işleviyle pencere öğesi içeriğini yeni değerle güncelleştirin.

// WidgetProvider.cpp
void WidgetProvider::OnActionInvoked(winrt::WidgetActionInvokedArgs actionInvokedArgs)
{
    auto verb = actionInvokedArgs.Verb();
    if (verb == L"inc")
    {
        auto widgetId = actionInvokedArgs.WidgetContext().Id();
        // If you need to use some data that was passed in after
        // Action was invoked, you can get it from the args:
        auto data = actionInvokedArgs.Data();
        if (const auto iter = RunningWidgets.find(widgetId); iter != RunningWidgets.end())
        {
            auto& localWidgetInfo = iter->second;
            // Increment the count
            localWidgetInfo.customState++;
            UpdateWidget(localWidgetInfo);
        }
    }
}

Uyarlamalı Kartlar için Action.Execute söz dizimi hakkında bilgi için bkz. Action.Execute. Pencere öğeleri için etkileşim tasarlama hakkında yönergeler için bkz . Pencere öğesi etkileşimi tasarım kılavuzu

OnWidgetContextChanged

Geçerli sürümde , OnWidgetContextChanged yalnızca kullanıcı sabitlenmiş pencere öğesinin boyutunu değiştirdiğinde çağrılır. İstenen boyuta bağlı olarak pencere öğesi konağına farklı bir JSON şablonu/verisi döndürmeyi seçebilirsiniz. Ayrıca , host.widgetSize değerini temel alan koşullu işlemeyi kullanarak kullanılabilir tüm boyutları desteklemek için JSON şablonunu tasarlayabilirsiniz. Boyut değişikliğini hesaba eklemek için yeni bir şablon veya veri göndermeniz gerekmiyorsa telemetri amacıyla OnWidgetContextChanged kullanabilirsiniz.

// WidgetProvider.cpp
void WidgetProvider::OnWidgetContextChanged(winrt::WidgetContextChangedArgs contextChangedArgs)
{
    auto widgetContext = contextChangedArgs.WidgetContext();
    auto widgetId = widgetContext.Id();
    auto widgetSize = widgetContext.Size();
    if (const auto iter = RunningWidgets.find(widgetId); iter != RunningWidgets.end())
    {
        auto localWidgetInfo = iter->second;

        UpdateWidget(localWidgetInfo);
    }
}
    

Etkinleştirme ve Devre Dışı Bırakma

Activate yöntemi, widget sağlayıcısına widget ana bilgisayarının sağlayıcıdan güncelleştirilmiş içerik almakla ilgilendiğini bildirmek için çağrılır. Örneğin, kullanıcının şu anda widget barındırıcısını aktif bir şekilde görüntülediği anlamına gelebilir. Deactivate yöntemi, widget sağlayıcısına artık widget barındırıcısının içerik güncelleştirmeleri istemediğini bildirmek için çağrılır. Bu iki yöntem, pencere öğesi ana bilgisayarının en çok up-totarih içeriğini göstermekle ilgilendiği bir pencere tanımlar. Pencere öğesi sağlayıcıları, herhangi bir zamanda, örneğin anında iletme bildirimine yanıt olarak pencere öğesine güncelleştirme gönderebilir, ancak herhangi bir arka plan görevinde olduğu gibi, pil ömrü gibi kaynak endişeleriyle up-totarih içerik sağlamayı dengelemek önemlidir.

etkinleştir ve devre dışı bırak widget başına çağrılır. Bu örnek , CompactWidgetInfo yardımcı yapısındaki her pencere öğesinin etkin durumunu izler. Activate yönteminde, pencere öğesimizi güncelleştirmek için UpdateWidget yardımcı yöntemini çağırırız. Etkinleştir ve Devre Dışı Bırak arasındaki zaman penceresinin küçük olabileceğini unutmayın; bu nedenle pencere öğesinizin kod yolunu olabildiğince hızlı güncelleştirmesini sağlamanız önerilir.

void WidgetProvider::Activate(winrt::Microsoft::Windows::Widgets::Providers::WidgetContext widgetContext)
{
    auto widgetId = widgetContext.Id();

    if (const auto iter = RunningWidgets.find(widgetId); iter != RunningWidgets.end())
    {
        auto& localWidgetInfo = iter->second;
        localWidgetInfo.isActive = true;

        UpdateWidget(localWidgetInfo);
    }
}

void WidgetProvider::Deactivate(winrt::hstring widgetId)
{
    if (const auto iter = RunningWidgets.find(widgetId); iter != RunningWidgets.end())
    {
        auto& localWidgetInfo = iter->second;
        localWidgetInfo.isActive = false;
    }
}

Widget güncelle

Etkin bir pencere öğesini güncelleştirmek için UpdateWidget yardımcı yöntemini tanımlayın. Bu örnekte, yöntemine geçirilen CompactWidgetInfo yardımcı yapısındaki pencere öğesinin adını denetleyeceğiz ve ardından hangi pencere öğesinin güncelleştirildiği temelinde uygun şablonu ve veri JSON'unu ayarlayacağız. WidgetUpdateRequestOptions, güncellenmekte olan widget için şablon, veri ve özel durumu ile başlatılır. WidgetManager sınıfının bir örneğini almak için WidgetManager::GetDefault öğesini çağırın ve ardından güncelleştirilmiş pencere öğesi verilerini pencere öğesi konağına göndermek için UpdateWidget'i çağırın.

// WidgetProvider.cpp
void WidgetProvider::UpdateWidget(CompactWidgetInfo const& localWidgetInfo)
{
    winrt::WidgetUpdateRequestOptions updateOptions{ localWidgetInfo.widgetId };

    winrt::hstring templateJson;
    if (localWidgetInfo.widgetName == L"Weather_Widget")
    {
        templateJson = winrt::to_hstring(weatherWidgetTemplate);
    }
    else if (localWidgetInfo.widgetName == L"Counting_Widget")
    {
        templateJson = winrt::to_hstring(countWidgetTemplate);
    }

    winrt::hstring dataJson;
    if (localWidgetInfo.widgetName == L"Weather_Widget")
    {
        dataJson = L"{}";
    }
    else if (localWidgetInfo.widgetName == L"Counting_Widget")
    {
        dataJson = L"{ \"count\": " + winrt::to_hstring(localWidgetInfo.customState) + L" }";
    }

    updateOptions.Template(templateJson);
    updateOptions.Data(dataJson);
    // You can store some custom state in the widget service that you will be able to query at any time.
    updateOptions.CustomState(winrt::to_hstring(localWidgetInfo.customState));
    winrt::WidgetManager::GetDefault().UpdateWidget(updateOptions);
}

Uygulama başlangıcında etkin pencere öğelerinin listesini başlatın.

Pencere öğesi sağlayıcımız ilk başlatıldığında, sağlayıcımızın şu anda hizmet vermekte olduğu çalışan pencere öğeleri olup olmadığını WidgetManager'a sormak iyi bir fikirdir. Bilgisayarın yeniden başlatılması veya sağlayıcının çökmesi durumunda uygulamayı önceki durumuna geri getirmeye yardımcı olacaktır. Uygulamanın varsayılan pencere öğesi yöneticisi örneğini almak için WidgetManager::GetDefault öğesini çağırın. Ardından, bir dizi WidgetInfo nesnesi döndüren GetWidgetInfosçağrısını yapın. Pencere öğesi kimliklerini, adlarını ve özel durumunu CompactWidgetInfo yardımcı yapısına kopyalayın ve RunningWidgets üye değişkenine kaydedin. Aşağıdaki kodu WidgetProvider sınıfının oluşturucusuna yapıştırın.

// WidgetProvider.cpp
WidgetProvider::WidgetProvider()
{
    auto runningWidgets = winrt::WidgetManager::GetDefault().GetWidgetInfos();
    for (auto widgetInfo : runningWidgets )
    {
        auto widgetContext = widgetInfo.WidgetContext();
        auto widgetId = widgetContext.Id();
        auto widgetName = widgetContext.DefinitionId();
        auto customState = widgetInfo.CustomState();
        if (RunningWidgets.find(widgetId) == RunningWidgets.end())
        {
            CompactWidgetInfo runningWidgetInfo{ widgetId, widgetName };
            try
            {
                // If we had any save state (in this case we might have some state saved for Counting widget)
                // convert string to required type if needed.
                int count = std::stoi(winrt::to_string(customState));
                runningWidgetInfo.customState = count;
            }
            catch (...)
            {

            }
            RunningWidgets[widgetId] = runningWidgetInfo;
        }
    }
}

Talep edildiğinde WidgetProvider örneği oluşturacak bir sınıf fabrikasını kaydedin.

WidgetProvider sınıfını tanımlayan üst bilgiyi uygulama main.cpp dosyanızın üst kısmındaki eklemelere ekleyin. Mutex'i de buraya dahil edeceğiz.

// main.cpp
...
#include "WidgetProvider.h"
#include <mutex>

Uygulamamızın çıkışını tetikleyecek olayı ve olayı ayarlayacak SignalLocalServerShutdown işlevini bildirin. Aşağıdaki kodu main.cpp yapıştırın.

// main.cpp
wil::unique_event g_shudownEvent(wil::EventOptions::None);

void SignalLocalServerShutdown()
{
    g_shudownEvent.SetEvent();
}

Ardından, COM etkinleştirmesi için pencere öğesi sağlayıcınızı tanımlamak için kullanılacak bir CLSID oluşturmanız gerekir. Araçlar-GUID> Oluştur'a giderek Visual Studio'da BIR GUID oluşturun. "static const GUID =" seçeneğini seçin ve Kopyala'a tıklayın, ardından bunu main.cpp'ye yapıştırın. GUID tanımını aşağıdaki C++/WinRT söz dizimi ile güncelleştirin ve GUID değişken adını widget_provider_clsid ayarlayın. Daha sonra uygulamanızı paketlerken bu biçime ihtiyacınız olacağı için GUID'nin açıklamalı sürümünü bırakın.

// main.cpp
...
// {80F4CB41-5758-4493-9180-4FB8D480E3F5}
static constexpr GUID widget_provider_clsid
{
    0x80f4cb41, 0x5758, 0x4493, { 0x91, 0x80, 0x4f, 0xb8, 0xd4, 0x80, 0xe3, 0xf5 }
};

Aşağıdaki sınıf fabrikası tanımını main.cpp'a ekleyin. Bu çoğunlukla pencere öğesi sağlayıcısı uygulamalarına özgü olmayan ortak koddur. CoWaitForMultipleObjects uygulamadan çıkmadan önce kapatma olayımızın tetiklanmasını beklediğini unutmayın.

// main.cpp
template <typename T>
struct SingletonClassFactory : winrt::implements<SingletonClassFactory<T>, IClassFactory>
{
    STDMETHODIMP CreateInstance(
        ::IUnknown* outer,
        GUID const& iid,
        void** result) noexcept final
    {
        *result = nullptr;

        std::unique_lock lock(mutex);

        if (outer)
        {
            return CLASS_E_NOAGGREGATION;
        }

        if (!instance)
        {
            instance = winrt::make<WidgetProvider>();
        }

        return instance.as(iid, result);
    }

    STDMETHODIMP LockServer(BOOL) noexcept final
    {
        return S_OK;
    }

private:
    T instance{ nullptr };
    std::mutex mutex;
};

int main()
{
    winrt::init_apartment();
    wil::unique_com_class_object_cookie widgetProviderFactory;
    auto factory = winrt::make<SingletonClassFactory<winrt::Microsoft::Windows::Widgets::Providers::IWidgetProvider>>();

    winrt::check_hresult(CoRegisterClassObject(
        widget_provider_clsid,
        factory.get(),
        CLSCTX_LOCAL_SERVER,
        REGCLS_MULTIPLEUSE,
        widgetProviderFactory.put()));

    DWORD index{};
    HANDLE events[] = { g_shudownEvent.get() };
    winrt::check_hresult(CoWaitForMultipleObjects(CWMO_DISPATCH_CALLS | CWMO_DISPATCH_WINDOW_MESSAGES,
        INFINITE,
        static_cast<ULONG>(std::size(events)), events, &index));

    return 0;
}

Pencere öğesi sağlayıcı uygulamanızı paketleyin

Geçerli sürümde yalnızca paketlenmiş uygulamalar pencere öğesi sağlayıcısı olarak kaydedilebilir. Aşağıdaki adımlar, uygulamanızı paketleme ve uygulamanızı işletim sistemine bir widget sağlayıcısı olarak kaydetmek için uygulama manifestini güncelleme sürecinde size kılavuzluk edecektir.

MSIX paketleme projesi oluşturma

Çözüm Gezgini, çözümünüze sağ tıklayın ve Yeni Proje Ekle...>seçin. Yeni Proje Ekle iletişim kutusunda "Windows Uygulama Paketleme Projesi" şablonunu seçin ve İleri'yetıklayın. Proje adını "ExampleWidgetProviderPackage" olarak ayarlayın ve Oluştur'a tıklayın. İstendiğinde hedef sürümü 1809 veya sonraki bir sürüme ayarlayın ve Tamam'a tıklayın. Ardından ExampleWidgetProviderPackage projesine sağ tıklayın ve Ekle ->Proje referansıseçin. ExampleWidgetProvider projesini seçin ve Tamam'a tıklayın.

Paketleme projesine Windows Uygulama SDK paket referansı ekleyin

MSIX paketleme projesine Windows Uygulama SDK'sı nuget paketine bir başvuru eklemeniz gerekir. Çözüm Gezgini'nde ExampleWidgetProviderPackage projesine çift tıklayarak ExampleWidgetProviderPackage.wapproj dosyasını açın. Project öğesinin içine aşağıdaki xml dosyasını ekleyin.

<!--ExampleWidgetProviderPackage.wapproj-->
<ItemGroup>
    <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.2.221116.1">
        <IncludeAssets>build</IncludeAssets>
    </PackageReference>  
</ItemGroup>

Uyarı

PackageReference öğesinde belirtilen Sürüm'in önceki adımda bahsedilen en son kararlı sürümle eşleştiğinden emin olun.

Windows Uygulama SDK'sının doğru sürümü bilgisayarda zaten yüklüyse ve SDK çalışma zamanını paketinizde paketlemek istemiyorsanız, ExampleWidgetProviderPackage projesi için Package.appxmanifest dosyasında paket bağımlılığını belirtebilirsiniz.

<!--Package.appxmanifest-->
...
<Dependencies>
...
    <PackageDependency Name="Microsoft.WindowsAppRuntime.1.2-preview2" MinVersion="2000.638.7.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
...
</Dependencies>
...

Paket bildirimini güncelleştirme

Çözüm Gezgini'nde dosyaya Package.appxmanifest sağ tıklayın ve Kodu Görüntüle'yi seçerek bildirim xml dosyasını açın. Ardından, kullanacağımız uygulama paketi uzantıları için bazı ad alanı bildirimleri eklemeniz gerekir. Üst düzey Package öğesine aşağıdaki ad alanı tanımlarını ekleyin.

<!-- Package.appmanifest -->
<Package
  ...
  xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"

Application öğesinin içinde Extensions adlı yeni bir boş öğe oluşturun. Bunun uap:VisualElementskapanış etiketinden sonra geldiğinden emin olun.

<!-- Package.appxmanifest -->
<Application>
...
    <Extensions>

    </Extensions>
</Application>

Eklememiz gereken ilk uzantı ComServer uzantısıdır. Bu işlem yürütülebilir dosyanın giriş noktasını işletim sistemine kaydeder. Bu uzantı, bir kayıt defteri anahtarı ayarlayarak COM sunucusunu kaydetmenin paketlenmiş uygulama eşdeğeridir ve pencere öğesi sağlayıcılarına özgü değildir. Aşağıdaki com:Extension öğesini Extensions öğesinin alt öğesi olarak ekleyin. com:Class öğesinin Id özniteliğindeki GUID değerini önceki adımda oluşturduğunuz GUID ile değiştirin.

<!-- Package.appxmanifest -->
<Extensions>
    <com:Extension Category="windows.comServer">
        <com:ComServer>
            <com:ExeServer Executable="ExampleWidgetProvider\ExampleWidgetProvider.exe" DisplayName="ExampleWidgetProvider">
                <com:Class Id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" DisplayName="ExampleWidgetProvider" />
            </com:ExeServer>
        </com:ComServer>
    </com:Extension>
</Extensions>

Ardından, uygulamayı pencere öğesi sağlayıcısı olarak kaydeden uzantıyı ekleyin. uap3:Extension öğesini aşağıdaki kod parçacığına Extensions öğesinin alt öğesi olarak yapıştırın. COM öğesinin ClassId özniteliğini önceki adımlarda kullandığınız GUID ile değiştirdiğinizden emin olun.

<!-- Package.appxmanifest -->
<Extensions>
    ...
    <uap3:Extension Category="windows.appExtension">
        <uap3:AppExtension Name="com.microsoft.windows.widgets" DisplayName="WidgetTestApp" Id="ContosoWidgetApp" PublicFolder="Public">
            <uap3:Properties>
                <WidgetProvider>
                    <ProviderIcons>
                        <Icon Path="Images\StoreLogo.png" />
                    </ProviderIcons>
                    <Activation>
                        <!-- Apps exports COM interface which implements IWidgetProvider -->
                        <CreateInstance ClassId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
                    </Activation>

                    <TrustedPackageFamilyNames>
                        <TrustedPackageFamilyName>Microsoft.MicrosoftEdge.Stable_8wekyb3d8bbwe</TrustedPackageFamilyName>
                    </TrustedPackageFamilyNames>

                    <Definitions>
                        <Definition Id="Weather_Widget"
                            DisplayName="Weather Widget"
                            Description="Weather Widget Description"
                            AllowMultiple="true">
                            <Capabilities>
                                <Capability>
                                    <Size Name="small" />
                                </Capability>
                                <Capability>
                                    <Size Name="medium" />
                                </Capability>
                                <Capability>
                                    <Size Name="large" />
                                </Capability>
                            </Capabilities>
                            <ThemeResources>
                                <Icons>
                                    <Icon Path="ProviderAssets\Weather_Icon.png" />
                                </Icons>
                                <Screenshots>
                                    <Screenshot Path="ProviderAssets\Weather_Screenshot.png" DisplayAltText="For accessibility" />
                                </Screenshots>
                                <!-- DarkMode and LightMode are optional -->
                                <DarkMode />
                                <LightMode />
                            </ThemeResources>
                        </Definition>
                        <Definition Id="Counting_Widget"
                                DisplayName="Microsoft Counting Widget"
                                Description="Couting Widget Description">
                            <Capabilities>
                                <Capability>
                                    <Size Name="small" />
                                </Capability>
                            </Capabilities>
                            <ThemeResources>
                                <Icons>
                                    <Icon Path="ProviderAssets\Counting_Icon.png" />
                                </Icons>
                                <Screenshots>
                                    <Screenshot Path="ProviderAssets\Counting_Screenshot.png" DisplayAltText="For accessibility" />
                                </Screenshots>
                                <!-- DarkMode and LightMode are optional -->
                                <DarkMode>

                                </DarkMode>
                                <LightMode />
                            </ThemeResources>
                        </Definition>
                    </Definitions>
                </WidgetProvider>
            </uap3:Properties>
        </uap3:AppExtension>
    </uap3:Extension>
</Extensions>

Bu öğelerin tümüne ilişkin ayrıntılı açıklamalar ve biçim bilgileri için Pencere Öğesi Sağlayıcı Paketi Manifesto XML Biçimi'ne bakın.

Paketleme projenize simgeler ve diğer görüntüler ekleme

Çözüm Gezginibölümünde, ExampleWidgetProviderPackage üzerine sağ tıklayın ve Yeni Klasör Ekle'yiseçin. Bu klasöre, önceki adımda Package.appxmanifest'de kullanılan ad olan ProviderAssets adını verin. Pencere öğelerimiz için Simgeleri ve Ekran Görüntüleri burada depolayacağız. İstediğiniz Simgeleri ve Ekran Görüntülerini ekledikten sonra, görüntü adlarının Path=ProviderAssets\ sonra gelen adlarla eşleştiğinden emin olun; aksi takdirde pencere öğeleri pencere öğesi ana bilgisayarında gösterilmez.

Ekran görüntülerinin tasarım gereksinimleri ve yerelleştirilmiş ekran görüntüleri için adlandırma kuralları hakkında bilgi için bkz. Pencere öğesi seçiciyle entegrasyon.

Widget sağlayıcınızı test etme

Geliştirme makinenizle uyumlu olan mimariyi, örneğin "x64", Çözüm Platformları açılır listesinden seçtiğinizden emin olun. Çözüm Gezgini'nde çözüme sağ tıklayın ve Çözümü Oluşturseçin. Bu işlem tamamlandıktan sonra ExampleWidgetProviderPackage üzerine sağ tıklayın ve Dağıtseçeneğini seçin. Geçerli sürümde desteklenen tek pencere öğesi konağı Pencere Öğeleri Panosu'dur. Pencere öğelerini görmek için Pencere Öğeleri Panosu'nu açmanız ve sağ üst kısımdaki Pencere öğesi ekle seçmeniz gerekir. Kullanılabilir pencere öğelerinin en altına kaydırın; bu öğreticide oluşturulan sahte Hava Durumu Pencere Öğesi ve Microsoft Sayma Pencere Öğesi'ü görmelisiniz. Pencere öğelerini, pencere öğeleri panonuza sabitlemek ve işlevlerini test etmek için tıklayın.

Widget sağlayıcınızda hata ayıklama

Pencere öğelerinizi sabitledikten sonra Pencere Öğesi Platformu, pencere öğesi hakkında ilgili bilgileri almak ve göndermek için pencere öğesi sağlayıcısı uygulamanızı başlatır. Çalışan pencere öğesinde hata ayıklamak için, çalışan pencere öğesi sağlayıcısı uygulamasına bir hata ayıklayıcı ekleyebilir veya başlatıldıktan sonra Visual Studio'yu pencere öğesi sağlayıcısı işleminde hata ayıklamayı otomatik olarak başlatacak şekilde ayarlayabilirsiniz.

Çalışan işleme eklemek için:

  1. Visual Studio'da Hata Ayıklama ->işleme ekle'ye tıklayın.
  2. İşlemleri filtreleyin ve istediğiniz pencere öğesi sağlayıcısı uygulamasını bulun.
  3. Hata ayıklayıcısını ekleyin.

Hata ayıklayıcıyı başlangıçta başlatıldığında işleme otomatik olarak eklemek için:

  1. Visual Studio'da Hata Ayıkla -> Diğer Hata Ayıklama Hedefleri -> Yüklü Uygulama Paketinde Hata Ayıklama'ya tıklayın.
  2. Paketleri filtreleyin ve istediğiniz pencere öğesi sağlayıcısı paketini bulun.
  3. Bunu seçin ve "Başlatmayın, ancak başlatıldığında kodumu hata ayıklayın" diyen kutuyu işaretleyin.
  4. Ekle'e tıklayın.

Konsol uygulamanızı Windows uygulamasına dönüştürme

Bu kılavuzda oluşturulan konsol uygulamasını bir Windows uygulamasına dönüştürmek için:

  1. çözüm gezgini ExampleWidgetProvider projesine sağ tıklayın ve Özelliklerseçeneğini belirleyin. Bağlayıcısı -> Sistem öğesine gidin ve Alt Sistem "Konsol"u "Windows" olarak değiştirin. Bu, <Alt Sistemi>Windows</SubSystem> ekleyerek .vcxproj dosyasının <Bağlantı>..</Link> bölümüne yapılabilir.
  2. main.cpp'de int main() ile int WINAPI wWinMain(_In_ HINSTANCE /*hInstance*/, _In_opt_ HINSTANCE /*hPrevInstance*/, _In_ PWSTR pCmdLine, _In_ int /*nCmdShow*/)'i değiştirin.

Çıkış türü Windows Uygulaması olarak ayarlanmış C++ pencere öğesi sağlayıcısı proje özelliklerini gösteren ekran görüntüsü

Widget'i yayımlama

Pencere öğesinizi geliştirip test ettikten sonra, kullanıcıların pencere öğelerinizi cihazlarına yükleyebilmesi için uygulamanızı Microsoft Store'da yayımlayabilirsiniz. Uygulama yayımlamaya yönelik adım adım yönergeler için bkz. Uygulamanızı Microsoft Store'da yayımlama.

Widget Mağaza Koleksiyonu

Uygulamanız Microsoft Store'da yayımlandıktan sonra, uygulamanızın kullanıcıların Windows Pencere Öğeleri içeren uygulamaları bulmasına yardımcı olan pencere öğeleri Mağaza Koleksiyonu'na eklenmesini isteyebilirsiniz. İsteğinizi göndermek için bkz. Mağaza Koleksiyonueklemek için Pencere Öğesi bilgilerinizi gönderme.

Kullanıcıların Windows Pencere Öğeleri içeren uygulamaları keşfetmesine olanak tanıyan pencere öğeleri koleksiyonunu gösteren Microsoft Store'un ekran görüntüsü.

Pencere öğesi özelleştirmesini uygulamak

Windows Uygulama SDK'sı 1.4'den başlayarak pencere öğeleri kullanıcı özelleştirmesini destekleyebilir. Bu özellik uygulandığında, "Özelleştir pencere öğesi" seçeneği, "Pencere öğesini kaldır" seçeneğinin üstünde yer alan üç nokta menüsüne eklenir.

Özelleştirme iletişim kutusunun görüntülendiği bir pencere öğesini gösteren ekran görüntüsü.

Aşağıdaki adımlarda pencere öğesi özelleştirme işlemi özetlenmiştir.

  1. Normal işlemde pencere öğesi sağlayıcısı, normal pencere öğesi deneyimi için görsel ve veri JSON şablonlarıyla pencere öğesi konağından gelen isteklere yanıt verir.
  2. Kullanıcı üç noktalı menüdeki Özelleştir pencere öğesi düğmesine tıklar.
  3. Pencere öğesi, kullanıcının pencere öğesi özelleştirme deneyimini istediği belirtmek için pencere öğesi sağlayıcısında OnCustomizationRequested olayını tetikler.
  4. Pencere öğesi sağlayıcısı, pencere öğesinin özelleştirme modunda olduğunu belirtmek için bir iç bayrak ayarlar. Özelleştirme modundayken, pencere öğesi sağlayıcısı normal pencere öğesi kullanıcı arabirimi yerine pencere öğesi özelleştirme kullanıcı arabirimi için JSON şablonlarını gönderir.
  5. Özelleştirme modundayken, kullanıcı özelleştirme kullanıcı arabirimiyle etkileşim kurarken pencere öğesi sağlayıcısı OnActionInvoked olaylarını alır ve kullanıcının eylemlerine göre iç yapılandırmasını ve davranışını ayarlar.
  6. OnActionInvoked olayıyla ilişkili eylem uygulama tanımlı "özelleştirmeden çık" eylemi olduğunda, pencere öğesi sağlayıcısı artık özelleştirme modunda olmadığını belirtmek için iç bayrağını sıfırlar ve normal pencere öğesi deneyimi için görsel ve veri JSON şablonlarını göndermeye devam eder ve özelleştirme sırasında istenen değişiklikleri yansıtır.
  7. Pencere öğesi sağlayıcısı, değişikliklerin pencere öğesi sağlayıcısı çağrıları arasında korunması için özelleştirme seçeneklerini diskte veya bulutta korur.

Uyarı

Windows Uygulama SDK'sı kullanılarak oluşturulan ve özelleştirme kartı gösterildikten sonra üç nokta menüsünün yanıt vermemeye başlamasına neden olan pencere öğeleri için Windows Pencere Öğesi Panosu'yla ilgili bilinen bir hata vardır.

Tipik Pencere Öğesi özelleştirme senaryolarında kullanıcı, pencere öğesinde hangi verilerin görüntüleneceğini seçer veya pencere öğesinin görsel sunumunu ayarlar. Kolaylık olması için, bu bölümdeki örnekte kullanıcının önceki adımlarda uygulanan sayım pencere öğesinin sayacını sıfırlamasına olanak tanıyan özelleştirme davranışı eklenecektir.

Uyarı

Pencere öğesi özelleştirmesi yalnızca Windows Uygulama SDK 1.4 ve sonraki sürümlerde desteklenir. Projenizdeki başvuruları Nuget paketinin en son sürümüne güncelleştirdiğinizden emin olun.

Özelleştirme desteği bildirmek için paket bildirimini güncelleştirin

Pencere öğesi konağına pencere öğesinin özelleştirmeyi desteklediğini bildirmek için, pencere öğesinin Tanım eleent'ine IsCustomizable özniteliğini ekleyin ve true olarak ayarlayın.

...
<Definition Id="Counting_Widget"
    DisplayName="Microsoft Counting Widget"
    Description="CONFIG counting widget description"
    IsCustomizable="true">
...

WidgetProvider.h dosyasını güncelleştirme

Bu makaledeki önceki adımlarda oluşturulan pencere öğesine özelleştirme desteği eklemek için pencere öğesi sağlayıcımız WidgetProvider.h için üst bilgi dosyasını güncelleştirmemiz gerekir.

İlk olarak CompactWidgetInfo tanımını güncelleştirin. Bu yardımcı yapı, etkin pencere öğelerimizin geçerli durumunu izlememize yardımcı olur. Pencere öğesi sunucusunun normal pencere öğesi şablonu yerine özelleştirme JSON şablonumuzu göndermemizi beklediği zamanları izlemek için kullanılacak inCustomization alanını ekleyin.

// WidgetProvider.h
struct CompactWidgetInfo
{
    winrt::hstring widgetId;
    winrt::hstring widgetName;
    int customState = 0;
    bool isActive = false;
    bool inCustomization = false;
};

IWidgetProvider2 arabirimini uygulamak için WidgetProvider bildirimini güncelleştirin.

// WidgetProvider.h

struct WidgetProvider : winrt::implements<WidgetProvider, winrt::Microsoft::Windows::Widgets::Providers::IWidgetProvider, winrt::Microsoft::Windows::Widgets::Providers::IWidgetProvider2>

IWidgetProvider2 arabiriminin OnCustomizationRequested geri çağırması için bir bildirim ekleyin.

// WidgetProvider.h

void OnCustomizationRequested(winrt::Microsoft::Windows::Widgets::Providers::WidgetCustomizationRequestedArgs args);

Son olarak, pencere öğesi özelleştirme kullanıcı arabirimi için JSON şablonunu tanımlayan bir dize değişkeni bildirin. Bu örnekte, sağlayıcımızın normal pencere öğesi davranışına dönmesi için sinyal veren bir "Sayacı sıfırla" düğmesi ve "Özelleştirmeden çık" düğmemiz vardır.

// WidgetProvider.h
const std::string countWidgetCustomizationTemplate = R"(
{
    "type": "AdaptiveCard",
    "actions" : [
        {
            "type": "Action.Execute",
            "title" : "Reset counter",
            "verb": "reset"
            },
            {
            "type": "Action.Execute",
            "title": "Exit customization",
            "verb": "exitCustomization"
            }
    ],
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.5"
})";

Güncelleştirme WidgetProvider.cpp

Şimdi pencere öğesi özelleştirme davranışını uygulamak için WidgetProvider.cpp dosyasını güncelleştirin. Bu yöntem, kullandığımız diğer geri çağırmalarla aynı deseni kullanır. WidgetContext'ten özelleştirilecek pencere öğesinin kimliğini alır ve bu pencere öğesiyle ilişkili CompactWidgetInfo yardımcı yapısını bulur ve inCustomization alanını true olarak ayarlarız.

//WidgetProvider.cpp
void WidgetProvider::OnCustomizationRequested(winrt::WidgetCustomizationRequestedArgs args)
{
    auto widgetId = args.WidgetContext().Id();

    if (const auto iter = RunningWidgets.find(widgetId); iter != RunningWidgets.end())
    {
        auto& localWidgetInfo = iter->second;
        localWidgetInfo.inCustomization = true;

        UpdateWidget(localWidgetInfo);
    }
}

Ardından, verilerimizi ve görsel JSON şablonlarımızı pencere öğesi konağına gönderen UpdateWidget yardımcı yöntemimizi güncelleştireceğiz. Sayım pencere öğesini güncelleştirirken inCustomization alanının değerine bağlı olarak normal pencere öğesi şablonunu veya özelleştirme şablonunu göndeririz. Kısa olması için bu kod parçacığında özelleştirmeyle ilgili olmayan kod atlanır.

//WidgetProvider.cpp
void WidgetProvider::UpdateWidget(CompactWidgetInfo const& localWidgetInfo)
{
    ...
    else if (localWidgetInfo.widgetName == L"Counting_Widget")
    {
        if (!localWidgetInfo.inCustomization)
        {
            std::wcout << L" - not in customization " << std::endl;
            templateJson = winrt::to_hstring(countWidgetTemplate);
		}
        else
        {
            std::wcout << L" - in customization " << std::endl;
            templateJson = winrt::to_hstring(countWidgetCustomizationTemplate);
		}
    }
    ...
    
    updateOptions.Template(templateJson);
    updateOptions.Data(dataJson);
    // !!  You can store some custom state in the widget service that you will be able to query at any time.
    updateOptions.CustomState(winrt::to_hstring(localWidgetInfo.customState));
    winrt::WidgetManager::GetDefault().UpdateWidget(updateOptions);
}

Kullanıcılar özelleştirme şablonumuzdaki girişlerle etkileşime geçtiğinde, kullanıcı normal pencere öğesi deneyimiyle etkileşime geçtiğinde olduğu gibi Aynı OnActionInvoked işleyicisini çağırır. Özelleştirmeyi desteklemek için özelleştirme JSON şablonumuzda "reset" ve "exitCustomization" fiillerini ararız. Eylem "Sayacı sıfırla" düğmesine yönelikse, yardımcı yapımızın customState alanında tutulan sayacı 0 olarak sıfırlarız. Eylem "Özelleştirmeden çık" düğmesi içinse inCustomization alanını false olarak ayarlarız, böylece UpdateWidget'i çağırdığımızda yardımcı yöntemimiz özelleştirme şablonunu değil normal JSON şablonlarını gönderir.

//WidgetProvider.cpp
void WidgetProvider::OnActionInvoked(winrt::WidgetActionInvokedArgs actionInvokedArgs)
{
    auto verb = actionInvokedArgs.Verb();
    if (verb == L"inc")
    {
        auto widgetId = actionInvokedArgs.WidgetContext().Id();
        // If you need to use some data that was passed in after
        // Action was invoked, you can get it from the args:
        auto data = actionInvokedArgs.Data();
        if (const auto iter = RunningWidgets.find(widgetId); iter != RunningWidgets.end())
        {
            auto& localWidgetInfo = iter->second;
            // Increment the count
            localWidgetInfo.customState++;
            UpdateWidget(localWidgetInfo);
        }
    }
    else if (verb == L"reset") 
    {
        auto widgetId = actionInvokedArgs.WidgetContext().Id();
        auto data = actionInvokedArgs.Data();
        if (const auto iter = RunningWidgets.find(widgetId); iter != RunningWidgets.end())
        {
            auto& localWidgetInfo = iter->second;
            // Reset the count
            localWidgetInfo.customState = 0;
            localWidgetInfo.inCustomization = false;
            UpdateWidget(localWidgetInfo);
        }
    }
    else if (verb == L"exitCustomization")
    {
        auto widgetId = actionInvokedArgs.WidgetContext().Id();
        // If you need to use some data that was passed in after
        // Action was invoked, you can get it from the args:
        auto data = actionInvokedArgs.Data();
        if (const auto iter = RunningWidgets.find(widgetId); iter != RunningWidgets.end())
        {
            auto& localWidgetInfo = iter->second;
            // Stop sending the customization template
            localWidgetInfo.inCustomization = false;
            UpdateWidget(localWidgetInfo);
        }
    }
}

Şimdi pencere öğesinizi dağıtırken üç nokta menüsünde Pencere öğesini özelleştir düğmesini görmeniz gerekir. Özelleştir düğmesine tıkladığınızda özelleştirme şablonunuz görüntülenir.

Pencere öğelerini özelleştirme kullanıcı arabirimini gösteren ekran görüntüsü.

Sayacı sıfırla düğmesine tıklayarak sayacı 0'a sıfırlayın. Pencere öğesinizin normal davranışına dönmek için Özelleştirmeden çık düğmesine tıklayın.