Teilen über


Implementieren eines Widgetanbieters in einer C#-Windows-App

Dieser Artikel führt Sie durch die Erstellung eines einfachen Widgetanbieters, der die Schnittstelle IWidgetProvider implementiert. Die Methoden dieser Schnittstelle werden vom Widgethost aufgerufen, um die Daten anzufordern, die ein Widget definieren, oder um den Widgetanbieter auf eine Benutzeraktion für ein Widget reagieren zu lassen. Widgetanbieter können ein einzelnes Widget oder mehrere Widgets unterstützen. In diesem Beispiel werden zwei verschiedene Widgets definiert. Ein Widget ist ein simuliertes Wetterwidget, das einige der vom Framework für adaptive Karten bereitgestellten Formatierungsoptionen veranschaulicht. Das zweite Widget veranschaulicht Benutzeraktionen und das Feature für den benutzerdefinierten Widgetzustand durch Verwalten eines Leistungsindikators, der sich immer dann erhöht, wenn der Benutzer auf eine Schaltfläche klickt, die im Widget angezeigt wird.

Screenshot eines einfachen Wetter-Widgets. Das Widget zeigt einige wetterbezogene Grafiken und Daten sowie einige Diagnosetexte an, die zeigen, dass die Vorlage für das mittlere Widget angezeigt wird.

Screenshot eines einfachen Zählwidgets. Das Widget zeigt eine Zeichenkette mit dem numerischen Wert, der erhöht wird, und eine Schaltfläche mit der Beschriftung „Inkrement“ sowie einen Diagnosetext, der zeigt, dass die Vorlage für das kleine Widget angezeigt wird.

Der Beispielcode in diesem Artikel basiert auf dem Beispiel für Windows App SDK-Widgets. Informationen zum Implementieren eines Widgetanbieters mithilfe von C++/WinRT finden Sie unter Implementieren eines Widgetanbieters in einer Win32-App (C++/WinRT).

Voraussetzungen

  • Auf Ihrem Gerät muss der Entwicklermodus aktiviert sein. Weitere Informationen finden Sie unter Aktivieren von Geräten für die Entwicklung.
  • Visual Studio 2022 oder höher, mit der Workload für die UWP-Entwicklung. Stellen Sie sicher, dass Sie die Komponente für C++ (v143) aus der optionalen Dropdownliste hinzufügen.

Erstellen einer neuen Konsolen-App in C#

Erstellen Sie in Visual Studio ein neues Projekt. Legen Sie im Dialogfeld Neues Projekt erstellen den Sprachfilter auf „C#“ und den Plattformfilter auf „Windows“ fest, und wählen Sie dann die Projektvorlage „Konsolen-App“ aus. Nennen Sie das neue Projekt „ExampleWidgetProvider“. Wenn Sie dazu aufgefordert werden, legen Sie die .NET-Zielversion auf 8.0 fest.

Wenn das Projekt geladen wird, klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektnamen, und wählen Sie dann Eigenschaften aus. Scrollen Sie auf der Seite Allgemein nach unten zu Zielbetriebssystem, und wählen Sie „Windows“ aus. Wählen Sie unter Zielbetriebssystemversion die Version 10.0.19041.0 oder höher aus.

Um Ihr Projekt zur Unterstützung von .NET 8.0 zu aktualisieren, klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf den Projektnamen, und wählen Sie Projektdatei bearbeiten aus. Fügen Sie innerhalb der PropertyGroup das folgende RuntimeIdentifiers-Element hinzu.

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

Beachten Sie, dass in dieser exemplarischen Vorgehensweise eine Konsolen-App verwendet wird, die das Konsolenfenster anzeigt, wenn das Widget aktiviert wird, um einfaches Debuggen zu ermöglichen. Wenn Sie bereit sind, Ihre Widgetanbieter-App zu veröffentlichen, können Sie die Konsolenanwendung mithilfe der Schritte unter Konvertieren Ihrer Konsolen-App in eine Windows-App in eine Windows-Anwendung konvertieren.

Hinzufügen von Verweisen auf das Windows App SDK

In diesem Beispiel wird das neueste stabile NuGet-Paket der Windows App SDK verwendet. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf Abhängigkeiten, und wählen Sie NuGet-Pakete verwalten... aus. Wählen Sie im NuGet-Paket-Manager die Registerkarte Durchsuchen aus, und suchen Sie nach „Microsoft.WindowsAppSDK“. Wählen Sie in der Dropdownliste Version die neueste stabile Version aus, und klicken Sie dann auf Installieren.

