Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Dit is het vierde deel van een zelfstudie die laat zien hoe u een voorbeeld-WPF-bureaublad-app met de naam Contoso Expenses kunt moderniseren. Zie Zelfstudie: Een WPF-app moderniserenvoor een overzicht van de zelfstudie, vereisten en instructies voor het downloaden van de voorbeeld-app. In dit artikel wordt ervan uitgegaan dat u deel 3 al hebt voltooid.
In de vorige delen van deze zelfstudie hebt u UWP XAML-besturingselementen aan de app toegevoegd met behulp van XAML-eilanden. Als bijproduct hiervan hebt u de app ook ingeschakeld om winRT-API's aan te roepen. Hiermee opent u de mogelijkheid voor de app om veel andere functies van Windows te gebruiken, niet alleen UWP XAML-besturingselementen.
In het fictieve scenario van deze zelfstudie heeft het ontwikkelteam van Contoso besloten om twee nieuwe functies toe te voegen aan de app: activiteiten en meldingen. Dit deel van de zelfstudie laat zien hoe u deze functies implementeert.
Een gebruikersactiviteit toevoegen
Opmerking
De tijdlijnfunctie wordt stopgezet sinds Windows 11
In Windows 10 kunnen apps activiteiten bijhouden die door de gebruiker worden uitgevoerd, zoals het openen van een bestand of het weergeven van een specifieke pagina. Deze activiteiten worden vervolgens beschikbaar gesteld via Tijdlijn, een functie die is geïntroduceerd in Windows 10 versie 1803, waarmee de gebruiker snel terug kan gaan naar het verleden en een activiteit kan hervatten die ze eerder hebben gestart.
Gebruikersactiviteiten worden bijgehouden met behulp van Microsoft Graph. Wanneer u echter een Windows 10-app bouwt, hoeft u niet rechtstreeks te communiceren met de REST-eindpunten van Microsoft Graph. In plaats daarvan kunt u een handige set WinRT-API's gebruiken. We gaan deze WinRT-API's gebruiken in de Contoso Expenses-app om bij te houden wanneer de gebruiker een uitgave in de app opent, en Adaptive Cards gebruiken om gebruikers in staat te stellen de activiteit te creëren.
Inleiding tot adaptieve kaarten
In deze sectie vindt u een kort overzicht van Adaptive Cards. Als u deze informatie niet nodig hebt, kunt u deze overslaan en direct doorgaan naar de instructies voor het toevoegen van een adaptieve kaart.
Met adaptieve kaarten kunnen ontwikkelaars kaartinhoud op een gemeenschappelijke en consistente manier uitwisselen. Een adaptieve kaart wordt beschreven door een JSON-nettolading die de inhoud definieert, waaronder tekst, afbeeldingen, acties en meer.
Een adaptieve kaart definieert alleen de inhoud en niet het visuele uiterlijk van de inhoud. Het platform waarop de adaptieve kaart wordt ontvangen, kan de inhoud weergeven met behulp van de meest geschikte stijl. De manier waarop adaptieve kaarten worden ontworpen, is via een renderer, die de JSON-nettolading kan gebruiken en deze kan converteren naar een systeemeigen gebruikersinterface. De gebruikersinterface kan bijvoorbeeld XAML zijn voor een WPF- of UWP-app, AXML voor een Android-app of HTML voor een website of een botchat.
Hier volgt een voorbeeld van een eenvoudige payload van een adaptieve kaart.
{
"type": "AdaptiveCard",
"body": [
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"size": "Medium",
"weight": "Bolder",
"text": "Publish Adaptive Card schema"
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"items": [
{
"type": "Image",
"style": "Person",
"url": "https://pbs.twimg.com/profile_images/3647943215/d7f12830b3c17a5a9e4afcc370e3a37e_400x400.jpeg",
"size": "Small"
}
],
"width": "auto"
},
{
"type": "Column",
"items": [
{
"type": "TextBlock",
"weight": "Bolder",
"text": "Matt Hidinger",
"wrap": true
},
{
"type": "TextBlock",
"spacing": "None",
"text": "Created {{DATE(2017-02-14T06:08:39Z,SHORT)}}",
"isSubtle": true,
"wrap": true
}
],
"width": "stretch"
}
]
}
]
}
],
"actions": [
{
"type": "Action.ShowCard",
"title": "Set due date",
"card": {
"type": "AdaptiveCard",
"style": "emphasis",
"body": [
{
"type": "Input.Date",
"id": "dueDate"
},
{
"type": "Input.Text",
"id": "comment",
"placeholder": "Add a comment",
"isMultiline": true
}
],
"actions": [
{
"type": "Action.OpenUrl",
"title": "OK",
"url": "http://adaptivecards.io"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json"
}
},
{
"type": "Action.OpenUrl",
"title": "View",
"url": "http://adaptivecards.io"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}
In de onderstaande afbeelding ziet u hoe deze JSON op verschillende manieren wordt weergegeven door ta Teams-kanaal, Cortana en een Windows-melding.
Adaptieve kaarten spelen een belangrijke rol in de tijdlijn omdat dit de manier is waarop Windows activiteiten weergeeft. Elke miniatuur die in de tijdlijn wordt weergegeven, is eigenlijk een adaptieve kaart. Als u een gebruikersactiviteit in uw app gaat maken, wordt u gevraagd om een adaptieve kaart op te geven om deze weer te geven.
Opmerking
Een geweldige manier om te brainstormen over het ontwerp van een Adaptive Card is door gebruik te maken van de online designer. U kunt de kaart ontwerpen met bouwstenen (afbeeldingen, teksten, kolommen, enzovoort) en de bijbehorende JSON ophalen. Nadat u een idee hebt van het uiteindelijke ontwerp, kunt u een bibliotheek met de naam Adaptieve kaarten gebruiken om het eenvoudiger te maken om uw adaptieve kaart te bouwen met behulp van C#-klassen in plaats van gewone JSON. Dit kan lastig zijn om fouten op te sporen en te bouwen.
Een adaptieve kaart toevoegen
Klik met de rechtermuisknop op het project ContosoExpenses.Core in Solution Explorer en kies NuGet-pakketten beheren.
Klik in het venster NuGet Package Manager op Bladeren.... Zoek het
Newtonsoft.Jsonpakket en installeer de meest recente beschikbare versie. Dit is een populaire JSON-manipulatiebibliotheek die u gaat gebruiken om de JSON-tekenreeksen te bewerken die vereist zijn voor adaptieve kaarten.
Opmerking
Als u het
Newtonsoft.Jsonpakket niet afzonderlijk installeert, verwijst de bibliotheek adaptieve kaarten naar een oudere versie van hetNewtonsoft.Jsonpakket die .NET Core 3.0 niet ondersteunt.Klik in het venster NuGet Package Manager op Bladeren.... Zoek het
AdaptiveCardspakket en installeer de meest recente beschikbare versie.
Klik in Solution Explorer met de rechtermuisknop op het project ContosoExpenses.Core en kies Toevoegen -> Klasse. Geef de klasse een naam TimelineService.cs en klik op OK.
Voeg in het bestand TimelineService.cs de volgende instructies toe aan het begin van het bestand.
using AdaptiveCards; using ContosoExpenses.Data.Models;Wijzig de naamruimte gedeclareerd in het bestand
ContosoExpenses.CorenaarContosoExpenses.Voeg de volgende methode toe aan de klasse
TimelineService.private string BuildAdaptiveCard(Expense expense) { AdaptiveCard card = new AdaptiveCard("1.0"); AdaptiveTextBlock title = new AdaptiveTextBlock { Text = expense.Description, Size = AdaptiveTextSize.Medium, Wrap = true }; AdaptiveColumnSet columnSet = new AdaptiveColumnSet(); AdaptiveColumn photoColumn = new AdaptiveColumn { Width = "auto" }; AdaptiveImage image = new AdaptiveImage { Url = new Uri("https://appmodernizationworkshop.blob.core.windows.net/contosoexpenses/Contoso192x192.png"), Size = AdaptiveImageSize.Small, Style = AdaptiveImageStyle.Default }; photoColumn.Items.Add(image); AdaptiveTextBlock amount = new AdaptiveTextBlock { Text = expense.Cost.ToString(), Weight = AdaptiveTextWeight.Bolder, Wrap = true }; AdaptiveTextBlock date = new AdaptiveTextBlock { Text = expense.Date.Date.ToShortDateString(), IsSubtle = true, Spacing = AdaptiveSpacing.None, Wrap = true }; AdaptiveColumn expenseColumn = new AdaptiveColumn { Width = "stretch" }; expenseColumn.Items.Add(amount); expenseColumn.Items.Add(date); columnSet.Columns.Add(photoColumn); columnSet.Columns.Add(expenseColumn); card.Body.Add(title); card.Body.Add(columnSet); string json = card.ToJson(); return json; }
Informatie over de code
Deze methode ontvangt een Expense-object met alle informatie over de te renderen onkosten en bouwt een nieuw AdaptiveCard--object. De methode voegt het volgende toe aan de kaart:
- Een titel, die de beschrijving van de onkosten gebruikt.
- Een afbeelding, het Contoso-logo.
- Het bedrag van de kosten.
- De datum van de onkosten.
De laatste drie elementen worden gesplitst in twee verschillende kolommen, zodat het Contoso-logo en de details over de onkosten naast elkaar kunnen worden geplaatst. Nadat het object is gemaakt, retourneert de methode de bijbehorende JSON-tekenreeks met behulp van de ToJson-methode .
De gebruikersactiviteit definiëren
Nu u de adaptieve kaart hebt gedefinieerd, kunt u er een gebruikersactiviteit op basis van maken.
Voeg de volgende instructies toe aan het begin van TimelineService.cs bestand:
using Windows.ApplicationModel.UserActivities; using System.Threading.Tasks; using Windows.UI.Shell;Opmerking
Dit zijn UWP-naamruimten. Deze worden opgelost omdat het
Microsoft.Toolkit.Wpf.UI.ControlsNuGet-pakket dat u in stap 2 hebt geïnstalleerd, een verwijzing naar hetMicrosoft.Windows.SDK.Contractspakket bevat, waardoor het Project ContosoExpenses.Core kan verwijzen naar WinRT-API's, ook al is het een .NET Core 3-project.Voeg de volgende velddeclaraties toe aan de
TimelineServiceklasse.private UserActivityChannel _userActivityChannel; private UserActivity _userActivity; private UserActivitySession _userActivitySession;Voeg de volgende methode toe aan de klasse
TimelineService.public async Task AddToTimeline(Expense expense) { _userActivityChannel = UserActivityChannel.GetDefault(); _userActivity = await _userActivityChannel.GetOrCreateUserActivityAsync($"Expense-{expense.ExpenseId}"); _userActivity.ActivationUri = new Uri($"contosoexpenses://expense/{expense.ExpenseId}"); _userActivity.VisualElements.DisplayText = "Contoso Expenses"; string json = BuildAdaptiveCard(expense); _userActivity.VisualElements.Content = AdaptiveCardBuilder.CreateAdaptiveCardFromJson(json); await _userActivity.SaveAsync(); _userActivitySession?.Dispose(); _userActivitySession = _userActivity.CreateSession(); }Sla de wijzigingen op in TimelineService.cs.
Informatie over de code
De AddToTimeline methode haalt eerst een UserActivityChannel-object op dat is vereist voor het opslaan van gebruikersactiviteiten. Vervolgens wordt een nieuwe gebruikersactiviteit gemaakt met behulp van de methode GetOrCreateUserActivityAsync , waarvoor een unieke id is vereist. Als er al een activiteit bestaat, kan de app deze bijwerken. anders wordt er een nieuwe gemaakt. De id die moet worden doorgegeven, is afhankelijk van het type toepassing dat u bouwt:
- Als u altijd dezelfde activiteit wilt bijwerken, zodat tijdlijn alleen de meest recente activiteit weergeeft, kunt u een vaste id (zoals Onkosten) gebruiken.
- Als u elke activiteit wilt bijhouden als een andere activiteit, zodat alle activiteiten in de tijdlijn worden weergegeven, kunt u een dynamische id gebruiken.
In dit scenario houdt de app elke geopende onkosten bij als een andere gebruikersactiviteit, zodat de code elke ID definieert met behulp van het trefwoord Expense- gevolgd door de unieke onkosten-ID.
Nadat de methode een UserActivity-object heeft gemaakt, wordt het object gevuld met de volgende informatie:
- Een ActivationUri- die wordt aangeroepen wanneer de gebruiker op de activiteit in de tijdlijn klikt. De code maakt gebruik van een aangepast protocol met de naam contosoexpenses dat later door de app wordt verwerkt.
- Het VisualElements-object , dat een set eigenschappen bevat waarmee het uiterlijk van de activiteit wordt gedefinieerd. Deze code stelt de DisplayText in (de titel die boven de vermelding in de tijdlijn staat) en de Inhoud.
Hier speelt de adaptieve kaart die u eerder hebt gedefinieerd een rol. De app geeft de door u eerder ontworpen adaptieve kaart als inhoud door aan de methode. Windows 10 gebruikt echter een ander object om een kaart weer te geven in vergelijking met het object dat door het AdaptiveCards NuGet-pakket wordt gebruikt. Daarom maakt de methode de kaart opnieuw met behulp van de methode CreateAdaptiveCardFromJson die wordt weergegeven door de klasse AdaptiveCardBuilder . Nadat de methode de gebruikersactiviteit heeft gemaakt, wordt de activiteit opgeslagen en wordt er een nieuwe sessie gemaakt.
Wanneer een gebruiker op een activiteit in de tijdlijn klikt, wordt het contosoexpenses:// -protocol geactiveerd en bevat de URL de informatie die de app nodig heeft om de geselecteerde onkosten op te halen. Als optionele taak kunt u de protocolactivering implementeren zodat de toepassing correct reageert wanneer de gebruiker Tijdlijn gebruikt.
De toepassing integreren met tijdlijn
Nu u een klasse hebt gemaakt die communiceert met Tijdlijn, kunnen we deze gaan gebruiken om de ervaring van de toepassing te verbeteren. De beste plek om de methode AddToTimeline te gebruiken die wordt weergegeven door de klasse TimelineService is wanneer de gebruiker de detailpagina van een onkosten opent.
Vouw in het project ContosoExpenses.Core de map ViewModels uit en open het bestand ExpenseDetailViewModel.cs . Dit is het ViewModel dat het venster van de onkostendetails ondersteunt.
Zoek de openbare constructor van de klasse ExpenseDetailViewModel en voeg de volgende code toe aan het einde van de constructor. Wanneer het kostenvenster wordt geopend, roept de methode de AddToTimeline--methode aan en geeft de huidige kosten door. De klasse TimelineService gebruikt deze informatie om een gebruikersactiviteit te maken met behulp van de onkostengegevens.
TimelineService timeline = new TimelineService(); timeline.AddToTimeline(expense);Wanneer u klaar bent, moet de constructor er als volgt uitzien.
public ExpensesDetailViewModel(IDatabaseService databaseService, IStorageService storageService) { var expense = databaseService.GetExpense(storageService.SelectedExpense); ExpenseType = expense.Type; Description = expense.Description; Location = expense.Address; Amount = expense.Cost; TimelineService timeline = new TimelineService(); timeline.AddToTimeline(expense); }Druk op F5 om de app te bouwen en uit te voeren in het foutopsporingsprogramma. Kies een werknemer uit de lijst en kies vervolgens een onkost. Noteer op de detailpagina de beschrijving van de onkosten, de datum en het bedrag.
Druk op Start + Tab om de tijdlijn te openen.
Schuif omlaag in de lijst met momenteel geopende toepassingen totdat u de sectie eerder vandaag ziet. In deze sectie ziet u enkele van uw meest recente gebruikersactiviteiten. Klik op de Alle activiteiten weergeven koppeling naast de Eerder vandaag kop.
Bevestig dat u een nieuwe kaart ziet met de informatie over de onkosten die u zojuist hebt geselecteerd in de toepassing.
Als u nu andere uitgaven opent, ziet u dat er nieuwe kaarten worden toegevoegd als gebruikersactiviteiten. Houd er rekening mee dat de code een andere identificatiecode gebruikt voor elke activiteit, zodat er een kaart wordt gemaakt voor elke uitgave die u in de app opent.
Sluit de app.
Een melding toevoegen
De tweede functie die het contoso-ontwikkelingsteam wil toevoegen, is een melding die wordt weergegeven aan de gebruiker wanneer er een nieuwe onkosten worden opgeslagen in de database. Hiervoor kunt u gebruikmaken van het ingebouwde systeem voor meldingen in Windows 10, dat beschikbaar is voor ontwikkelaars via WinRT-API's. Dit meldingssysteem heeft veel voordelen:
- Meldingen zijn consistent met de rest van het besturingssysteem.
- Ze kunnen actie ondernemen.
- Ze worden opgeslagen in het Actiecentrum, zodat ze later kunnen worden gecontroleerd.
Een melding toevoegen aan de app:
Klik in Solution Explorer met de rechtermuisknop op het project ContosoExpenses.Core en kies Toevoegen -> Klasse. Geef de klasse een naam NotificationService.cs en klik op OK.
Voeg in het bestand NotificationService.cs de volgende instructies toe aan het begin van het bestand.
using Windows.Data.Xml.Dom; using Windows.UI.Notifications;Wijzig de naamruimte gedeclareerd in het bestand
ContosoExpenses.CorenaarContosoExpenses.Voeg de volgende methode toe aan de klasse
NotificationService.public void ShowNotification(string description, double amount) { string xml = $@"<toast> <visual> <binding template='ToastGeneric'> <text>Expense added</text> <text>Description: {description} - Amount: {amount} </text> </binding> </visual> </toast>"; XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); ToastNotification toast = new ToastNotification(doc); ToastNotificationManager.CreateToastNotifier().Show(toast); }Toastmeldingen worden vertegenwoordigd door een XML-payload, die tekst, afbeeldingen, acties en meer kan bevatten. Hier vindt u alle ondersteunde elementen. Deze code maakt gebruik van een heel eenvoudig schema met twee regels tekst: de titel en de hoofdtekst. Nadat de code de XML-nettolading definieert en laadt in een XmlDocument-object , wordt de XML in een ToastNotification-object verpakt en weergegeven met behulp van de klasse ToastNotificationManager .
Vouw in het project ContosoExpenses.Core de map ViewModels uit en open het bestand AddNewExpenseViewModel.cs .
Zoek de
SaveExpenseCommandmethode, die wordt geactiveerd wanneer de gebruiker op de knop drukt om een nieuwe onkosten te besparen. Voeg de volgende code toe aan deze methode, net na de aanroep naar deSaveExpensemethode.NotificationService notificationService = new NotificationService(); notificationService.ShowNotification(expense.Description, expense.Cost);Wanneer u klaar bent, moet de
SaveExpenseCommandmethode er als volgt uitzien.private RelayCommand _saveExpenseCommand; public RelayCommand SaveExpenseCommand { get { if (_saveExpenseCommand == null) { _saveExpenseCommand = new RelayCommand(() => { Expense expense = new Expense { Address = Address, City = City, Cost = Cost, Date = Date, Description = Description, EmployeeId = storageService.SelectedEmployeeId, Type = ExpenseType }; databaseService.SaveExpense(expense); NotificationService notificationService = new NotificationService(); notificationService.ShowNotification(expense.Description, expense.Cost); Messenger.Default.Send<UpdateExpensesListMessage>(new UpdateExpensesListMessage()); Messenger.Default.Send<CloseWindowMessage>(new CloseWindowMessage()); }, () => IsFormFilled ); } return _saveExpenseCommand; } }Druk op F5 om de app te bouwen en uit te voeren in het foutopsporingsprogramma. Kies een werknemer in de lijst en klik vervolgens op de knop Nieuwe onkosten toevoegen . Vul alle velden in het formulier in en druk op Opslaan.
U ontvangt de volgende uitzondering.
Deze uitzondering wordt veroorzaakt door het feit dat de app Contoso Expenses nog geen pakketidentiteit heeft. Voor sommige WinRT-API's, waaronder de api voor meldingen, is pakketidentiteit vereist voordat ze in een app kunnen worden gebruikt. UWP-apps ontvangen standaard pakketidentiteit omdat ze alleen kunnen worden gedistribueerd via MSIX-pakketten. Andere typen Windows-apps, waaronder WPF-apps, kunnen ook worden geïmplementeerd via MSIX-pakketten om pakketidentiteit te verkrijgen. In het volgende deel van deze zelfstudie wordt uitgelegd hoe u dit doet.
Volgende stappen
Op dit moment in de zelfstudie hebt u een gebruikersactiviteit toegevoegd aan de app die is geïntegreerd met Windows Timeline en u hebt ook een melding toegevoegd aan de app die wordt geactiveerd wanneer gebruikers een nieuwe onkosten maken. De melding werkt echter nog niet omdat voor de app pakketidentiteit is vereist voor het gebruik van de API voor meldingen. Zie deel 5: Verpakken en implementeren met MSIX voor de app voor meer informatie over het bouwen van een MSIX-pakket om pakketidentiteit te verkrijgen en andere implementatievoordelen te krijgen.
Windows developer