Megosztás:


Widget-szolgáltató implementálása C# Windows-alkalmazásban

Ez a cikk bemutatja, hogyan hozhat létre egy egyszerű widget-szolgáltatót, amely megvalósítja az IWidgetProvider felületet. Ennek a felületnek a metódusait a widget-gazdagép meghívja, hogy kérje le a widgetet meghatározó adatokat, vagy hogy a widgetszolgáltató válaszoljon egy widget felhasználói műveletére. A widgetszolgáltatók egyetlen vagy több widgetet is támogathatnak. Ebben a példában két különböző widgetet határozunk meg. Az egyik widget egy szimulált időjárási widget, amely az Adaptív kártyák keretrendszer által biztosított formázási lehetőségek némelyikét mutatja be. A második widget bemutatja a felhasználói műveleteket és az egyéni widgetállapot-funkciót egy olyan számláló fenntartásával, amely növekszik, amikor a felhasználó a widgeten megjelenő gombra kattint.

Képernyőkép egy egyszerű időjárási widgetről. A widget az időjárással kapcsolatos ábrákat és adatokat, valamint néhány diagnosztikai szöveget jelenít meg, amelyek azt szemléltetik, hogy a közepes méretű widget sablonja jelenik meg.

Képernyőkép egy egyszerű számláló widgetről. A widget egy karakterláncot jelenít meg, amely tartalmazza a növelendő számértéket, egy

A cikkben szereplő mintakód a Windows App SDK widgetek mintáiból lett átdolgozva. A widget-szolgáltató C++/WinRT használatával történő implementálásához lásd: Widget-szolgáltató implementálása win32-alkalmazásban (C++/WinRT).

Előfeltételek

  • Az eszköznek engedélyeznie kell a fejlesztői módot. További információ: Beállítások fejlesztőknek.
  • Visual Studio 2022 vagy újabb verzió a Univerzális Windows Platform fejlesztési munkafolyamattal. Mindenképpen adja hozzá a C++ (v143) összetevőt az opcionális legördülő listából.

Új C#-konzolalkalmazás létrehozása

Hozzon létre egy új projektet a Visual Studióban. Az Új projekt létrehozása párbeszédpanelen állítsa a nyelvi szűrőt "C#" értékre, a platformszűrőt pedig Windowsra, majd válassza ki a Konzolalkalmazás projektsablont. Nevezze el az új projektet "ExampleWidgetProvider" néven. Amikor a rendszer kéri, állítsa a cél .NET-verziót 8.0-ra.

Amikor a projekt betöltődik, a Megoldáskezelőben kattintson a jobb gombbal a projekt nevére, és válassza a Tulajdonságok lehetőséget. Az Általános lapon görgessen le a Cél Rendszer részhez, és válassza a "Windows" lehetőséget. A Cél operációsrendszer-verzió területen válassza a 10.0.19041.0-s vagy újabb verziót.

Ha frissíteni szeretné a projektet a .NET 8.0 támogatásához, a Megoldáskezelőben kattintson a jobb gombbal a projekt nevére, és válassza a Projektfájl szerkesztése lehetőséget. A Tulajdonságcsoporton belül adja hozzá a következő RuntimeIdentifiers elemet.

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

Vegye figyelembe, hogy ez az útmutató egy konzolalkalmazást használ, amely megjeleníti a konzolablakot a widget aktiválásakor a könnyű hibakeresés érdekében. Ha készen áll a widget-szolgáltató alkalmazás közzétételére, a konzolalkalmazást Windows-alkalmazássá alakíthatja a konzolalkalmazás konvertálása Windows-alkalmazássá a konzolalkalmazás konvertálása című témakörben leírt lépések végrehajtásával.

Hivatkozások hozzáadása a Windows App SDK-hoz

Ez a minta a legújabb stabil Windows App SDK NuGet-csomagot használja. A Megoldáskezelőben kattintson a jobb gombbal a Függőségek elemre , és válassza a NuGet-csomagok kezelése... lehetőséget. A NuGet-csomagkezelőben válassza a Tallózás lapot, és keressen rá a "Microsoft.WindowsAppSDK" kifejezésre. Válassza ki a legújabb stabil verziót a Verzió legördülő listában, majd kattintson a Telepítés gombra.