Hinzufügen einer WidgetProvider-Klasse zum Verarbeiten von Widgetvorgängen

Klicken Sie in Visual Studio im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt ExampleWidgetProvider, und wählen Sie Hinzufügen -> Klasse aus. Nennen Sie die Klasse im Dialogfeld Klasse hinzufügen „WidgetProvider“, und klicke dann auf Hinzufügen. Aktualisieren Sie die Klassendefinition in der generierten WidgetProvider.cs-Datei, um anzugeben, dass sie die IWidgetProvider-Schnittstelle implementiert.

// WidgetProvider.cs
internal class WidgetProvider : IWidgetProvider

Vorbereiten der Nachverfolgung aktivierter Widgets

Ein Widgetanbieter kann ein einzelnes Widget oder mehrere Widgets unterstützen. Wann immer der Widgethost einen Vorgang mit dem Widgetanbieter initiiert, übergibt er eine ID, um das dem Vorgang zugeordnete Widget zu identifizieren. Jedes Widget verfügt außerdem über einen zugeordneten Namen und einen Zustandswert, der zum Speichern benutzerdefinierter Daten verwendet werden kann. In diesem Beispiel wird eine einfache Hilfsstruktur zum Speichern von ID, Namen und Daten für jedes angeheftete Widget deklariert. Widgets können sich auch im aktiven Zustand befinden. Dies wird im Abschnitt Aktivieren und Deaktivieren weiter unten erläutert. Dieser Zustand wird für jedes Widget mit einem booleschen Wert nachverfolgt. Fügen Sie der WidgetProvider.cs-Datei innerhalb des ExampleWidgetProvider-Namespace, aber außerhalb der WidgetProvider-Klassendefinition die folgende Definition hinzu.

// WidgetProvider.cs

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

}

Fügen Sie in der WidgetProvider-Klassendefinition in „WidgetProvider.cs“ ein Member für die Zuordnung hinzu, das die Liste der aktivierten Widgets verwaltet, wobei die Widget-ID als Schlüssel für jeden Eintrag verwendet wird.

// WidgetProvider.cs

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

Deklarieren von JSON-Zeichenfolgen für Widgetvorlagen

In diesem Beispiel werden einige statische Zeichenfolgen deklariert, um die JSON-Vorlagen für jedes Widget zu definieren. Zur Vereinfachung werden diese Vorlagen in den Membervariablen der WidgetProvider-Klasse gespeichert. Wenn Sie einen allgemeinen Speicher für die Vorlagen benötigen, können sie als Teil des Anwendungspakets einbezogen werden: Zugreifen auf Paketdateien. Informationen zum Erstellen des JSON-Dokuments für Widgetvorlage finden Sie unter Erstellen einer Widgetvorlage mit dem Designer für adaptive Karten.

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

Implementieren der IWidgetProvider-Methoden

In den nächsten Abschnitten wird die Methoden der IWidgetProvider-Schnittstelle implementiert. Die in mehreren dieser Methodenimplementierungen aufgerufene Hilfsmethode UpdateWidget wird weiter unten in diesem Artikel gezeigt.

Hinweis

Objekte, die an die Rückrufmethoden der IWidgetProvider-Schnittstelle übergeben werden, sind nur innerhalb des Rückrufs gültig. Sie sollten keine Verweise auf diese Objekte speichern, da ihr Verhalten außerhalb des Kontexts des Rückrufs nicht definiert ist.

CreateWidget

Der Widgethost ruft CreateWidget auf, wenn der Benutzer eines der Widgets Ihrer App im Widgethost angeheftet hat. Zunächst ruft diese Methode die ID und den Namen des zugeordneten Widgets ab und fügt der Auflistung aktivierter Widgets eine neue Instanz der Hilfsstruktur CompactWidgetInfo hinzu. Als Nächstes werden die anfängliche Vorlage und die Daten für das Widget gesendet, das in der UpdateWidget-Hilfsmethode gekapselt ist.

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

Der Widgethost ruft DeleteWidget auf, wenn der Benutzer eines der angehefteten Widgets Ihrer App aus dem Widgethost löst. In diesem Fall wird das zugeordnete Widget aus der Liste der aktivierten Widgets entfernt, sodass keine weiteren Updates für dieses Widget gesendet werden.

