Aracılığıyla paylaş


C# Windows Uygulamasında pencere öğesi sağlayıcısı uygulama

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++/WinRT kullanarak pencere öğesi sağlayıcısı uygulamak için bkz. Win32 uygulamasında pencere öğesi sağlayıcısı uygulama (C++/WinRT).

Ö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# konsol uygulaması oluşturma

Visual Studio'da yeni bir proje oluşturun. Yeni proje oluştur iletişim kutusunda dil filtresini "C#" ve platform filtresini Windows olarak ayarlayın, ardından Konsol Uygulaması proje şablonunu seçin. Yeni projeyi "ExampleWidgetProvider" olarak adlandırın. İstendiğinde hedef .NET sürümünü 8.0 olarak ayarlayın.

Proje yüklendiğinde, Çözüm Gezgini'nde proje adına sağ tıklayın ve Özelliklerseçin. Genel sayfasında, aşağı kaydırarak Hedef İşletim Sistemi'ne gelin ve "Windows" seçeneğini belirleyin. Hedef İşletim Sistemi Sürümü'nin altında sürüm 10.0.19041.0 veya üzerini seçin.

Projenizi .NET 8.0'ı destekleyecek şekilde güncelleştirmek için Çözüm Gezgini'nde proje adına sağ tıklayın ve Proje Dosyasını Düzenle'yi seçin. PropertyGroup'un içine aşağıdaki RuntimeIdentifiers öğesini ekleyin.

<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>

Bu kılavuzda, kolay hata ayıklamayı etkinleştirmek için pencere öğesi etkinleştirildiğinde konsol penceresini görüntüleyen bir konsol uygulaması kullanıldığına dikkat edin. Pencere öğesi sağlayıcı uygulamanızı yayımlamaya hazır olduğunuzda konsol uygulamanızı Windows uygulamasına dönüştürme bölümünde yer alan adımları izleyerek konsol uygulamasını bir Windows uygulamasına dönüştürebilirsiniz.

Windows Uygulama SDK'ye bağıntılar ekleme

Bu örnek en son kararlı Windows Uygulama SDK'sı NuGet paketini kullanır. Çözüm Gezgini'ndeBağımlılıklar'a sağ tıklayın ve NuGet paketlerini yönet... öğesini 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.

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. Oluşturulan WidgetProvider.cs dosyasında sınıf tanımını , IWidgetProvider arabirimini uyguladığını gösterecek şekilde güncelleştirin.

// WidgetProvider.cs
internal class WidgetProvider : IWidgetProvider

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.cs dosyasına ExampleWidgetProvider ad alanının içine, ancak WidgetProvider sınıf tanımının dışına ekleyin.

// WidgetProvider.cs

public class CompactWidgetInfo
{
    public string? widgetId { get; set; }
    public string? widgetName { get; set; }
    public int customState = 0;
    public bool isActive = false;

}

WidgetProvider.cs dosyasındaki WidgetProvider sınıf tanımının içine, her girişin anahtarı olarak pencere öğesi kimliğini kullanarak etkin pencere öğelerinin listesini koruyacak bir dizin üyesi ekleyin.

// WidgetProvider.cs

// Class member of WidgetProvider
public static Dictionary<string, CompactWidgetInfo> RunningWidgets = new Dictionary<string, CompactWidgetInfo>(); 

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ının üye değişkenlerinde 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 Widgets 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.cs

