Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek vás provede vytvořením jednoduchého zprostředkovatele widgetu, který implementuje rozhraní IWidgetProvider. Metody tohoto rozhraní jsou vyvolány hostitelem widgetu, aby požádal o data, která definují widget, nebo aby poskytovatel widgetu reagoval na akci uživatele na widgetu. Poskytovatelé widgetů můžou podporovat jeden widget nebo více widgetů. V tomto příkladu definujeme dva různé widgety. Jedním widgetem je widget napodobení počasí, který znázorňuje některé možnosti formátování poskytované architekturou Adaptivní karty. Druhý widget předvede akce uživatele a vlastní funkci stavu widgetu tím, že zachová čítač, který se zvýší, kdykoli uživatel klikne na tlačítko zobrazené na widgetu.
Vzorový kód v tomto článku je přizpůsoben z ukázky widgetů sady Windows App SDK. Pokud chcete implementovat poskytovatele widgetu pomocí C++/WinRT, přečtěte si téma Implementace zprostředkovatele widgetu v aplikaci win32 (C++/WinRT).
Požadavky
- Vaše zařízení musí mít povolený vývojářský režim. Další informace najdete v tématu Nastavení pro vývojáře.
- Visual Studio 2022 nebo novější s vývojovou úlohou pro univerzální platformu Windows . Nezapomeňte přidat komponentu pro C++ (v143) z volitelného rozevíracího seznamu.
Vytvoření nové konzolové aplikace jazyka C#
V sadě Visual Studio vytvořte nový projekt. V dialogovém okně Vytvořit nový projekt nastavte filtr jazyka na C# a filtr platformy na Windows a pak vyberte šablonu projektu konzolové aplikace. Pojmenujte nový projekt ExampleWidgetProvider. Po zobrazení výzvy nastavte cílovou verzi .NET na 8.0.
Když se projekt načte, v Průzkumníku řešení pravým tlačítkem myši klikněte na název projektu a vyberte Vlastnosti. Na stránce Obecné přejděte dolů na Cílový OS a vyberte "Windows". V části Cílová verze operačního systému vyberte verzi 10.0.19041.0 nebo novější.
Pokud chcete projekt aktualizovat tak, aby podporoval .NET 8.0, klikněte v Průzkumníku řešení pravým tlačítkem myši na název projektu a vyberte Upravit soubor projektu. Uvnitř PropertyGroup přidejte následující element RuntimeIdentifiers.
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
Všimněte si, že tento průvodce používá konzolovou aplikaci, která při aktivaci widgetu otevře konzolové okno, aby umožnila snadné ladění. Až budete připraveni publikovat aplikaci zprostředkovatele widgetů, můžete konzolovou aplikaci převést na aplikaci pro Windows pomocí kroků v části Převod konzolové aplikace do aplikace pro Windows.
Přidání odkazů na sadu Windows App SDK
Tato ukázka používá nejnovější stabilní balíček NuGet sady Windows App SDK. Ve Průzkumníku řešeníklikněte pravým tlačítkem na Závislosti a vyberte Spravovat balíčky NuGet.... V nástroji pro správu balíčků NuGet vyberte kartu Procházet a vyhledejte "Microsoft.WindowsAppSDK". V rozevíracím seznamu Verze vyberte nejnovější stabilní verzi a klikněte na Nainstalovat.
Přidání třídy WidgetProvider pro zpracování operací widgetu
V sadě Visual Studio klikněte pravým tlačítkem na projekt ExampleWidgetProvider v Průzkumníku řešení a vyberte Přidat –>Třída. V dialogovém okně Přidat třídu pojmenujte třídu WidgetProvider a klikněte na Přidat. Ve vygenerovaném WidgetProvider.cs souboru aktualizujte definici třídy tak, aby indikovala, že implementuje IWidgetProvider rozhraní.
// WidgetProvider.cs
internal class WidgetProvider : IWidgetProvider
Příprava ke sledování povolených widgetů
Poskytovatel widgetů může podporovat jeden widget nebo více widgetů. Kdykoli hostitel widgetu zahájí operaci s poskytovatelem widgetu, předá ID k identifikaci widgetu přidruženého k operaci. Každý widget má také přidružený název a hodnotu stavu, kterou lze použít k ukládání vlastních dat. V tomto příkladu deklarujeme jednoduchou pomocnou strukturu pro uložení ID, názvu a dat pro každý připnutý widget. Widgety můžou být také v aktivním stavu, který je popsán v části Aktivovat a deaktivovat níže. Tento stav budeme sledovat pro každý widget s logickou hodnotou. Do souboru WidgetProvider.cs přidejte následující definici do oboru názvů ExampleWidgetProvider, ale mimo definici třídy WidgetProvider.
// WidgetProvider.cs
public class CompactWidgetInfo
{
public string? widgetId { get; set; }
public string? widgetName { get; set; }
public int customState = 0;
public bool isActive = false;
}
V definici třídy WidgetProvider v WidgetProvider.cs přidejte člena pro mapu, která bude udržovat seznam povolených widgetů pomocí ID widgetu jako klíč pro každou položku.
// WidgetProvider.cs
// Class member of WidgetProvider
public static Dictionary<string, CompactWidgetInfo> RunningWidgets = new Dictionary<string, CompactWidgetInfo>();
Deklarace řetězců JSON šablony widgetu
Tento příklad deklaruje některé statické řetězce, které definují šablony JSON pro každý widget. Pro usnadnění práce jsou tyto šablony uloženy v proměnných členů třídy WidgetProvider. Pokud potřebujete obecné úložiště pro šablony – dají se zahrnout jako součást balíčku aplikace: přístup k souborům balíčků. Informace o vytvoření dokumentu JSON šablony widgetu najdete v tématu Vytvoření šablony widgetu pomocí návrháře adaptivních karet.
V nejnovější verzi mohou aplikace, které implementují widgety pro Windows, přizpůsobit záhlaví jejich widgetů na panelu widgetů a přepsat tak výchozí prezentaci. Další informace naleznete v tématu Přizpůsobení oblasti záhlaví widgetu.
Poznámka:
V nejnovější verzi mohou aplikace, které implementují widgety Windows, zvolit naplnění obsahu widgetu kódem HTML získaným ze specifikované adresy URL místo poskytování obsahu ve formátu schématu adaptivní karty v datové části JSON předané z poskytovatele na panel widgetů. Poskytovatelé widgetů musí stále poskytovat datovou část JSON adaptivní karty, takže kroky implementace v tomto návodu platí pro webové widgety. Další informace naleznete v tématu poskytovatelé webových widgetů.
// 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"
}
""";
Implementace metod IWidgetProvider
V následujících několika částech budeme implementovat metody IWidgetProvider rozhraní. Pomocná metoda UpdateWidget, která je volána v několika z těchto implementací metod, se zobrazí dále v tomto článku.
Poznámka:
Objekty předané do metod zpětného volání rozhraní IWidgetProvider jsou zaručeně platné pouze v rámci samotného zpětného volání. Odkazy na tyto objekty byste neměli ukládat, protože jejich chování mimo kontext zpětného volání není definováno.
VytvořitWidget
Hostitel widgetu volá CreateWidget, když uživatel připnul některý z widgetů vaší aplikace do hostitele widgetu. Nejprve tato metoda získá ID a název přidružené widgetu a přidá novou instanci naší pomocné struktury, CompactWidgetInfo, do kolekce povolených widgetů. Dále odešleme počáteční šablonu a data widgetu, která je zapouzdřená v pomocné metodě UpdateWidget.
// 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);
}
Odstranit Widget
Hostitel widgetu volá DeleteWidget, když uživatel odepnul některý z widgetů vaší aplikace z widgetového hostitele. Když k tomu dojde, odebereme přidružený widget ze seznamu povolených widgetů, abychom pro tento widget neposílali žádné další aktualizace.
// WidgetProvider.cs
public void DeleteWidget(string widgetId, string customState)
{
RunningWidgets.Remove(widgetId);
if(RunningWidgets.Count == 0)
{
emptyWidgetListEvent.Set();
}
}
V tomto příkladu kromě odebrání widgetu se zadaným ze seznamu povolených widgetů také zkontrolujeme, jestli je seznam prázdný, a pokud ano, nastavíme událost, která se později použije k tomu, aby se aplikace ukončila, když nejsou povolené widgety. Do definice vaší třídy přidejte deklaraci ManualResetEvent a veřejnou přístupovou funkci.
// WidgetProvider.cs
static ManualResetEvent emptyWidgetListEvent = new ManualResetEvent(false);
public static ManualResetEvent GetEmptyWidgetListEvent()
{
return emptyWidgetListEvent;
}
OnActionInvolat
Hostitel widgetu volá OnActionInvolat, když uživatel pracuje s akcí, kterou jste definovali v šabloně widgetu. Pro widget čítače použitého v tomto příkladu byla akce deklarována se slovesem a hodnotou "inc" v JSON šabloně pro widget. Kód zprostředkovatele widgetu použije tuto hodnotu příkazu k určení akce, která se má provést v reakci na interakci uživatele.
...
"actions": [
{
"type": "Action.Execute",
"title": "Increment",
"verb": "inc"
}
],
...
V metodě OnActionInvoked získejte hodnotu slovesa kontrolou vlastnosti Verb objektu WidgetActionInvokedArgs předaného do metody. Pokud je sloveso "inc", víme, že zvýšíme počet v přizpůsobeném stavu widgetu. Z WidgetActionInvokedArgszískejte objekt WidgetContext a potom WidgetId získat ID pro widget, který se aktualizuje. Vyhledejte položku v mapě povolených widgetů se zadaným ID a pak aktualizujte hodnotu vlastního stavu, která se používá k uložení počtu přírůstků. Nakonec aktualizujte obsah widgetu novou hodnotou pomocí UpdateWidget pomocné funkce.
// 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);
}
}
}
Informace o syntaxi Action.Execute pro adaptivní karty najdete v tématu Action.Execute. Pro pokyny ohledně návrhu interakce widgetů si přečtěte Pokyny k návrhu interakce widgetu.
OnWidgetContextChanged
V aktuální verzi se OnWidgetContextChanged volá pouze v případě, že uživatel změní velikost připnutého widgetu. V závislosti na požadované velikosti můžete hostiteli widgetu vrátit jinou šablonu NEBO data JSON. Můžete také navrhnout JSON šablony tak, aby podporovala všechny dostupné velikosti pomocí podmíněného vykreslování na základě hodnoty host.widgetSize. Pokud pro změnu velikosti nepotřebujete odesílat novou šablonu nebo data, můžete pro účely telemetrie použít OnWidgetContextChanged.
// 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);
}
}
Aktivace a deaktivace
Volá se metoda Activate, která informuje poskytovatele widgetu, že hostitel widgetu má v současné době zájem o příjem aktualizovaného obsahu od poskytovatele. Může to například znamenat, že uživatel aktuálně aktivně zobrazuje hostitele widgetu. Metoda Deactivate je volána k upozornění poskytovatele widgetu, že hostitel widgetu již nevyžaduje aktualizace obsahu. Tyto dvě metody definují okno, ve kterém má hostitel widgetu největší zájem o zobrazení nejaktuálnějšího obsahu up-to. Poskytovatelé widgetů můžou kdykoliv odesílat aktualizace do widgetu, například v reakci na push oznámení, ale stejně jako u jakéhokoli úkolu na pozadí, je důležité vyvážit up-to–date obsah se zdroji, jako je životnost baterie.
Aktivovat a Deaktivovat jsou volány pro každý widget zvlášť. Tento příklad sleduje aktivní stav jednotlivých widgetů v CompactWidgetInfo pomocné struktury. V metodě Activate voláme metodu pomocníka UpdateWidget pro aktualizaci widgetu. Všimněte si, že časové období mezi Aktivovat a Deaktivovat může být malé, proto doporučujeme, abyste se pokusili co nejrychleji aktualizovat cestu kódu widgetu.
// 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;
}
}
Aktualizace widgetu
Definujte metodu pomocné rutiny UpdateWidget pro aktualizaci povoleného widgetu. V tomto příkladu zkontrolujeme název widgetu v CompactWidgetInfo pomocné struktury předané metodě a pak nastavíme odpovídající šablonu a data JSON na základě toho, který widget se aktualizuje. Možnost žádosti o aktualizaci widgetu je inicializována pomocí šablony, dat a vlastního stavu pro aktualizovaný widget. Zavolejte WidgetManager::GetDefault, abyste získali instanci třídy WidgetManager, a potom zavolejte UpdateWidget, abyste odeslali aktualizovaná data widgetu hostiteli widgetu.
// 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);
}
Inicializace seznamu povolených widgetů při spuštění
Když je náš poskytovatel widgetu poprvé inicializován, je vhodné se zeptat WidgetManager pokud existují nějaké spuštěné widgety, které náš poskytovatel aktuálně obsluhuje. Pomůže obnovit aplikaci do předchozího stavu v případě restartování počítače nebo chybového ukončení poskytovatele. Chcete-li získat výchozí instanci správce widgetů pro aplikaci, volejte WidgetManager.GetDefault. Potom zavolejte GetWidgetInfos, které vrátí pole objektů WidgetInfo. Zkopírujte ID widgetu, názvy a vlastní stav do pomocné struktury CompactWidgetInfo a uložte ho do RunningWidgets členské proměnné. Vložte následující kód do definice třídy WidgetProvider.
// 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;
}
}
}
Implementace objektu pro vytváření tříd, která vytvoří instanci WidgetProvideru na žádost
Aby hostitel widgetu komunikoval s naším poskytovatelem widgetů, musíme volat CoRegisterClassObject. Tato funkce vyžaduje, abychom vytvořili implementaci IClassFactory , která vytvoří objekt třídy pro naši WidgetProvider třídy. Náš objekt pro vytváření tříd implementujeme do samostatné pomocné třídy.
V sadě Visual Studio klikněte pravým tlačítkem na projekt ExampleWidgetProvider v Průzkumníku řešení a vyberte Přidat –>Třída. V dialogovém okně Přidat třídu pojmenujte třídu FactoryHelper a klikněte na Přidat.
Obsah souboru FactoryHelper.cs nahraďte následujícím kódem. Tento kód definuje rozhraní IClassFactory a implementuje je dvě metody CreateInstance a LockServer. Tento kód je typický často používaný pro implementaci objektu pro vytváření tříd a není specifický pro funkce zprostředkovatele widgetu s tím rozdílem, že označujeme, že objekt třídy, který se vytváří, implementuje IWidgetProvider rozhraní.
// 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;
}
}
Vytvořte identifikátor GUID, který představuje CLSID pro vašeho poskytovatele widgetu
Dále je potřeba vytvořit identifikátor GUID představující CLSID , který se použije k identifikaci vašeho poskytovatele widgetu pro aktivaci COM. Stejná hodnota se použije také při balení aplikace. Vygenerujte GUID v sadě Visual Studio tak, že přejdete na Tools->Vytvořit GUID. Vyberte možnost formát registru a klikněte na Kopírovat a vložte ho do textového souboru, abyste ho mohli později zkopírovat.
Registrace objektu třídy zprostředkovatele widgetu v OLE
V souboru Program.cs pro náš spustitelný soubor zavoláme CoRegisterClassObject k registraci poskytovatele widgetu v OLE, aby s ním hostitel widgetu mohl pracovat. Obsah Program.cs nahraďte následujícím kódem. Tento kód importuje funkci CoRegisterClassObject a volá ji a předává WidgetProviderFactory rozhraní, které jsme definovali v předchozím kroku. Nezapomeňte aktualizovat deklaraci proměnné CLSID_Factory tak, aby používala identifikátor GUID, který jste vygenerovali v předchozím kroku.
// 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);
}
Všimněte si, že tento příklad kódu naimportuje funkci GetConsoleWindow , která určí, jestli je aplikace spuštěná jako konzolová aplikace, výchozí chování pro tento názorný postup. Pokud funkce vrátí platný ukazatel, zapíšeme do konzoly informace o ladění. Jinak je aplikace spuštěná jako aplikace pro Windows. V takovém případě počkáme na událost, kterou jsme nastavili v DeleteWidget metodě, když je seznam povolených widgetů prázdný, a poté aplikaci ukončíme. Informace o převodu ukázkové konzolové aplikace na aplikaci pro Windows najdete v tématu Převod konzolové aplikace na aplikaci pro Windows.
Zabalte svou aplikaci poskytovatele widgetů
V aktuální verzi je možné jako poskytovatele widgetů zaregistrovat jenom zabalené aplikace. Následující kroky vás provedou procesem zabalení aplikace a aktualizací manifestu aplikace pro registraci aplikace v operačním systému jako poskytovatele widgetu.
Vytvoření projektu balení MSIX
V Průzkumníku řešeníklikněte pravým tlačítkem na své řešení a vyberte Přidat–>Nový projekt.... V dialogovém okně Přidat nový projekt vyberte šablonu Projekt balení aplikace pro Windows a klikněte na Další. Nastavte název projektu na ExampleWidgetProviderPackage a klikněte na Vytvořit. Po zobrazení výzvy nastavte cílovou verzi na verzi 1809 nebo novější a klikněte na OK. Dále klikněte pravým tlačítkem myši na projekt s názvem ExampleWidgetProviderPackage a vyberte Add->Project reference. Vyberte projekt ExampleWidgetProvider a klikněte na tlačítko OK.
Přidání odkazu na balíček sady Windows App SDK do projektu balení
Do projektu balíčku MSIX musíte přidat odkaz na balíček NuGet sady Windows App SDK. V Průzkumníku řešenídvojklikněte na projekt ExampleWidgetProviderPackage a otevřete soubor ExampleWidgetProviderPackage.wapproj. Do elementu Project přidejte následující kód XML.
<!--ExampleWidgetProviderPackage.wapproj-->
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.2.221116.1">
<IncludeAssets>build</IncludeAssets>
</PackageReference>
</ItemGroup>
Poznámka:
Ujistěte se, že verze zadaná v elementu PackageReference odpovídá nejnovější stabilní verzi, na kterou jste odkazovali v předchozím kroku.
Pokud je v počítači už nainstalovaná správná verze sady Windows App SDK a nechcete do balíčku zabalit modul runtime sady SDK, můžete určit závislost balíčku v souboru Package.appxmanifest pro projekt ExampleWidgetProviderPackage.
<!--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>
...
Aktualizace manifestu balíčku
Ve Průzkumníku řešení klikněte pravým tlačítkem na soubor Package.appxmanifest a vyberte možnost Zobrazit kód, abyste otevřeli soubor XML manifestu. Dále je potřeba přidat deklarace oboru názvů pro některá rozšíření balíčků aplikací, které budeme používat. Do elementu nejvyšší úrovně Package přidejte následující definice oboru názvů.
<!-- Package.appmanifest -->
<Package
...
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
Uvnitř elementu Application vytvořte nový prázdný prvek s názvem Extensions. Dbejte na to, aby to přišlo po uzavírací značce uap:VisualElements.
<!-- Package.appxmanifest -->
<Application>
...
<Extensions>
</Extensions>
</Application>
První rozšíření, které potřebujeme přidat, je rozšíření ComServer. Tím se zaregistruje vstupní bod spustitelného souboru v operačním systému. Toto rozšíření je ekvivalentem zabalené aplikace pro registraci serveru COM nastavením klíče registru a není specifické pro poskytovatele widgetů. Přidejte následující prvek com:Extension jako podřízený prvek Extensions. Změňte GUID v atributu Id elementu com:Class na GUID, který jste vygenerovali v předchozím kroku.
<!-- 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>
Dále přidejte rozšíření, které zaregistruje aplikaci jako poskytovatele widgetu. V následujícím úseku kódu vložte prvek uap3:Extension jako podřízený prvek elementu Extensions. Nezapomeňte nahradit atribut ClassId elementu COM identifikátorem GUID, který jste použili v předchozích krocích.
<!-- 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>
Podrobné popisy a informace o formátu pro všechny tyto prvky naleznete v tématu Formát XML manifestu balíčku poskytovatele widgetu.
Přidání ikon a dalších obrázků do projektu balení
V Průzkumníku řešeníklikněte pravým tlačítkem myši na ExampleWidgetProviderPackage a vyberte Přidat->Nová složka. Pojmenujte tuto složku ProviderAssets, protože se používá v Package.appxmanifest z předchozího kroku. Tady uložíme naše ikony a snímky obrazovek pro naše widgety. Po přidání požadovaných ikon a snímků obrazovky se ujistěte, že názvy obrázků odpovídají tomu, co následuje po Path=ProviderAssets\ ve vašem Package.appxmanifest nebo se widgety nezobrazí v hostiteli widgetu.
Informace o požadavcích na návrh obrázků snímků obrazovky a konvencích vytváření názvů pro lokalizované snímky obrazovky najdete v tématu Integrace s nástrojem pro výběr widgetu.
Testování poskytovatele widgetů
Ujistěte se, že jste vybrali architekturu, která odpovídá vašemu vývojovému počítači, z rozevíracího seznamu platformy řešení , například x64. V Průzkumníku řešeníklikněte pravým tlačítkem na vaše řešení a vyberte Sestavit řešení. Po dokončení klikněte pravým tlačítkem na ExampleWidgetProviderPackage a vyberte možnost Nasadit. V aktuální verzi je jediným podporovaným hostitelem widgetů panel widgetů. Pokud chcete zobrazit widgety, budete muset otevřít panel widgetů a vybrat Přidat widgety v pravém horním rohu. Přejděte na konec seznamu dostupných widgetů a měli byste vidět simulovaný widget Počasí a widget Microsoft Counting , které byly vytvořeny v tomto kurzu. Kliknutím na widgety je připnete na panel widgetů a otestujete jejich funkčnost.
Ladění poskytovatele widgetů
Po připnutí widgetů spustí platforma widgetů aplikaci poskytovatele widgetů, aby mohla přijímat a odesílat relevantní informace o widgetu. Pokud chcete ladit spuštěný widget, můžete buď připojit ladicí program ke spuštěné aplikaci zprostředkovatele widgetů, nebo můžete nastavit visual Studio tak, aby po spuštění automaticky spustilo ladění procesu zprostředkovatele widgetu.
Chcete-li se připojit ke spuštěném procesu:
- V sadě Visual Studio klikněte na Ladit –> Připojit k procesu.
- Vyfiltrujte procesy a najděte požadovanou aplikaci zprostředkovatele widgetu.
- Připojte ladicí program.
Pokud chcete automaticky připojit ladicí program k procesu při počátečním spuštění:
- Ve Visual Studiu klikněte na Ladění –> Další cíle ladění –> Ladění nainstalovaného balíčku aplikace.
- Vyfiltrujte balíčky a najděte požadovaný balíček zprostředkovatele widgetu.
- Vyberte jej a zaškrtněte políčko s názvem Nespouštět, ale při spuštění ladit můj kód.
- Klepněte na tlačítko Připojit.
Převod konzolové aplikace na aplikaci pro Windows
Chcete-li převést konzolovou aplikaci vytvořenou v tomto názorném postupu na aplikaci pro Windows, klikněte pravým tlačítkem myši na projekt ExampleWidgetProvider v Průzkumníku řešení a vyberte Vlastnosti. V části Obecné aplikace> změňte typ výstupu z konzolové aplikace na "Aplikace systému Windows".
Publikování widgetu
Po vývoji a otestování widgetu můžete aplikaci publikovat v Microsoft Storu, aby si uživatelé nainstalovali widgety na svá zařízení. Podrobné pokyny k publikování aplikace najdete v tématu Publikování aplikace v Microsoft Storu.
Kolekce obchodu s widgety
Po publikování aplikace v Microsoft Storu můžete požádat o zahrnutí aplikace do kolekce widgetů Store, která uživatelům pomáhá zjišťovat aplikace, které obsahují widgety pro Windows. Pokud chcete odeslat svou žádost, přečtěte si jak odeslat informace o widgetu pro přidání do kolekce obchodu.
Implementace přizpůsobení widgetu
Od sady Windows App SDK 1.4 můžou widgety podporovat přizpůsobení uživatelů. Při implementaci této funkce se do nabídky se třemi tečkami nad možností Odepnout widget přidá možnost Přizpůsobit widget.
Následující kroky shrnují proces přizpůsobení widgetu.
- V normálním provozu poskytovatel widgetu reaguje na požadavky z hostitele widgetu pomocí šablony a datových částí pro běžné prostředí widgetu.
- Uživatel klikne na tlačítko Přizpůsobit widget v nabídce s trojtečkou.
- Widget vyvolá událost OnCustomizationRequested poskytovateli widgetu, aby naznačil, že uživatel požádal o přizpůsobení widgetu.
- Poskytovatel widgetu nastaví interní příznak, který označuje, že widget je v režimu přizpůsobení. V režimu přizpůsobení odesílá poskytovatel widgetů šablony JSON pro uživatelské rozhraní pro přizpůsobení widgetu místo běžného uživatelského rozhraní widgetu.
- V režimu přizpůsobení obdrží poskytovatel widgetu OnActionInvoked události, jakmile uživatel pracuje s uživatelským rozhraním pro přizpůsobení a upravuje jeho interní konfiguraci a chování na základě akcí uživatele.
- Když je akce spojená s událostí OnActionInvoked akcí "ukončení přizpůsobení" definovanou aplikací, poskytovatel widgetu resetuje svůj interní příznak, aby označil, že už není v režimu přizpůsobení, a pokračuje v odesílání šablon vizuálního zobrazení a dat v JSON formátu pro běžné prostředí widgetu, což odráží změny požadované během přizpůsobení. Uživatel může zavřít prostředí pro přizpůsobení, aniž by klikl na aplikací určenou akci pro ukončení přizpůsobení. V tomto případě bude vyvolána IWidgetProviderAnalytics.OnAnalyticsInfoReported a WidgetAnalyticsInfoReportedArgs.AnalyticsJson bude mít druhInterakce "exitCustomization".
- Poskytovatel widgetu uchovává možnosti přizpůsobení disku nebo cloudu, aby se změny zachovaly mezi vyvoláním poskytovatele widgetu.
Poznámka:
U widgetů vytvořených pomocí sady Windows App SDK existuje známá chyba, která způsobí, že nabídka se třemi tečkami přestane reagovat, jakmile se zobrazí karta přizpůsobení.
V typických scénářích přizpůsobení widgetu uživatel zvolí, jaká data se ve widgetu zobrazí, nebo upraví vizuální prezentaci widgetu. Pro zjednodušení, příklad v této části zavede funkci, která uživateli umožní resetovat čítač počítacího widgetu, který byl implementován v předchozích krocích.
Poznámka:
Přizpůsobení widgetu se podporuje jenom v sadě Windows App SDK 1.4 a novějších verzích. Nezapomeňte aktualizovat odkazy v projektu na nejnovější verzi balíčku NuGet.
Aktualizace manifestu balíčku pro deklaraci podpory přizpůsobení
Pokud chcete hostiteli widgetu dát vědět, že widget podporuje přizpůsobení, přidejte atribut IsCustomizable do elementu Definition widgetu a nastavte ho na true.
...
<Definition Id="Counting_Widget"
DisplayName="Microsoft Counting Widget"
Description="CONFIG counting widget description"
IsCustomizable="true">
...
Sledování, kdy je widget v režimu přizpůsobení
Příklad v tomto článku používá pomocné struktury CompactWidgetInfo ke sledování aktuálního stavu našich aktivních widgetů. Přidejte pole inCustomization, které se použije ke sledování, kdy hostitel widgetů očekává, že místo běžné šablony widgetu odešleme šablonu JSON vlastního nastavení.
// 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;
}
Implementujte IWidgetProvider2
Funkce přizpůsobení widgetu je zpřístupněna prostřednictvím rozhraní IWidgetProvider2 . Aktualizujte definici třídy WidgetProvider pro implementaci tohoto rozhraní.
// WidgetProvider.cs
internal class WidgetProvider : IWidgetProvider, IWidgetProvider2
Přidejte implementaci pro zpětné volání OnCustomizationRequested v rozhraní IWidgetProvider2. Tato metoda používá stejný vzor jako ostatní zpětné volání, které jsme použili. ID widgetu, který se má přizpůsobit, získáme z WidgetContextu a najdeme pomocnou strukturu CompactWidgetInfo přidruženou k danému widgetu a nastavíme pole inCustomization na hodnotu true.
// 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);
}
}
Teď deklarujte proměnnou řetězce, která definuje šablonu JSON pro uživatelské rozhraní pro přizpůsobení widgetu. V tomto příkladu máme tlačítko Resetovat čítač a tlačítko Ukončit vlastní nastavení, které signalizují, že se náš poskytovatel vrátí k běžnému chování widgetu. Tuto definici umístěte vedle ostatních definic šablon.
// 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""
}";
Odeslání šablony vlastního nastavení v nástroji UpdateWidget
V dalším kroku aktualizujeme naši UpdateWidget pomocnou metodu, která odesílá naše data a šablony JSON vizuálu hostiteli widgetů. Při aktualizaci widgetu pro počítání pošleme buď běžnou šablonu widgetu, nebo šablonu přizpůsobení v závislosti na hodnotě inCustomization pole. Pro stručnost není v tomto fragmentu kódu vynechán kód, který není relevantní pro přizpůsobení.
// 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);
}
Reakce na akce přizpůsobení
Když uživatelé pracují se vstupy v naší šabloně přizpůsobení, volá stejnou OnActionInvoked obslužnou rutinu, jako když uživatel pracuje s běžným prostředím widgetu. Abychom mohli podporovat přizpůsobení, vyhledáme příkazy "reset" a "exitCustomization" z naší šablony JSON pro přizpůsobení. Pokud se jedná o akci pro tlačítko „Resetovat čítač“, resetujeme čítač uložený v poli customState naší pomocné struktury na 0. Pokud je akce pro tlačítko "Ukončit přizpůsobení", nastavíme inCustomization pole false tak, aby při volání UpdateWidget, naše pomocná metoda odešle běžné šablony JSON, a ne šablonu přizpůsobení.
// 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);
}
}
}
Nyní, když nasadíte widget, měli byste v nabídce s elipsou vidět tlačítko Přizpůsobit widget. Kliknutím na tlačítko Přizpůsobit zobrazíte šablonu vlastního nastavení.
Kliknutím na tlačítko Resetovat počítadlo resetujete počítadlo na 0. Kliknutím na tlačítko Ukončit přizpůsobení se vrátíte k běžnému chování widgetu.
Windows developer