// WidgetProvider.cs

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

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

In diesem Beispiel wird zusätzlich zum Entfernen des Widgets aus der Liste der aktivierten Widgets auch überprüft, ob die Liste jetzt leer ist. Ist dies der Fall, wird ein Ereignis festgelegt, das später verwendet wird, damit die App beendet werden kann, wenn keine aktivierten Widgets mehr vorhanden sind. Fügen Sie in Ihrer Klassendefinition die Deklaration von ManualResetEvent und eine öffentliche Accessorfunktion hinzu.

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

public static ManualResetEvent GetEmptyWidgetListEvent()
{
    return emptyWidgetListEvent;
}

OnActionInvoked

Der Widgethost ruft OnActionInvoked auf, wenn der Benutzer mit einer Aktion interagiert, die Sie in Ihrer Widgetvorlage definiert haben. Für das in diesem Beispiel verwendete Leistungsindikatorwidget wurde in der JSON-Vorlage für das Widget eine Aktion mit dem Verb-Wert „inc“ deklariert. Der Code des Widgetanbieters verwendet diesen Verb-Wert, um zu bestimmen, welche Aktion als Reaktion auf die Benutzerinteraktion ausgeführt werden soll.

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

Rufen Sie in der Methode OnActionInvoked den Verbwert ab, indem Sie die Eigenschaft Verb der an die Methode übergebenen WidgetActionInvokedArgs-Werte überprüfen. Wenn das Verb „inc“ ist, wissen wir, dass die Zahl im benutzerdefinierten Zustand für das Widget erhöht wird. Rufen Sie aus WidgetActionInvokedArgs das WidgetContext-Objekt und dann die WidgetId ab, um die ID für das Widget abzurufen, das aktualisiert wird. Suchen Sie in der Zuordnung aktivierter Widgets den Eintrag mit der angegebenen ID, und aktualisieren Sie dann den benutzerdefinierten Zustandswert, der zum Speichern der Anzahl von Inkrementen verwendet wird. Aktualisieren Sie schließlich den Widgetinhalt mit dem neuen Wert unter Verwendung der Hilfsfunktion UpdateWidget.

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

Informationen zur Action.Execute-Syntax für adaptive Karten finden Sie unter Action.Execute. Anleitungen zum Entwerfen von Interaktionen für Widgets finden Sie unter Entwurfsleitfaden für Widgetinteraktionen.

OnWidgetContextChanged

Im aktuellen Release wird OnWidgetContextChanged nur aufgerufen, wenn der Benutzer die Größe eines angehefteten Widgets ändert. Sie können je nach angeforderter Größe eine andere JSON-Vorlage bzw. andere JSON-Daten an den Widgethost zurückgeben. Sie können die JSON-Vorlage auch so entwerfen, dass alle verfügbaren Größen unterstützt werden, indem Sie das bedingte Rendering basierend auf dem Wert von host.widgetSize verwenden. Wenn Sie keine neue Vorlage und keine neuen Daten senden müssen, um die Größenänderung zu berücksichtigen, können Sie OnWidgetContextChanged für Telemetriezwecke verwenden.

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

Aktivieren und Deaktivieren

Die Activate-Methode wird aufgerufen, um den Widgetanbieter darüber zu informieren, dass der Widgethost derzeit aktualisierte Inhalte vom Anbieter erhalten möchte. Dies kann beispielsweise bedeuten, dass der Benutzer den Widgethost gerade aktiv anzeigt. Die Deactivate-Methode wird aufgerufen, um den Widgetanbieter darüber zu informieren, dass der Widgethost keine Inhaltsupdates mehr anfordert. Diese beiden Methoden definieren ein Fenster, bei dem das größte Interesse des Widgethosts darin besteht, den aktuellsten Inhalt anzuzeigen. Widgetanbieter können jederzeit Updates an das Widget senden, z. B. als Reaktion auf eine Pushbenachrichtigung. Wie bei jeder Hintergrundaufgabe ist es jedoch wichtig, die Bereitstellung aktueller Inhalte gegen Ressourcenbedenken wie Akkulaufzeit abzuwägen.

Aktivieren und Deaktivieren werden pro Widget aufgerufen. In diesem Beispiel wird der aktive Status jedes Widgets in der CompactWidgetInfo-Hilfsstruktur nachverfolgt. In der Activate-Methode wird die UpdateWidget-Hilfsmethode aufgerufen, um das Widget zu aktualisieren. Beachten Sie, dass das Zeitfenster zwischen Aktivieren und Deaktivieren klein sein kann. Daher wird empfohlen, den Codepfad für die Widgetaktualisierung so schnell wie möglich festzulegen.

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

