Jegyzet
Az oldalhoz való hozzáférés engedélyezést igényel. Próbálhatod be jelentkezni vagy könyvtárat váltani.
Az oldalhoz való hozzáférés engedélyezést igényel. Megpróbálhatod a könyvtár váltását.
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.
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:
- A Visual Studióban kattintson a(z) Hibakeresés -> Csatlakozásfolyamathoz.
- Szűrje a folyamatokat, és keresse meg a kívánt widgetszolgáltatói alkalmazást.
- Csatold a hibakeresőt.
Annak érdekében, hogy a hibakereső automatikusan csatolva legyen a folyamathoz az első indításkor:
- A Visual Studióban kattintson a Hibakeresés –> Egyéb hibakeresési célok –> Telepített alkalmazáscsomag hibakeresése elemre.
- Szűrje a csomagokat, és keresse meg a kívánt widget-szolgáltatói csomagot.
- 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".
- 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.
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.
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.
Az alábbi lépések összefoglalják a widget testreszabásának folyamatát.
- 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.
- A felhasználó az ellipszis menüben a Widget testreszabása gombra kattint.
- 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.
- 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.
- 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.
- 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.
- 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.
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.
Windows developer