WidgetProvider-osztály hozzáadása a widgetműveletek kezeléséhez

A Visual Studio-ban kattintson a jobb gombbal a ExampleWidgetProvider projektre a Megoldáskezelőben, és válassza a Hozzáadás ->Osztálylehetőséget. Az Osztály hozzáadása párbeszédpanelen nevezze el a "WidgetProvider" osztályt, majd kattintson a hozzáadása elemre. A létrehozott WidgetProvider.cs fájlban frissítse az osztálydefiníciót, hogy azt jelezze, hogy implementálja az IWidgetProvider felületet.

// WidgetProvider.cs
internal class WidgetProvider : IWidgetProvider

Felkészülés az engedélyezett widgetek nyomon követésére

A widget-szolgáltatók egyetlen vagy több widgetet is támogathatnak. Amikor a widget-gazdagép műveletet kezdeményez a widget-szolgáltatónál, egy azonosítót ad át a művelethez társított widget azonosításához. Minden vezérlőhöz tartozik egy társított név és egy állapotérték is, amely egyéni adatok tárolására használható. Ebben a példában egy egyszerű segédstruktúrát deklarálunk az egyes rögzített vezérlők azonosítójának, nevének és adatainak tárolásához. A widgetek aktív állapotban is lehetnek, amelyet az alábbi Aktiválás és inaktiválás szakaszban ismertetünk, és ezt az állapotot minden widget esetében logikai értékkel követjük nyomon. Adja hozzá a következő definíciót a WidgetProvider.cs fájlhoz az ExampleWidgetProvider névtérben, de a WidgetProvider osztálydefiníción kívül.

// WidgetProvider.cs

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

}

A WidgetProvider.cs WidgetProvider osztálydefiníciójában adjon hozzá egy tagot a térképhez, amely megőrzi az engedélyezett widgetek listáját, és minden bejegyzéshez kulcsként használja a widget azonosítóját.

// WidgetProvider.cs

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

Widgetsablon JSON-sztringjeinek deklarálása

Ez a példa néhány statikus sztringet deklarál az egyes vezérlők JSON-sablonjainak meghatározásához. A kényelem érdekében ezek a sablonok a WidgetProvider osztály tagváltozóiban vannak tárolva. Ha általános tárterületre van szüksége a sablonokhoz , az alkalmazáscsomag részeként is felvehetők: Csomagfájlok elérése. A widgetsablon JSON-dokumentumának létrehozásáról további információt az Adaptív kártyatervezővel rendelkező widgetsablon létrehozása című témakörben talál.

A legújabb kiadásban a Windows-vezérlőket implementáló alkalmazások testre szabhatják a widgethez megjelenített fejlécet a Widgets Boardban, felülírva az alapértelmezett bemutatót. További információ: A widget fejlécterületének testreszabása.

Megjegyzés:

A legújabb kiadásban a Windows-widgeteket implementáló alkalmazások dönthetnek úgy, hogy a widget tartalmát egy megadott URL-címről kiszolgált HTML-lel töltik fel ahelyett, hogy a szolgáltatótól a Widgets Boardnak átadott JSON-hasznos adatban adja meg az Adaptív kártya sémaformátumában lévő tartalmat. A vezérlőszolgáltatóknak továbbra is rendelkezniük kell egy adaptív kártya JSON-hasznos adatával, így az útmutató implementálási lépései a webes widgetekre vonatkoznak. További információ: Webes widget-szolgáltatók.