Aktualisieren eines Widgets

Definieren Sie die UpdateWidget-Hilfsmethode zum Aktualisieren eines aktivierten Widgets. In diesem Beispiel wird der Name des Widgets in der an die Methode übergebenen CompactWidgetInfo-Hilfsstruktur überprüft und dann die entsprechende Vorlage und der JSON-Datencode basierend auf dem aktualisierten Widget festgelegt. Ein WidgetUpdateRequestOptions-Objekt wird mit der Vorlage, den Daten und dem benutzerdefinierten Zustand für das zu aktualisierende Widget initialisiert. Rufen Sie WidgetManager::GetDefault auf, um eine Instanz der WidgetManager-Klasse abzurufen, und rufen Sie dann UpdateWidget auf, um die aktualisierten Widgetdaten an den Widgethost zu senden.

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

Initialisieren der Liste der aktivierten Widgets beim Start

Wenn der Widgetanbieter zum ersten Mal initialisiert wird, empfiehlt es sich, WidgetManager zu fragen, ob aktive Widgets vorhanden sind, die aktuell vom Anbieter bedient werden. Dies hilft dabei, die App im Falle eines Neustarts des Computers oder eines Absturzes des Anbieters wieder in den vorherigen Zustand zu versetzen. Rufen Sie WidgetManager.GetDefault auf, um die Widget-Manager-Standardinstanz für die App abzurufen. Rufen Sie dann GetWidgetInfos auf, wodurch ein Array von WidgetInfo-Objekten zurückgegeben wird. Kopieren Sie die Widget-IDs, die Namen und den benutzerdefinierten Zustand in die Hilfsstruktur CompactWidgetInfo, und speichern Sie sie in der Membervariablen RunningWidgets. Fügen Sie den folgenden Code in die Klassendefinition für die WidgetProvider-Klasse ein.

// 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 = widgetName, widgetName = widgetId };
            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;
        }
    }
}

Implementieren einer Klassenfactory, die WidgetProvider bei Bedarf instanziiert

Damit der Widgethost mit dem Widgetanbieter kommunizieren kann, muss CoRegisterClassObject aufgerufen werden. Diese Funktion erfordert die Erstellung einer Implementierung der IClassFactory, die wiederum ein Klassenobjekt für die WidgetProvider-Klasse erstellt. Die Klassenfactory wird in einer eigenständigen Hilfsklasse implementiert.

Klicken Sie in Visual Studio im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt ExampleWidgetProvider, und wählen Sie Hinzufügen -> Klasse aus. Nennen Sie die Klasse im Dialogfeld Klasse hinzufügen „FactoryHelper“, und klicken Sie dann auf Hinzufügen.

Ersetzen Sie den Inhalt der Datei „FactoryHelper.cs“ mit folgendem Code. Dieser Code definiert die IClassFactory-Schnittstelle und implementiert die beiden Methoden CreateInstance und LockServer. Dieser Code ist ein typischer Baustein für die Implementierung einer Klassenfactory und nicht spezifisch für die Funktionalität eines Widgetanbieters. Es wird lediglich angegeben, dass das zu erstellende Klassenobjekt die IWidgetProvider-Schnittstelle implementiert.

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

    }
}

Erstellen einer GUID, die die CLSID für Ihren Widgetanbieter darstellt

Als Nächstes müssen Sie eine GUID erstellen, die die CLSID darstellt, die verwendet wird, um Ihren Widgetanbieter für die COM-Aktivierung zu identifizieren. Der gleiche Wert wird auch beim Packen Ihrer App verwendet. Generieren Sie eine GUID in Visual Studio, indem Sie zu Tools ->GUID erstellen wechseln. Wählen Sie die Registrierungsformatoption aus, klicken Sie auf Kopieren, und fügen Sie sie dann in eine Textdatei ein, damit Sie sie später kopieren können.

Registrieren des Widgetanbieter-Klassenobjekts bei OLE