// Class members of WidgetProvider
        const string weatherWidgetTemplate = """
{
    "$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 string countWidgetTemplate = """
{                                                                     
    "type": "AdaptiveCard",                                         
    "body": [                                                         
        {                                                               
            "type": "TextBlock",                                    
            "text": "You have clicked the button ${count} times"    
        },
        {
                "text":"Rendering Only if Small",
                "type":"TextBlock",
                "$when":"${$host.widgetSize==\"small\"}"
        },
        {
                "text":"Rendering Only if Medium",
                "type":"TextBlock",
                "$when":"${$host.widgetSize==\"medium\"}"
        },
        {
            "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.

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.

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.cs

public void CreateWidget(WidgetContext widgetContext)
{
    var widgetId = widgetContext.Id; // To save RPC calls
    var widgetName = widgetContext.DefinitionId;
    CompactWidgetInfo runningWidgetInfo = new CompactWidgetInfo() { widgetId = widgetId, widgetName = 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.cs

public void DeleteWidget(string widgetId, string customState)
{
    RunningWidgets.Remove(widgetId);

    if(RunningWidgets.Count == 0)
    {
        emptyWidgetListEvent.Set();
    }
}

Bu örnekte, etkin pencere öğeleri listesinden belirtilen pencere öğesini kaldırmaya ek olarak, listenin artık boş olup olmadığını da denetleriz ve boşsa, etkin pencere öğesi olmadığında uygulamanın çıkışına izin vermek için daha sonra kullanılacak bir olay ayarlarız. Sınıf tanımınızın içine ManualResetEvent bildirimini ve genel erişimci işlevini ekleyin.

// WidgetProvider.cs
static ManualResetEvent emptyWidgetListEvent = new ManualResetEvent(false);

public static ManualResetEvent GetEmptyWidgetListEvent()
{
    return emptyWidgetListEvent;
}

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.cs

public void OnActionInvoked(WidgetActionInvokedArgs actionInvokedArgs)
{
    var verb = actionInvokedArgs.Verb;
        if (verb == "inc")
        {
            var 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:
            var data = actionInvokedArgs.Data;
            if (RunningWidgets.ContainsKey(widgetId))
            {
                var localWidgetInfo = RunningWidgets[widgetId];
                // 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.cs

public void OnWidgetContextChanged(WidgetContextChangedArgs contextChangedArgs)
{
    var widgetContext = contextChangedArgs.WidgetContext;
    var widgetId = widgetContext.Id;
    var widgetSize = widgetContext.Size;
    if (RunningWidgets.ContainsKey(widgetId))
    {
        var localWidgetInfo = RunningWidgets[widgetId];
        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.

// WidgetProvider.cs

public void Activate(WidgetContext widgetContext)
{
    var widgetId = widgetContext.Id;

    if (RunningWidgets.ContainsKey(widgetId))
    {
        var localWidgetInfo = RunningWidgets[widgetId];
        localWidgetInfo.isActive = true;

        UpdateWidget(localWidgetInfo);
    }
}
public void Deactivate(string widgetId)
{
    if (RunningWidgets.ContainsKey(widgetId))
    {
        var localWidgetInfo = RunningWidgets[widgetId];
        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.cs

void UpdateWidget(CompactWidgetInfo localWidgetInfo)
{
    WidgetUpdateRequestOptions updateOptions = new WidgetUpdateRequestOptions(localWidgetInfo.widgetId);

    string? templateJson = null;
    if (localWidgetInfo.widgetName == "Weather_Widget")
    {
        templateJson = weatherWidgetTemplate.ToString();
    }
    else if (localWidgetInfo.widgetName == "Counting_Widget")
    {
        templateJson = countWidgetTemplate.ToString();
    }

    string? dataJson = null;
    if (localWidgetInfo.widgetName == "Weather_Widget")
    {
        dataJson = "{}";
    }
    else if (localWidgetInfo.widgetName == "Counting_Widget")
    {
        dataJson = "{ \"count\": " + localWidgetInfo.customState.ToString() + " }";
    }

    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= localWidgetInfo.customState.ToString();
    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'u ç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 sınıf tanımına yapıştırın.

// WidgetProvider.cs

public WidgetProvider()
{
    var runningWidgets = WidgetManager.GetDefault().GetWidgetInfos();

    foreach (var widgetInfo in runningWidgets)
    {
        var widgetContext = widgetInfo.WidgetContext;
        var widgetId = widgetContext.Id;
        var widgetName = widgetContext.DefinitionId;
        var customState = widgetInfo.CustomState;
        if (!RunningWidgets.ContainsKey(widgetId))
        {
            CompactWidgetInfo runningWidgetInfo = new CompactWidgetInfo() { widgetId = widgetId, widgetName = 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 = Convert.ToInt32(customState.ToString());
                runningWidgetInfo.customState = count;
            }
            catch
            {

            }
            RunningWidgets[widgetId] = runningWidgetInfo;
        }
    }
}

İstek üzerine WidgetProvider örneği oluşturacak bir sınıf fabrikası uygulayın

Pencere öğesi ana bilgisayarının pencere öğesi sağlayıcımızla iletişim kurabilmesi için CoRegisterClassObjectçağrısı yapmamız gerekir. Bu işlev, WidgetProvider sınıfımız için bir sınıf nesnesi oluşturacak IClassFactory uygulamasını oluşturmamızı gerektirir. Sınıf fabrikamızı bağımsız bir yardımcı sınıfında uygulayacağız.

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ı "FactoryHelper" olarak adlandırın ve Ekledüğmesine tıklayın.

FactoryHelper.cs dosyasının içeriğini aşağıdaki kodla değiştirin. Bu kod, IClassFactory arabirimini tanımlar ve CreateInstance ve LockServeriki yöntemini uygular. Bu kod, sınıf fabrikası uygulamak için tipik bir şablon koddur ve oluşturulan sınıf nesnesinin IWidgetProvider arabirimini uyguladığını belirtmemiz dışında bir araç sağlayıcısının işlevselliğine özgü değildir.

// FactoryHelper.cs

using Microsoft.Windows.Widgets.Providers;
using System.Runtime.InteropServices;
using WinRT;

namespace COM
{
    static class Guids
    {
        public const string IClassFactory = "00000001-0000-0000-C000-000000000046";
        public const string IUnknown = "00000000-0000-0000-C000-000000000046";
    }

    /// 
    /// IClassFactory declaration
    /// 
    [ComImport, ComVisible(false), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(COM.Guids.IClassFactory)]
    internal interface IClassFactory
    {
        [PreserveSig]
        int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
        [PreserveSig]
        int LockServer(bool fLock);
    }

    [ComVisible(true)]
    class WidgetProviderFactory<T> : IClassFactory
    where T : IWidgetProvider, new()
    {
        public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)
        {
            ppvObject = IntPtr.Zero;

            if (pUnkOuter != IntPtr.Zero)
            {
                Marshal.ThrowExceptionForHR(CLASS_E_NOAGGREGATION);
            }

            if (riid == typeof(T).GUID || riid == Guid.Parse(COM.Guids.IUnknown))
            {
                // Create the instance of the .NET object
                ppvObject = MarshalInspectable<IWidgetProvider>.FromManaged(new T());
            }
            else
            {
                // The object that ppvObject points to does not support the
                // interface identified by riid.
                Marshal.ThrowExceptionForHR(E_NOINTERFACE);
            }

            return 0;
        }

        int IClassFactory.LockServer(bool fLock)
        {
            return 0;
        }

        private const int CLASS_E_NOAGGREGATION = -2147221232;
        private const int E_NOINTERFACE = -2147467262;

    }
}

Pencere öğesi sağlayıcınız için CLSID'yi temsil eden bir GUID oluşturun.

Ardından, COM etkinleştirmesi için pencere öğesi sağlayıcınızı tanımlamak için kullanılacak CLSID'yi temsil eden bir GUID oluşturmanız gerekir. Uygulamanızı paketlerken de aynı değer kullanılır. Araçlar-GUID> Oluştur'a giderek Visual Studio'da BIR GUID oluşturun. Kayıt defteri biçimi seçeneğini belirleyin ve Kopyala'ya tıklayın ve daha sonra kopyalayabilmeniz için bunu bir metin dosyasına yapıştırın.

OLE ile pencere öğesi sağlayıcısı sınıf nesnesini kaydetme

Yürütülebilir dosyamızın Program.cs dosyasında, pencere öğesi sağlayıcımızı OLE'ye kaydetmek için CoRegisterClassObject'i çağıracağız, böylece pencere öğesi konağı onunla etkileşim kurabilir. Program.cs içeriğini aşağıdaki kodla değiştirin. Bu kod CoRegisterClassObject işlevini içeri aktarır ve önceki adımda tanımladığımız WidgetProviderFactory arabirimini geçirerek bu işlevi çağırır. önceki adımda oluşturduğunuz GUID'yi kullanmak için CLSID_Factory değişken bildirimini güncelleştirdiğinizden emin olun.

// Program.cs

using System.Runtime.InteropServices;
using ComTypes = System.Runtime.InteropServices.ComTypes;
using Microsoft.Windows.Widgets;
using ExampleWidgetProvider;
using COM;
using System;

[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();

[DllImport("ole32.dll")]

static extern int CoRegisterClassObject(
            [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
            [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
            uint dwClsContext,
            uint flags,
            out uint lpdwRegister);

[DllImport("ole32.dll")] static extern int CoRevokeClassObject(uint dwRegister);

Console.WriteLine("Registering Widget Provider");
uint cookie;

Guid CLSID_Factory = Guid.Parse("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
CoRegisterClassObject(CLSID_Factory, new WidgetProviderFactory<WidgetProvider>(), 0x4, 0x1, out cookie);
Console.WriteLine("Registered successfully. Press ENTER to exit.");
Console.ReadLine();

if (GetConsoleWindow() != IntPtr.Zero)
{
    Console.WriteLine("Registered successfully. Press ENTER to exit.");
    Console.ReadLine();
}
else
{
    // Wait until the manager has disposed of the last widget provider.
    using (var emptyWidgetListEvent = WidgetProvider.GetEmptyWidgetListEvent())
    {
        emptyWidgetListEvent.WaitOne();
    }

    CoRevokeClassObject(cookie);
}

Bu kod örneğinin, uygulamanın konsol uygulaması olarak çalışıp çalışmadığını belirlemek için GetConsoleWindow işlevini kullandığını ve bunun bu kılavuzun varsayılan davranışı olduğunu unutmayın. İşlev geçerli bir işaretçi döndürürse, konsola hata ayıklama bilgileri yazarız. Aksi takdirde, uygulama bir Windows uygulaması olarak çalışır. Bu durumda, etkin widget listesinin boş olduğu DeleteWidget yönteminde ayarladığımız olayı bekleriz ve ardından uygulamadan çıkarız. Örnek konsol uygulamasını Windows uygulamasına dönüştürme hakkında bilgi için bkz. Konsol uygulamanızı Windows uygulamasına dönüştürme.

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 Çözüm Gezgini'ndeExampleWidgetProvider projesine sağ tıklayın ve Özellikler'i seçin. Uygulama->Genel altında Çıkış türünü "Konsol Uygulaması"ndan "Windows Uygulaması"na yapın.

Çı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ı, pencere öğesi konağından gelen isteklere şablon ve normal pencere öğesi deneyimi için veri yükleri ile 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. Kullanıcının uygulama tanımlı çıkış özelleştirme eylemine tıklamadan özelleştirme deneyimini kapatması mümkündür. Bu durumda, IWidgetProviderAnalytics.OnAnalyticsInfoReported tetiklenir ve WidgetAnalyticsInfoReportedArgs.AnalyticsJson bir interactionKind 'exitCustomization' değerine sahip olur.
  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 öğesine IsCustomizable özniteliğini ekleyin ve true olarak ayarlayın.

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

Bir pencere öğesinin özelleştirme modunda olduğunu izleme

Bu makaledeki örnek, etkin pencere öğelerimizin geçerli durumunu izlemek için CompactWidgetInfo yardımcı yapısını kullanır. 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.cs
public class CompactWidgetInfo
{
    public string widgetId { get; set; }
    public string widgetName { get; set; }
    public int customState = 0;
    public bool isActive = false;
    public bool inCustomization = false;
}

IWidgetProvider2'yi Gerçekleştir

Pencere öğesi özelleştirme özelliği IWidgetProvider2 arabirimi aracılığıyla kullanıma sunulur. Bu arabirimi uygulamak için WidgetProvider sınıf tanımını güncelleştirin.

// WidgetProvider.cs
internal class WidgetProvider : IWidgetProvider, IWidgetProvider2

IWidgetProvider2 arabiriminin OnCustomizationRequested geri çağırması için bir uygulama ekleyin. 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.cs
public void OnCustomizationRequested(WidgetCustomizationRequestedArgs customizationInvokedArgs)
{
    var widgetId = customizationInvokedArgs.WidgetContext.Id;
    if (RunningWidgets.ContainsKey(widgetId))
    {
        var localWidgetInfo = RunningWidgets[widgetId];
        localWidgetInfo.inCustomization = true;
        UpdateWidget(localWidgetInfo);
    }
}

Şimdi, 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. Bu tanımı diğer şablon tanımlarının yanına yerleştirin.

// WidgetProvider.cs
const string countWidgetCustomizationTemplate = @"
{
    ""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""
}";

UpdateWidget'te özelleştirme şablonu gönderme

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.cs
void UpdateWidget(CompactWidgetInfo localWidgetInfo)
{
    ...
    else if (localWidgetInfo.widgetName == "Counting_Widget")
    {
        if (!localWidgetInfo.inCustomization)
        {
            templateJson = countWidgetTemplate.ToString();
        }
        else
        {
            templateJson = countWidgetCustomizationTemplate.ToString();
        }
    
    }
    ...
    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 = localWidgetInfo.customState.ToString();
    WidgetManager.GetDefault().UpdateWidget(updateOptions);
}

Özelleştirme eylemlerine yanıt verme

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.cs
public void OnActionInvoked(WidgetActionInvokedArgs actionInvokedArgs)
{
    var verb = actionInvokedArgs.Verb;
    if (verb == "inc")
    {
        var 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:
        var data = actionInvokedArgs.Data;
        if (RunningWidgets.ContainsKey(widgetId))
        {
            var localWidgetInfo = RunningWidgets[widgetId];
            // Increment the count
            localWidgetInfo.customState++;
            UpdateWidget(localWidgetInfo);
        }
    } 
    else if (verb == "reset") 
    {
        var widgetId = actionInvokedArgs.WidgetContext.Id;
        var data = actionInvokedArgs.Data;
        if (RunningWidgets.ContainsKey(widgetId))
        {
            var localWidgetInfo = RunningWidgets[widgetId];
            // Reset the count
            localWidgetInfo.customState = 0;
            localWidgetInfo.inCustomization = false;
            UpdateWidget(localWidgetInfo);
        }
    }
    else if (verb == "exitCustomization")
    {
        var widgetId = actionInvokedArgs.WidgetContext.Id;
        var data = actionInvokedArgs.Data;
        if (RunningWidgets.ContainsKey(widgetId))
        {
            var localWidgetInfo = RunningWidgets[widgetId];
            // 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.