// 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"                                                
}
""";

Az IWidgetProvider metódusok implementálása

A következő néhány szakaszban implementáljuk az IWidgetProvider felület módszereit. A cikk későbbi részében megjelenik az a UpdateWidget segítő metódus, amelyet több ilyen metódusmegvalósításban is meghívnak.

Megjegyzés:

Az IWidgetProvider felület visszahívási metódusaiba átadott objektumok csak a visszahíváson belül lesznek érvényesek. Ne tároljon hivatkozásokat ezekre az objektumokra, mert a visszahívás környezetén kívüli viselkedésük nincs meghatározva.

CreateWidget

A widget-gazdagép meghívja a CreateWidgetet , amikor a felhasználó az alkalmazás egyik widgetjét rögzítette a widget-gazdagépen. Először is ez a módszer lekéri a társított widget azonosítóját és nevét, és hozzáad egy új példányt a compactWidgetInfo segédstruktúránkhoz az engedélyezett widgetek gyűjteményéhez. Ezután elküldjük a widget kezdeti sablonját és adatait, amely az UpdateWidget segédmetódusban van beágyazva.

// 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);
}

Widget törlése

A widget-gazdagép akkor hívja meg a DeleteWidgetet , ha a felhasználó törölte az alkalmazás egyik widgetét a widget-gazdagépről. Ha ez történik, eltávolítjuk a társított widgetet az engedélyezett widgetek listájából, hogy ne küldhessünk további frissítéseket a widgethez.

// WidgetProvider.cs

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

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

Ebben a példában amellett, hogy eltávolítjuk a widgetet az engedélyezett widgetek listájából, azt is ellenőrizzük, hogy a lista üres-e, és ha igen, akkor beállítunk egy eseményt, amely később lesz használva, hogy az alkalmazás kiléphessen, ha nincsenek engedélyezett widgetek. Az osztálydefiníción belül adja hozzá a ManualResetEvent deklarációját és egy nyilvános kiegészítő függvényt.

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

public static ManualResetEvent GetEmptyWidgetListEvent()
{
    return emptyWidgetListEvent;
}

OnActionInvoked

A widget-gazdagép meghívja az OnActionInvoked parancsot , amikor a felhasználó egy, a widgetsablonban meghatározott művelettel lép kapcsolatba. Az ebben a példában használt számláló widget esetében a widget JSON-sablonjában egy "inc" értékű műveletet deklaráltak. A widget-szolgáltató kódja ezt az igeértéket használja annak meghatározására, hogy milyen műveletet kell elvégezni a felhasználói beavatkozásra válaszul.

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

Az OnActionInvoked metódusban szerezze meg az ige értékét a WidgetActionInvokedArgs objektum Verb tulajdonságának ellenőrzésével. Ha az ige "inc", akkor tudjuk, hogy a widget testreszabott állapotában növelni fogjuk a számlálót. A WidgetActionInvokedArgs fájlból kérje le a WidgetContext objektumot, majd a WidgetId azonosítót a frissített widget azonosítójának lekéréséhez. Keresse meg a bejegyzést az engedélyezett widgetek térképén a megadott azonosítóval, majd frissítse a növekmények tárolásához használt egyéni állapotértéket. Végül frissítse a widget tartalmát az új értékkel az UpdateWidget segédfüggvénnyel.

// 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);
            }
        }
}

Az Adaptív kártyák Action.Execute szintaxisával kapcsolatos információkért lásd: Action.Execute. A widgetek interakciójának tervezésével kapcsolatos útmutatásért tekintse meg vezérlők interakciójának tervezési útmutatóját

OnWidgetContextChanged

Az aktuális kiadásban az OnWidgetContextChanged csak akkor lesz meghívva, ha a felhasználó módosítja a rögzített widget méretét. A kért mérettől függően másik JSON-sablont/adatot adhat vissza a widget-gazdagépnek. A JSON sablont úgy is megtervezheti, hogy a host.widgetSize értékétől függően feltételes rendereléssel támogassa az összes elérhető méretet. Ha nem kell új sablont vagy adatokat küldenie a méretváltozáshoz, az OnWidgetContextChanged telemetriai célokra használható.

// 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);
    }
}
    

Aktiválás és inaktiválás

Az Activate metódust meghívva értesítheti a widget-szolgáltatót arról, hogy a widget-gazdagép jelenleg szeretne frissített tartalmat kapni a szolgáltatótól. Ez például azt jelentheti, hogy a felhasználó jelenleg aktívan tekinti meg a widget-gazdagépet. A rendszer meghívja az Inaktiválás metódust, amely értesíti a widget-szolgáltatót arról, hogy a widget-gazdagép már nem kér tartalomfrissítéseket. Ez a két módszer határoz meg egy ablakot, amelyben a widget-gazdagép leginkább a up-to-date tartalmat szeretné ábrázolni. A widget-szolgáltatók bármikor küldhetnek frissítéseket a widgetnek, például leküldéses értesítésre válaszolva, de mint minden háttérfeladat esetében, fontos, hogy up-todátumtartalmat biztosítson az erőforrásokkal kapcsolatos problémákkal, például az akkumulátor üzemidejével.

aktiválása és Inaktiválás meghívása widgetenként történik. Ez a példa a CompactWidgetInfo segédstruktúra egyes vezérlőinek aktív állapotát követi nyomon. Az Aktiválás metódusban meghívjuk az UpdateWidget segédmetódust a widget frissítéséhez. Vegye figyelembe, hogy az aktiválás és az inaktiválás közötti időablak kicsi lehet, ezért javasoljuk, hogy próbálja meg a lehető leggyorsabban frissíteni a widget kódját.

// 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 frissítése

Adja meg az UpdateWidget segédmetódusát egy engedélyezett widget frissítéséhez. Ebben a példában ellenőrizzük a CompactWidgetInfo segédstruktúrában átadott widget nevét, majd beállítjuk a megfelelő sablont és annak adat JSON-ját, annak függvényében, hogy melyik widgetet frissítjük. A WidgetUpdateRequestOptions inicializálva van a frissített widget sablonjával, adataival és egyéni állapotával. Hívja meg a WidgetManager::GetDefault parancsot a WidgetManager osztály egy példányának lekéréséhez, majd az UpdateWidget hívásával küldje el a frissített widgetadatokat a widget-gazdagépnek.

// 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);
}

Az engedélyezett widgetek listájának inicializálása indításkor

A widget-szolgáltató első inicializálásakor érdemes megkérdezni a WidgetManagert , hogy vannak-e futó widgetek, amelyeket a szolgáltató jelenleg kiszolgál. Segít helyreállítani az alkalmazást az előző állapotba a számítógép újraindítása vagy a szolgáltató összeomlása esetén. Hívja meg a WidgetManager.GetDefault parancsot az alkalmazás alapértelmezett widget-kezelő példányának lekéréséhez. Ezután hívja meg a GetWidgetInfos parancsot, amely WidgetInfo-objektumok tömbét adja vissza. Másolja át a widget ID-ket, neveket és egyéni állapotokat a segítő struktúrába CompactWidgetInfo, és mentse el a RunningWidgets tagváltozóba. Illessze be a következő kódot a WidgetProvider osztály osztálydefiníciójába.

// 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;
        }
    }
}

Implementáljon egy osztály-előállítót, amely kérésre példányosítani fogja a WidgetProvidert

Ahhoz, hogy a widget-gazdagép kommunikálhasson a widget-szolgáltatóval, meg kell hívnunk a CoRegisterClassObject parancsot. Ehhez a függvényhez létre kell hoznunk az IClassFactory implementációját, amely létrehoz egy osztályobjektumot a WidgetProvider osztályhoz. Az osztálygyárat egy önálló segédosztályban fogjuk megvalósítani.

A Visual Studio-ban kattintson a jobb gombbal a ExampleWidgetProvider projektre a Megoldáskezelőben, és válassza a Hozzáadás ->Osztálylehetőséget. Az Osztály hozzáadása párbeszédpanelen nevezze el az osztályt "FactoryHelper"-nek, majd kattintson a Hozzáadásgombra.

Cserélje le a FactoryHelper.cs fájl tartalmát a következő kódra. Ez a kód határozza meg az IClassFactory felületet, és implementálja a két metódust, a CreateInstance-t és a LockServert. Ez a kód tipikus sablon egy osztály-előállító implementálásához, és nem jellemző a widget-szolgáltató működésére, csak azt jelzi, hogy a létrehozott osztályobjektum implementálja az IWidgetProvider interfészt.

// 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;

    }
}

A widget szolgáltató CLSID azonosítóját képviselő GUID létrehozása

Ezután létre kell hoznia egy GUID-t, amely a CLSID és képvisel, és amely a widgetszolgáltató azonosítására szolgál a COM aktiválásához. Ugyanezt az értéket fogja használni az alkalmazás csomagolásakor is. Visual Studióban generáljon GUID-azonosítót úgy, hogy lép a Eszközök ->GUID létrehozásamenüpontra. Válassza a beállításjegyzék formátumbeállítását, és kattintson a Másolás gombra, majd illessze be azt egy szövegfájlba, hogy később másolhassa.

A widget-szolgáltató osztály objektumának regisztrálása az OLE-vel

A végrehajtható példány Program.cs fájljában meghívjuk a CoRegisterClassObjectet , hogy regisztrálja a widget-szolgáltatót az OLE-ben, hogy a widget-gazdagép kommunikáljon vele. Cserélje le a Program.cs tartalmát a következő kódra. Ez a kód importálja a CoRegisterClassObject függvényt , és meghívja azt az előző lépésben definiált WidgetProviderFactory felületen. Mindenképpen frissítse a CLSID_Factory változódeklarációt az előző lépésben létrehozott GUID használatára.

// 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);
}

Vegye figyelembe, hogy ez a példakód importálja a GetConsoleWindow függvényt annak megállapításához, hogy az alkalmazás konzolalkalmazásként fut-e, az útmutató alapértelmezett viselkedését. Ha a függvény érvényes mutatót ad vissza, hibakeresési információkat írunk a konzolra. Ellenkező esetben az alkalmazás Windows-alkalmazásként fut. Ebben az esetben megvárjuk a DeleteWidget metódusban beállított eseményt, amikor az engedélyezett widgetek listája üres, és kilépünk az alkalmazásból. A példakonzolalkalmazás Windows-alkalmazássá alakításával kapcsolatos információkért lásd : Konzolalkalmazás átalakítása Windows-alkalmazássá.

Csomagolja a widget-szolgáltató alkalmazást

Az aktuális kiadásban csak a csomagolt alkalmazások regisztrálhatók widget-szolgáltatókként. Az alábbi lépések végigvezetik az alkalmazás csomagolásának és az alkalmazásjegyzék frissítésének folyamatán, hogy regisztrálja az alkalmazást az operációs rendszerben widget-szolgáltatóként.

MSIX csomagolási projekt létrehozása

A Megoldáskezelőben kattintson a jobb gombbal a megoldásra, és válassza az Add-New> Project(Új projekt hozzáadása) lehetőséget. Az Új projekt hozzáadása párbeszédpanelen válassza a "Windows Alkalmazáscsomagoló projekt" sablont, és kattintson a Tovább gombra. Állítsa a projekt nevét "ExampleWidgetProviderPackage" értékre, majd kattintson a létrehozása gombra. Amikor a rendszer kéri, állítsa a célverziót az 1809-es vagy újabb verzióra, és kattintson az OK gombra. Ezután kattintson a jobb egérgombbal az ExampleWidgetProviderPackage projektre, és válassza a Hozzáadás>Projekthivatkozáslehetőséget. Válassza ki a ExampleWidgetProvider projektet, és kattintson az OK gombra.

Windows App SDK-csomaghivatkozás hozzáadása a csomagolási projekthez

Az MSIX csomagolási projekthez hozzá kell adnia egy hivatkozást a Windows App SDK nuget-csomaghoz. A Megoldáskezelőablakban kattintson duplán az ExampleWidgetProviderPackage projektre az ExampleWidgetProviderPackage.wapproj fájl megnyitásához. Adja hozzá a következő xml-t a Project elemhez.

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

Megjegyzés:

Győződjön meg arról, hogy a PackageReference elemben megadott verzió megegyezik az előző lépésben hivatkozott legújabb stabil verzióval.

Ha a Windows App SDK megfelelő verziója már telepítve van a számítógépen, és nem szeretné csomagolni az SDK-futtatókörnyezetet a csomagban, a csomagfüggőséget a ExampleWidgetProviderPackage projekt Package.appxmanifest fájljában adhatja meg.

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

A csomagjegyzék frissítése

A Megoldáskezelőben kattintson a jobb gombbal a fájlra, Package.appxmanifest és válassza a Kód megtekintése lehetőséget a jegyzék xml-fájljának megnyitásához. Ezután hozzá kell adnia néhány névtér-deklarációt a használni kívánt alkalmazáscsomag-bővítményekhez. Adja hozzá a következő névtérdefiníciókat a legfelső szintű csomagelemhez .

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

Az Alkalmazáselemen belül hozzon létre egy új üres, Bővítmények nevű elemet. Győződjön meg arról, hogy ez a uap:VisualElementszáró címkéje után jelenik meg.

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

    </Extensions>
</Application>

Az első bővítmény, amelyet hozzá kell adnunk, a ComServer bővítmény. Ez regisztrálja a végrehajtható fájl belépési pontját az operációs rendszeren. Ez a bővítmény a COM-kiszolgáló regisztrációs kulcs beállításával történő regisztrálásával egyenértékű csomagolt alkalmazás, és nem a widget-szolgáltatókra vonatkozik. Adja hozzá a következő com:Extension elemet a Bővítmények elem gyermekelemeként. Módosítsa a Id attribútum GUID-ját a com:Class elemben arra a GUID-ra, amelyet az előző lépésben generált.

<!-- 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>

Ezután adja hozzá az alkalmazást widget-szolgáltatóként regisztráló bővítményt. Illessze be a uap3:Extension elemet a következő kódrészletbe, a Bővítmények elem gyermekeként. Mindenképpen cserélje le a COM-elemClassId attribútumát az előző lépésekben használt GUID azonosítóra.

<!-- 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>

Az összes elem részletes leírását és formátuminformációit lásd itt: Widget provider package manifest XML format.

Ikonok és egyéb képek hozzáadása a csomagolási projekthez

A Megoldáskezelőbenkattintson a jobb gombbal az ExampleWidgetProviderPackage elemre, majd válassza a Hozzáadás –>Új mappaparancsot. Nevezze el ezt a mappát ProviderAssets néven, mivel ez volt az Package.appxmanifest előző lépésben használt mappa. Itt fogjuk tárolni a widgetek ikonjait és képernyőképeit . Miután hozzáadta a kívánt ikonokat és képernyőképeket, győződjön meg arról, hogy a képnevek megegyeznek a Path=ProviderAssets\ után található névvel a Package.appxmanifest-ben, különben a widgetek nem fognak megjelenni a widgetgazdagépen.

A képernyőképképek tervezési követelményeivel és a honosított képernyőképek elnevezési konvencióival kapcsolatos információkért lásd: Integrálás a vezérlőválasztóval.

A widget-szolgáltató tesztelése

Győződjön meg arról, hogy kiválasztotta a fejlesztői gépnek megfelelő architektúrát a Megoldásplatformok legördülő listából, például "x64". A Megoldáskezelőben kattintson a jobb gombbal a megoldásra, és válassza a Megoldás létrehozása lehetőséget. Ha ez megtörtént, kattintson jobb gombbal az ExampleWidgetProviderPackage elemre, és válassza a Üzembe helyezéslehetőséget. Az aktuális kiadásban az egyetlen támogatott widget-gazdagép a Widgets Board. A widgetek megtekintéséhez meg kell nyitnia a widgetek tábláját, és a jobb felső sarokban válassza a Widgetek hozzáadása lehetőséget. Görgessen az elérhető widgetek aljára, és látnia kell az oktatóanyagban létrehozott, a példaként szolgáló Weather Widget és Microsoft Counting Widget widgeteket. A widgetekre kattintva rögzítheti őket a widgetek tábláján, és tesztelheti a funkciójukat.

A widget-szolgáltató hibakeresése

Miután rögzítette a widgeteket, a widgetplatform elindítja a widget-szolgáltató alkalmazást, hogy releváns információkat kapjon és küldjön a widgetről. A futó widget hibakereséséhez csatolhat egy hibakeresőt a futó widget-szolgáltató alkalmazáshoz, vagy beállíthatja, hogy a Visual Studio automatikusan elindítsa a widget-szolgáltatói folyamat hibakeresését az indítás után.

A futó folyamathoz való csatoláshoz:

  1. A Visual Studióban kattintson a(z) Hibakeresés -> Csatlakozásfolyamathoz.
  2. Szűrje a folyamatokat, és keresse meg a kívánt widgetszolgáltatói alkalmazást.
  3. Csatold a hibakeresőt.

Annak érdekében, hogy a hibakereső automatikusan csatolva legyen a folyamathoz az első indításkor:

  1. A Visual Studióban kattintson a Hibakeresés –> Egyéb hibakeresési célok –> Telepített alkalmazáscsomag hibakeresése elemre.
  2. Szűrje a csomagokat, és keresse meg a kívánt widget-szolgáltatói csomagot.
  3. Válassza ki, és jelölje be a jelölőnégyzetet, amelynek szövege: "Ne induljon el, de végezzen hibakeresést, amikor a kód elindul".
  4. Kattintson az ésCsatolás gombra.

A konzolalkalmazás átalakítása Windows-alkalmazássá

Az útmutatóban létrehozott konzolalkalmazás Windows-alkalmazássá alakításához kattintson a jobb gombbal a ExampleWidgetProvider projektre a Megoldáskezelőben , és válassza a Tulajdonságok lehetőséget. Az Application-General> területen módosítsa a kimenet típusát a "Konzolalkalmazás" típusról a "Windows-alkalmazás" értékre.

Képernyőkép a C# widgetszolgáltató projekttulajdonságáról a Windows-alkalmazásra beállított kimeneti típussal

A widget közzététele

Miután kifejlesztette és tesztelte a widgetet, közzéteheti az alkalmazást a Microsoft Store-ban, hogy a felhasználók telepíthessék a widgeteket az eszközeikre. Az alkalmazások közzétételével kapcsolatos részletes útmutatásért lásd : Alkalmazás közzététele a Microsoft Store-ban.

A widgetek áruházgyűjteménye

Miután az alkalmazást közzétette a Microsoft Store-ban, kérheti, hogy az alkalmazás szerepeljen a widgetek Áruház gyűjteményében, amely segít a felhasználóknak felderíteni a Windows widgeteket tartalmazó alkalmazásokat. A kérés elküldéséhez lásd: a widget adatainak benyújtása a Store gyűjteményhez való hozzáadáshoz.

Képernyőkép a Microsoft Store-ról, amelyen a widgetek gyűjteménye látható, amely lehetővé teszi a felhasználók számára a Windows widgeteket tartalmazó alkalmazások felderítését.

Widget testreszabásának megvalósítása

A Windows App SDK 1.4-től kezdve a widgetek támogatják a felhasználók testreszabását. A funkció megvalósításakor a rendszer hozzáad egy testreszabási widget-beállítást a vezérlő rögzítésének feloldása lehetőség feletti három pont menühöz.

Képernyőkép egy widgetről, amelyen megjelenik a testreszabási párbeszédpanel.

Az alábbi lépések összefoglalják a widget testreszabásának folyamatát.

  1. Szokásos működés során a widget-szolgáltató válaszol a widget-gazdagéptől érkező kérésekre a sablonnal és az adatokkal a normál widget-élmény érdekében.
  2. A felhasználó az ellipszis menüben a Widget testreszabása gombra kattint.
  3. A widget az OnCustomizationRequested eseményt a widget-szolgáltatón jelzi, hogy a felhasználó kérte a widget testreszabási felületét.
  4. A widget-szolgáltató beállít egy belső jelzőt, amely jelzi, hogy a widget testreszabási módban van. Testreszabási módban a widget-szolgáltató a szokásos widget-felhasználói felület helyett elküldi a widget testreszabási felhasználói felületéhez tartozó JSON-sablonokat.
  5. Testreszabási módban a widget-szolgáltató onActionInvoked eseményeket fogad, miközben a felhasználó interakcióba lép a testreszabási felhasználói felülettel, és a felhasználó műveletei alapján módosítja annak belső konfigurációját és viselkedését.
  6. Ha az OnActionInvoked eseményhez társított művelet az alkalmazás által definiált "kilépés testreszabása" művelet, a widget-szolgáltató visszaállítja a belső jelzőt, hogy jelezze, hogy már nincs testreszabási módban, és folytatja a vizualizációs és adat JSON-sablonok küldését a szokásos widget-élmény érdekében, a testreszabás során kért módosításoknak megfelelően. A felhasználó bezárhatja a testreszabási felületet anélkül, hogy az alkalmazás által meghatározott kilépési testreszabási műveletre kattintanak. Ebben az esetben aktiválódik az IWidgetProviderAnalytics.OnAnalyticsInfoReported, és a WidgetAnalyticsInfoReportedArgs.AnalyticsJson "exitCustomization" típusú interakcióval rendelkezik.
  7. A widget-szolgáltató megőrzi a lemez vagy a felhő testreszabási beállításait, hogy a módosítások megmaradjanak a widget-szolgáltató meghívásai között.

Megjegyzés:

A Windows Widget Board ismert hibája a Windows App SDK-val létrehozott vezérlők esetében, amely miatt a három pont menü nem válaszol a testreszabási kártya megjelenítése után.

A widgetek tipikus testreszabási forgatókönyveiben a felhasználó kiválaszthatja, hogy milyen adatok jelenjenek meg a widgeten, vagy módosíthatja a widget vizuális megjelenítését. Az egyszerűség kedvéért az ebben a szakaszban szereplő példa olyan testreszabási viselkedést ad hozzá, amely lehetővé teszi, hogy a felhasználó visszaállítsa az előző lépésekben implementált számláló widget számlálóját.

Megjegyzés:

A widget testreszabása csak a Windows App SDK 1.4-ben és újabb verzióiban támogatott. Győződjön meg arról, hogy a projekt hivatkozásait a Nuget-csomag legújabb verziójára frissíti.

A csomagjegyzék frissítése a testreszabási támogatás deklarálásához

Ha tudatni szeretné a widget gazdagépével, hogy a widget támogatja a testreszabást, adja hozzá az IsCustomizable attribútumot a widget Definíció eleméhez, és állítsa igaz értékre.

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

Nyomon követheti, ha egy widget testreszabási módban van

A cikkben szereplő példa a CompactWidgetInfo segédstruktúra segítségével követi nyomon az aktív widgetek aktuális állapotát. Adja hozzá az inCustomization mezőt, amely nyomon követi, hogy a widget-gazdagép mikor várja, hogy elküldjük a testreszabási JSON-sablont a szokásos widgetsablon helyett.

// 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 implementálása

A widget testreszabási funkciója az IWidgetProvider2 felületen keresztül érhető el. Frissítse a WidgetProvider osztálydefiníciót a felület implementálásához.

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

Adjon hozzá egy implementációt az IWidgetProvider2 felület OnCustomizationRequested visszahívásához. Ez a módszer ugyanazt a mintát használja, mint a többi használt visszahívás. Lekérjük a widget testreszabásához szükséges azonosítót a WidgetContextből , és megkeresjük a widgethez társított CompactWidgetInfo segédszerkezetet, és igaz értékre állítjuk az inCustomization mezőt.

// 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);
    }
}

Most deklaráljon egy sztringváltozót, amely meghatározza a widget testreszabási felhasználói felületéhez tartozó JSON-sablont. Ebben a példában az "Alaphelyzetbe állítás számláló" gomb és a "Kilépés a testreszabásból" gomb jelzi a szolgáltatónknak, hogy térjen vissza a szokásos widget-működéshez. Helyezze ezt a definíciót a többi sablondefiníció mellé.

// 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""
}";

Testreszabási sablon küldése az UpdateWidgetben

Ezután frissítjük az UpdateWidget segédmetódusunkat, amely elküldi az adatokat és a vizuális JSON-sablonokat a widget-gazdagépnek. A számláló widget frissítésekor a szokásos widgetsablont vagy a testreszabási sablont küldjük el az inCustomization mező értékétől függően. A rövidség kedvéért a testreszabás szempontjából nem releváns kód hiányzik ebben a kódrészletben.

// 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);
}

Válasz a testreszabási műveletekre

Amikor a felhasználók a testreszabási sablonban lévő bemenetekkel dolgoznak, ugyanazt az OnActionInvoked kezelőt hívja meg, mint amikor a felhasználó a szokásos vezérlőélményt használja. A testreszabás támogatása érdekében a testreszabási JSON-sablonban az "reset" és "exitCustomization" igéket keressük. Ha a művelet a "Számláló alaphelyzetbe állítása" gombra van állítva, a segédstruktúra customState mezőjében tárolt számlálót 0 értékre állítjuk vissza. Ha a művelet a "Kilépés a testreszabásból" gombra van állítva, az InCustomization mezőt hamisra állítjuk, hogy az UpdateWidget hívásakor a segédmetódus a szokásos JSON-sablonokat küldje el, és ne a testreszabási sablont.

// 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);
        }
    }
}

Most, amikor üzembe helyezi a widgetet, látnia kell a Widget testreszabása gombot a három pont menüben. A testreszabás gombra kattintva megjelenik a testreszabási sablon.

Képernyőkép a widgetek testreszabási felhasználói felületével.

A Számláló alaphelyzetbe állítása gombra kattintva állítsa vissza a számlálót 0-ra. Kattintson a Kilépés a testreszabásból gombra a widget szokásos viselkedéséhez való visszatéréshez.