In der Datei „Program.cs“ für die ausführbare Datei wird CoRegisterClassObject aufgerufen, um den Widgetanbieter bei OLE zu registrieren, damit der Widgethost damit interagieren kann. Ersetzen Sie den Inhalt von "Program.cs" durch den folgenden Code. Dieser Code importiert die Funktion CoRegisterClassObject und ruft sie auf, wobei die in einem vorherigen Schritt definierte WidgetProviderFactory-Schnittstelle übergeben wird. Aktualisieren Sie die CLSID_Factory-Variablendeklaration unbedingt so, dass die im vorherigen Schritt generierte GUID verwendet wird.

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

Beachten Sie, dass in diesem Codebeispiel die Funktion GetConsoleWindow importiert wird, um zu bestimmen, ob die App als Konsolenanwendung ausgeführt wird. Dies ist das Standardverhalten für diese exemplarische Vorgehensweise. Wenn die Funktion einen gültigen Zeiger zurückgibt, werden Debuginformationen in die Konsole geschrieben. Andernfalls wird die App als Windows-App ausgeführt. In diesem Fall wird auf das in der DeleteWidget-Methode festgelegte Ereignis gewartet, wenn die Liste der aktivierten Widgets leer ist und die App beendet wird. Informationen zum Konvertieren der Beispielkonsolen-App in eine Windows-App finden Sie unter Konvertieren Ihrer Konsolen-App in eine Windows-App.

Packen Ihrer Widgetanbieter-App

Im aktuellen Release können nur gepackte Apps als Widgetanbieter registriert werden. Die folgenden Schritte führen Sie durch den Vorgang zum Packen Ihrer App und zum Aktualisieren des App-Manifests, um Ihre App beim Betriebssystem als Widgetanbieter zu registrieren.

Erstellen eines MSIX-Paketerstellungsprojekts

Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Ihre Projektmappe, und wählen Sie Hinzufügen -> Neues Projekt... aus. Wählen Sie im Dialogfeld Neues Projekt hinzufügen die Vorlage „Paketerstellungsprojekt für Windows-Anwendungen“ aus, und klicken Sie auf Weiter. Legen Sie den Projektnamen auf „ExampleWidgetProviderPackage“ fest, und klicken Sie auf Erstellen. Wenn Sie dazu aufgefordert werden, legen Sie die Zielversion auf Version 1809 oder höher fest, und klicken Sie auf OK. Klicken Sie als Nächstes mit der rechten Maustaste auf das Projekt „ExampleWidgetProviderPackage“, und wählen Sie Hinzufügen -> Projektverweis aus. Wählen Sie das Projekt ExampleWidgetProvider aus, und klicken Sie auf „OK“.

Hinzufügen eines Windows App SDK-Paketverweises zum Paketprojekt

Sie müssen dem MSIX-Paketprojekt einen Verweis auf das NuGet-Paket des Windows App SDK hinzufügen. Doppelklicken Sie im Projektmappen-Explorer auf das Projekt „ExampleWidgetProviderPackage“, um die Datei „ExampleWidgetProviderPackage.wapproj“ zu öffnen. Fügen Sie im Project-Element den folgenden XML-Code hinzu.

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

Hinweis

Stellen Sie sicher, dass die im PackageReference-Element angegebene Version mit der neuesten stabilen Version übereinstimmt, auf die Sie im vorherigen Schritt verwiesen haben.

Wenn die richtige Version des Windows App SDK bereits auf dem Computer installiert ist und Sie die SDK-Runtime nicht in Ihrem Paket bündeln möchten, können Sie die Paketabhängigkeit in der Datei „Package.appxmanifest“ für das Projekt „ExampleWidgetProviderPackage“ angeben.

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

Aktualisieren des Paketmanifests

Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf die Datei Package.appxmanifest, und wählen Sie Code anzeigen aus, um die XML-Datei des Manifests zu öffnen. Als Nächstes müssen Sie einige Namespacedeklarationen für die verwendeten App-Paketerweiterungen hinzufügen. Fügen Sie dem Package-Element der obersten Ebene die folgenden Namespacedefinitionen hinzu.

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

Erstellen Sie im Application-Element ein neues leeres Element namens Extensions. Stellen Sie sicher, dass Sie dieses Element nach dem schließenden Tag für uap:VisualElements angeben.

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

    </Extensions>
</Application>

Die erste Erweiterung, die hinzugefügt werden muss, ist die ComServer-Erweiterung. Dadurch wird der Einstiegspunkt der ausführbaren Datei beim Betriebssystem registriert. Diese Erweiterung ist das Paket-App-Äquivalent zur Registrierung eines COM-Servers durch Festlegen eines Registrierungsschlüssels und nicht spezifisch für Widget-Anbieter. Fügen Sie das folgende com:Extension-Element als untergeordnetes Element des Elements Extensions hinzu. Ändern Sie die GUID im Id-Attribut des com:Class-Elements in die GUID, die Sie in einem vorherigen Schritt generiert haben.

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

Fügen Sie als Nächstes die Erweiterung hinzu, die die App als Widgetanbieter registriert. Fügen Sie das uap3:Extension-Element als untergeordnetes Element des Extensions-Elements in den folgenden Codeausschnitt ein. Ersetzen Sie das ClassId-Attribut des COM-Elements durch die GUID, die Sie in den vorherigen Schritten verwendet haben.

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

Ausführliche Beschreibungen und Formatinformationen für all diese Elemente finden Sie unter XML-Format des Widgetanbieter-Paketmanifests.

Hinzufügen von Symbolen und anderen Bildern zu Ihrem Paketerstellungsprojekt

Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Ihr ExampleWidgetProviderPackage, und wählen Sie Hinzufügen -> Neuer Ordner aus. Nennen Sie diesen Ordner „ProviderAssets“, da dies das ist, was im Package.appxmanifest im vorherigen Schritt verwendet wurde. Hier werden Symbole und Screenshots für die Widgets gespeichert. Nachdem Sie die gewünschten Symbole und Screenshots hinzugefügt haben, stellen Sie sicher, dass die Bildnamen mit dem übereinstimmen, was nach Path=ProviderAssets\ in Ihrem Package.appxmanifest steht, oder die Widgets werden nicht im Widgethost angezeigt.

Informationen zu den Entwurfsanforderungen für Screenshots und den Benennungskonventionen für lokalisierte Screenshots finden Sie unter Integrieren in die Widgetauswahl.

Testen Ihres Widgetanbieters

Stellen Sie sicher, dass Sie in der Dropdownliste Projektmappenplattformen die Architektur ausgewählt haben, die Ihrem Entwicklungscomputer entspricht, z. B. „x64“. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf die Projektmappe, und wählen Sie Projektmappe erstellen aus. Klicken Sie anschließend mit der rechten Maustaste auf Ihr ExampleWidgetProviderPackage, und wählen Sie Bereitstellen aus. Im aktuellen Release ist der einzige unterstützte Widgethost das Widgets Board. Um die Widgets anzuzeigen, müssen Sie das Widgets Board öffnen und oben rechts Widgets hinzufügen auswählen. Scrollen Sie in den verfügbaren Widgets nach unten. Sie sollten das simulierte Wetterwidget und das Microsoft-Zählwidget sehen, die in diesem Tutorial erstellt wurden. Klicken Sie auf die Widgets, um sie an Ihr Widgets Board anzuheften und ihre Funktionalität zu testen.

Debuggen Ihres Widgetanbieters

Nachdem Sie Ihre Widgets angeheftet haben, startet die Widgetplattform Ihre Widgetanbieteranwendung, um relevante Informationen über das Widget zu empfangen und zu senden. Zum Debuggen des ausgeführten Widgets können Sie entweder einen Debugger an die ausgeführte Widgetanbieteranwendung anfügen oder Visual Studio so einrichten, dass das Debuggen des Widgetanbieterprozesses nach dem Start automatisch gestartet wird.

Zum Anfügen an den ausgeführten Prozess:

  1. Klicken Sie in Visual Studio auf Debuggen -> An den Prozess anhängen.
  2. Filtern Sie die Prozesse, und suchen Sie ihre gewünschte Widgetanbieteranwendung.
  3. Fügen Sie den Debugger an.

Zum Anfügen des Debuggers an den Prozess beim erstmaligen Start:

  1. Klicken Sie in Visual Studio auf Debuggen -> Andere Debugziele -> Installiertes App-Paket debuggen aus.
  2. Filtern Sie die Pakete, und suchen Sie ihr gewünschtes Widgetanbieterpaket.
  3. Wählen Sie es aus, und aktivieren Sie das Kontrollkästchen „Eigenen Code zunächst nicht starten, sondern debuggen“.
  4. Klicken Sie auf Anfügenaus.

Konvertieren Sie Ihre Konsolen-App in eine Windows-App

Um die in dieser exemplarischen Vorgehensweise erstellte Konsolen-App in eine Windows-App zu konvertieren, klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt ExampleWidgetProvider, und wählen Sie Eigenschaften aus. Ändern Sie unter „Anwendung -> Allgemein“ den Ausgabetyp von „Konsolenanwendung“ in „Windows-Anwendung“.

Screenshot der Eigenschaften des C#-Widgetanbieterprojekts, wobei der Ausgabetyp auf „Windows-Anwendung“ festgelegt ist

Veröffentlichen Ihres Widgets

Nachdem Sie Ihr Widget entwickelt und getestet haben, können Sie Ihre App im Microsoft Store veröffentlichen, damit Benutzer Ihre Widgets auf ihren Geräten installieren können. Eine schrittweise Anleitung zum Veröffentlichen einer App finden Sie unter Veröffentlichen Ihrer App im Microsoft Store.

Die Widgetssammlung im Store

Nachdem Ihre App im Microsoft Store veröffentlicht wurde, können Sie anfordern, dass Ihre App in die Widgetssammlung im Store aufgenommen wird, die Benutzern hilft, Apps mit Windows-Widgets zu entdecken. Informationen zum Übermitteln Ihrer Anforderung finden Sie unter Übermitteln Ihrer Widgetinformationen, um Sie zur Store-Sammlung hinzuzufügen.

Screenshot des Microsoft Store mit der Widgetssammlung, die Benutzern eine Auswahl von Apps mit Windows-Widgets bereitstellt.

Implementieren der Widgetanpassung

Ab Windows App SDK 1.4 unterstützen Widgets die Benutzeranpassung. Wenn dieses Feature implementiert ist, wird dem Menü mit den Auslassungspunkten oberhalb der Option Widget loslösen eine Option Widget anpassen hinzugefügt.

Screenshot eines Widgets mit angezeigtem Anpassungsdialogfeld.

Die folgenden Schritte fassen den Prozess für die Widgetanpassung zusammen.

  1. Im normalen Betrieb antwortet der Widgetanbieter auf Anforderungen vom Widgethost mit den Vorlagen und Daten-Payloads für die normale Widgeterfahrung.
  2. Der Benutzer klickt im Menü mit den Auslassungspunkten auf die Schaltfläche Widget anpassen.
  3. Das Widget löst das OnCustomizationRequested-Ereignis beim Widgetanbieter aus, um anzuzeigen, dass der Benutzer die Widgetanpassung angefordert hat.
  4. Der Widgetanbieter legt ein internes Flag fest, um anzuzeigen, dass sich das Widget im Anpassungsmodus befindet. Im Anpassungsmodus sendet der Widgetanbieter die JSON-Vorlagen für die Widgetanpassungs-Benutzeroberfläche anstelle der normalen Widget-Benutzeroberfläche.
  5. Im Anpassungsmodus empfängt der Widgetanbieter OnActionInvoked-Ereignisse, wenn der Benutzer mit der Anpassungsbenutzeroberfläche interagiert, und passt seine interne Konfiguration und sein Verhalten auf der Grundlage der Aktionen des Benutzers an.
  6. Wenn die Aktion, die mit dem OnActionInvoked-Ereignis verknüpft ist, die von der App definierte Aktion „Anpassung beenden“ ist, setzt der Widgetanbieter sein internes Flag zurück, um anzuzeigen, dass er sich nicht mehr im Anpassungsmodus befindet, und nimmt das Senden der visuellen und Daten-JSON-Vorlagen für die normale Widgeterfahrung wieder auf, wobei die während der Anpassung angeforderten Änderungen berücksichtigt werden.
  7. Der Widgetanbieter behält die Anpassungsoptionen auf dem Datenträger oder in der Cloud bei, sodass die Änderungen zwischen Aufrufen des Widgetanbieters erhalten bleiben.

Hinweis

Es gibt einen bekannten Fehler im Windows Widget Board für Widgets, die mit dem Windows App SDK erstellt wurden, der dazu führt, dass das Menü mit den Auslassungspunkten nicht mehr reagiert, nachdem die Anpassungskarte angezeigt wurde.

In typischen Widget-Anpassungsszenarien wählt der Benutzer aus, welche Daten auf dem Widget angezeigt werden, oder er passt die visuelle Darstellung des Widgets an. Der Einfachheit halber wird im Beispiel in diesem Abschnitt ein Anpassungsverhalten hinzugefügt, das es dem Benutzer ermöglicht, den Zähler des in den vorherigen Schritten implementierten Zählwidgets zurückzusetzen.

Hinweis

Die Widgetanpassung wird nur in Windows App SDK 1.4 und höher unterstützt. Stellen Sie sicher, dass Sie die Verweise in Ihrem Projekt auf die neueste Version des Nuget-Pakets aktualisieren.

Aktualisieren des Paketmanifests zum Deklarieren der Anpassungsunterstützung

Um dem Widgethost mitzuteilen, dass das Widget die Anpassung unterstützt, fügen Sie das Attribut IsCustomizable zum Definitionselement für das Widget hinzu, und legen Sie es auf „true“ fest.

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

Nachverfolgen, wenn sich ein Widget im Anpassungsmodus befindet

Im Beispiel in diesem Artikel wird die Hilfsstruktur CompactWidgetInfo verwendet, um den aktuellen Status unserer aktiven Widgets nachzuverfolgen. Fügen Sie das Feld inCustomization hinzu, mit dem nachverfolgt wird, wann der Widgethost erwartet, dass wir unsere JSON-Anpassungsvorlage anstelle der normalen Widgetvorlage senden.

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

Implementieren von IWidgetProvider2

Das Widgetanpassungsfeature wird über die IWidgetProvider2-Schnittstelle verfügbar gemacht. Aktualisieren Sie die WidgetProvider-Klassendefinition, um diese Schnittstelle zu implementieren.

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

Fügen Sie eine Implementierung für den OnCustomizationRequested-Rückruf der IWidgetProvider2-Schnittstelle hinzu. Bei dieser Methode wird dasselbe Muster verwendet wie bei den anderen verwendeten Rückrufen. Die ID des anzupassenden Widgets rufen wir aus dem WidgetContext ab, anschließend suchen wir die mit dem Widget verknüpfte Hilfsstruktur CompactWidgetInfo und legen das Feld inCustomization auf true fest.

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

Deklarieren Sie jetzt eine Zeichenfolgenvariable, welche die JSON-Vorlage für die Widgetanpassungs-Benutzeroberfläche definiert. In diesem Beispiel gibt es eine Schaltfläche „Zähler zurücksetzen“ und eine Schaltfläche „Anpassung beenden“, die unserem Anbieter signalisiert, dass er zum normalen Widgetverhalten zurückkehren soll. Platzieren Sie diese Definition neben den anderen Vorlagendefinitionen.

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

Anpassungsvorlage in UpdateWidget senden

Als Nächstes aktualisieren wir unsere Hilfsmethode UpdateWidget, die unsere Daten- und visuellen JSON-Vorlagen an den Widgethost sendet. Beim Aktualisieren des Zählwidgets senden wir abhängig vom Wert des Felds InCustomization entweder die normale Widgetvorlage oder die Anpassungsvorlage. Aus Platzgründen wird Code, der nicht für die Anpassung relevant ist, in diesem Codeausschnitt weggelassen.

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

Reagieren auf Anpassungsaktionen

Wenn Benutzer mit Eingaben in unserer Anpassungsvorlage interagieren, ruft sie denselben OnActionInvoked-Handler auf, als wenn der Benutzer mit der normalen Widgeterfahrung interagieren würde. Zur Unterstützung der Anpassung suchen wir nach den Verben „reset“ und „exitCustomization“ aus unserer JSON-Anpassungsvorlage. Wenn die Aktion die Schaltfläche „Zähler zurücksetzen“ betrifft, setzen wir den Zähler im Feld customState unserer Hilfsstruktur auf 0 zurück. Wenn die Aktion die Schaltfläche „Anpassung beenden“ betrifft, legen wir das Feld inCustomization auf false fest, sodass beim Aufrufen von UpdateWidget unsere Hilfsmethode die normalen JSON-Vorlagen und nicht die Anpassungsvorlage sendet.

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

Wenn Sie nun Ihr Widget bereitstellen, sollte die Schaltfläche Widget anpassen im Menü mit den Auslassungspunkten angezeigt werden. Wenn Sie auf die Schaltfläche „Anpassen“ klicken, wird Ihre Anpassungsvorlage angezeigt.

Ein Screenshot, der die Benutzeroberfläche zur Widget-Anpassung zeigt.

Klicken Sie auf die Schaltfläche Zähler zurücksetzen, um den Zähler auf 0 zurückzusetzen. Klicken Sie auf die Schaltfläche Anpassung beenden, um zum normalen Verhalten Ihres Widgets zurückzukehren.