Bagian 4: Menambahkan aktivitas dan pemberitahuan pengguna Windows
Ini adalah bagian keempat dari tutorial yang menunjukkan cara memodernisasi sampel aplikasi desktop WPF bernama Contoso Expenses. Untuk gambaran umum tutorial, prasyarat, dan instruksi untuk mengunduh aplikasi sampel, lihat Tutorial: Memodernisasi aplikasi WPF. Artikel ini mengasumsikan Anda telah menyelesaikan bagian 3.
Di bagian sebelumnya dari tutorial ini Anda menambahkan kontrol UWP XAML ke aplikasi menggunakan Kepulauan XAML. Sebagai produk sampingan dari ini, Anda juga mengaktifkan aplikasi untuk memanggil API WinRT apa pun. Ini membuka kesempatan bagi aplikasi untuk menggunakan banyak fitur lain yang ditawarkan oleh Windows, bukan hanya kontrol UWP XAML.
Dalam skenario fiktif tutorial ini, tim pengembangan Contoso telah memutuskan untuk menambahkan dua fitur baru ke aplikasi: aktivitas dan pemberitahuan. Bagian tutorial ini menunjukkan cara mengimplementasikan fitur-fitur ini.
Menambahkan aktivitas pengguna
Catatan
Fitur garis waktu dihentikan sejak Windows 11
Di Windows 10, aplikasi dapat melacak aktivitas yang dilakukan oleh pengguna seperti membuka file atau menampilkan halaman tertentu. Aktivitas ini kemudian tersedia melalui Timeline, fitur yang diperkenalkan di Windows 10 versi 1803, yang memungkinkan pengguna untuk dengan cepat kembali ke masa lalu dan melanjutkan aktivitas yang mereka mulai sebelumnya.
Aktivitas pengguna dilacak menggunakan Microsoft Graph. Namun, saat membuat aplikasi Windows 10, Anda tidak perlu berinteraksi langsung dengan titik akhir REST yang disediakan oleh Microsoft Graph. Sebagai gantinya, Anda dapat menggunakan sekumpulan API WinRT yang nyaman. Kami akan menggunakan API WinRT ini di aplikasi Pengeluaran Contoso untuk melacak setiap kali pengguna membuka pengeluaran dalam aplikasi, dan menggunakan Kartu Adaptif untuk memungkinkan pengguna membuat aktivitas.
Pengantar Kartu Adaptif
Bagian ini memberikan gambaran singkat tentang Kartu Adaptif. Jika Anda tidak memerlukan informasi ini, Anda dapat melewati ini dan langsung masuk ke instruksi tambahkan Kartu Adaptif.
Kartu Adaptif memungkinkan pengembang untuk bertukar konten kartu dengan cara yang sama dan konsisten. Kartu Adaptif dijelaskan oleh payload JSON yang menentukan kontennya, yang dapat mencakup teks, gambar, tindakan, dan banyak lagi.
Kartu Adaptif hanya mendefinisikan konten dan bukan tampilan visual konten. Platform tempat Kartu Adaptif diterima dapat merender konten menggunakan gaya yang paling tepat. Cara Kartu Adaptif dirancang adalah melalui perender, yang mampu mengambil payload JSON dan untuk mengonversinya menjadi UI asli. Misalnya, UI dapat berupa XAML untuk aplikasi WPF atau UWP, AXML untuk aplikasi Android, atau HTML untuk situs web atau obrolan bot.
Berikut adalah contoh payload Kartu Adaptif sederhana.
{
"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"
}
Gambar di bawah ini menunjukkan bagaimana JSON ini dirender dengan cara yang berbeda dengan saluran Ta Teams, Cortana, dan pemberitahuan Windows.
Kartu adaptif memainkan peran penting dalam Garis Waktu karena itu adalah cara Windows merender aktivitas. Setiap gambar mini yang ditampilkan di dalam Garis Waktu sebenarnya adalah Kartu Adaptif. Dengan demikian, saat Anda akan membuat aktivitas pengguna di dalam aplikasi, Anda akan diminta untuk menyediakan Kartu Adaptif untuk merendernya.
Catatan
Cara yang bagus untuk bertukar pikiran desain Kartu Adaptif menggunakan perancang online. Anda akan memiliki kesempatan untuk merancang kartu dengan blok penyusun (gambar, teks, kolom, dll) dan mendapatkan JSON yang sesuai. Setelah Anda memiliki gambaran tentang desain akhir, Anda dapat menggunakan pustaka yang disebut Kartu Adaptif untuk membuatnya lebih mudah untuk membangun Kartu Adaptif Anda menggunakan kelas C# alih-alih JSON biasa, yang mungkin sulit untuk di-debug dan dibangun.
Menambahkan Kartu Adaptif
Klik kanan pada proyek ContosoExpenses.Core di Penjelajah Solusi dan pilih Kelola paket NuGet.
Di jendela Manajer Paket NuGet, klik Telusuri. Cari
Newtonsoft.Json
paket dan instal versi terbaru yang tersedia. Ini adalah pustaka manipulasi JSON populer yang akan Anda gunakan untuk membantu memanipulasi string JSON yang diperlukan oleh Kartu Adaptif.Catatan
Jika Anda tidak menginstal
Newtonsoft.Json
paket secara terpisah, pustaka Kartu Adaptif akan mereferensikan versiNewtonsoft.Json
paket lama yang tidak mendukung .NET Core 3.0.Di jendela Manajer Paket NuGet, klik Telusuri. Cari
AdaptiveCards
paket dan instal versi terbaru yang tersedia.Di Penjelajah Solusi, klik kanan proyek ContosoExpenses.Core, pilih Tambahkan -> Kelas. Beri nama kelas TimelineService.cs dan klik OK.
Dalam file TimelineService.cs, tambahkan pernyataan berikut ke bagian atas file.
using AdaptiveCards; using ContosoExpenses.Data.Models;
Ubah namespace yang dideklarasikan dalam file dari
ContosoExpenses.Core
keContosoExpenses
.Tambahkan metode berikut ke kelas
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; }
Tentang kode
Metode ini menerima objek Pengeluaran dengan semua informasi tentang pengeluaran yang akan dirender dan membangun objek AdaptiveCard baru. Metode menambahkan yang berikut ke kartu:
- Judul, yang menggunakan deskripsi pengeluaran.
- Gambar, yang merupakan logo Contoso.
- Jumlah pengeluaran.
- Tanggal pengeluaran.
3 elemen terakhir dibagi menjadi dua kolom yang berbeda, sehingga logo Contoso dan detail tentang pengeluaran dapat ditempatkan berdampingan. Setelah objek dibuat, metode mengembalikan string JSON yang sesuai dengan bantuan metode ToJson .
Menentukan aktivitas pengguna
Setelah menentukan Kartu Adaptif, Anda dapat membuat aktivitas pengguna berdasarkannya.
Tambahkan pernyataan berikut ke bagian atas file TimelineService.cs :
using Windows.ApplicationModel.UserActivities; using System.Threading.Tasks; using Windows.UI.Shell;
Catatan
Ini adalah namespace layanan UWP. Ini diselesaikan karena
Microsoft.Toolkit.Wpf.UI.Controls
paket NuGet yang Anda instal di langkah 2 menyertakan referensi keMicrosoft.Windows.SDK.Contracts
paket, yang memungkinkan proyek ContosoExpenses.Core untuk mereferensikan API WinRT meskipun itu adalah proyek .NET Core 3.Tambahkan deklarasi bidang berikut ke
TimelineService
kelas .private UserActivityChannel _userActivityChannel; private UserActivity _userActivity; private UserActivitySession _userActivitySession;
Tambahkan metode berikut ke kelas
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(); }
Simpan perubahan ke TimelineService.cs.
Tentang kode
Metode ini AddToTimeline
pertama-tama mendapatkan objek UserActivityChannel yang diperlukan untuk menyimpan aktivitas pengguna. Kemudian membuat aktivitas pengguna baru menggunakan metode GetOrCreateUserActivityAsync , yang memerlukan pengidentifikasi unik. Dengan cara ini, jika aktivitas sudah ada, aplikasi dapat memperbaruinya; jika tidak, itu akan membuat yang baru. Pengidentifikasi yang akan diteruskan tergantung pada jenis aplikasi yang Anda bangun:
- Jika Anda ingin selalu memperbarui aktivitas yang sama sehingga Garis Waktu hanya akan menampilkan yang terbaru, Anda dapat menggunakan pengidentifikasi tetap (seperti Pengeluaran).
- Jika Anda ingin melacak setiap aktivitas sebagai aktivitas yang berbeda, sehingga Garis Waktu akan menampilkan semuanya, Anda dapat menggunakan pengidentifikasi dinamis.
Dalam skenario ini, aplikasi akan melacak setiap pengeluaran yang dibuka sebagai aktivitas pengguna yang berbeda, sehingga kode membuat setiap pengidentifikasi dengan menggunakan kata kunci Expense- diikuti oleh ID pengeluaran unik.
Setelah metode membuat objek UserActivity , metode mengisi objek dengan info berikut:
- ActivationUri yang dipanggil saat pengguna mengklik aktivitas di Garis Waktu. Kode ini menggunakan protokol kustom yang disebut contosoexpenses yang akan ditangani aplikasi nanti.
- Objek VisualElements , yang berisi sekumpulan properti yang menentukan tampilan visual aktivitas. Kode ini mengatur DisplayText (yang merupakan judul yang ditampilkan di atas entri di Garis Waktu) dan Konten.
Di sinilah Kartu Adaptif yang Anda tentukan sebelumnya memainkan peran. Aplikasi ini meneruskan Kartu Adaptif yang Anda rancang sebelumnya sebagai konten ke metode . Namun, Windows 10 menggunakan objek yang berbeda untuk mewakili kartu dibandingkan dengan yang digunakan oleh AdaptiveCards
paket NuGet. Oleh karena itu, metode membuat ulang kartu dengan menggunakan metode CreateAdaptiveCardFromJson yang diekspos oleh kelas AdaptiveCardBuilder . Setelah metode membuat aktivitas pengguna, metode menyimpan aktivitas dan membuat sesi baru.
Ketika pengguna mengklik aktivitas di Garis Waktu, protokol contosoexpenses:// akan diaktifkan dan URL akan menyertakan informasi yang dibutuhkan aplikasi untuk mengambil pengeluaran yang dipilih. Sebagai tugas opsional, Anda dapat menerapkan aktivasi protokol sehingga aplikasi bereaksi dengan benar saat pengguna menggunakan Garis Waktu.
Mengintegrasikan aplikasi dengan Garis Waktu
Sekarang setelah Anda membuat kelas yang berinteraksi dengan Timeline, kita dapat mulai menggunakannya untuk meningkatkan pengalaman aplikasi. Tempat terbaik untuk menggunakan metode AddToTimeline yang diekspos oleh kelas TimelineService adalah ketika pengguna membuka halaman detail pengeluaran.
Dalam proyek ContosoExpenses.Core, perluas folder ViewModels dan buka file ExpenseDetailViewModel.cs. Ini adalah ViewModel yang mendukung jendela detail pengeluaran.
Temukan konstruktor publik kelas ExpenseDetailViewModel dan tambahkan kode berikut di akhir konstruktor. Setiap kali jendela pengeluaran dibuka, metode memanggil metode AddToTimeline dan melewati pengeluaran saat ini. Kelas TimelineService menggunakan info ini untuk membuat aktivitas pengguna menggunakan informasi pengeluaran.
TimelineService timeline = new TimelineService(); timeline.AddToTimeline(expense);
Setelah selesai, konstruktor akan terlihat seperti ini.
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); }
Tekan F5 untuk membuat dan menjalankan aplikasi di debugger. Pilih karyawan dari daftar lalu pilih pengeluaran. Di halaman detail, perhatikan deskripsi pengeluaran, tanggal, dan jumlahnya.
Tekan Mulai + TAB untuk membuka Garis Waktu.
Gulir ke bawah daftar aplikasi yang saat ini dibuka hingga Anda melihat bagian berjudul Sebelumnya hari ini. Bagian ini memperlihatkan beberapa aktivitas pengguna terbaru Anda. Klik tautan Lihat semua aktivitas di samping judul Sebelumnya hari ini.
Konfirmasikan bahwa Anda melihat kartu baru dengan informasi tentang pengeluaran yang baru saja Anda pilih dalam aplikasi.
Jika sekarang Anda membuka pengeluaran lain, Anda akan melihat kartu baru ditambahkan sebagai aktivitas pengguna. Ingatlah bahwa kode menggunakan pengidentifikasi yang berbeda untuk setiap aktivitas, sehingga membuat kartu untuk setiap pengeluaran yang Anda buka di aplikasi.
Tutup aplikasi.
Menambahkan pemberitahuan
Fitur kedua yang ingin ditambahkan tim pengembangan Contoso adalah pemberitahuan yang ditampilkan kepada pengguna setiap kali pengeluaran baru disimpan ke database. Untuk melakukan ini, Anda dapat memanfaatkan sistem pemberitahuan bawaan di Windows 10, yang diekspos ke pengembang melalui API WinRT. Sistem pemberitahuan ini memiliki banyak keuntungan:
- Pemberitahuan konsisten dengan OS lainnya.
- Mereka dapat ditindak.
- Mereka disimpan di Pusat Tindakan sehingga dapat ditinjau nanti.
Untuk menambahkan pemberitahuan ke aplikasi:
Di Penjelajah Solusi, klik kanan proyek ContosoExpenses.Core, pilih Tambahkan -> Kelas. Beri nama kelas NotificationService.cs dan klik OK.
Dalam file NotificationService.cs, tambahkan pernyataan berikut ke bagian atas file.
using Windows.Data.Xml.Dom; using Windows.UI.Notifications;
Ubah namespace yang dideklarasikan dalam file dari
ContosoExpenses.Core
keContosoExpenses
.Tambahkan metode berikut ke kelas
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); }
Pemberitahuan toast diwakili oleh payload XML, yang dapat menyertakan teks, gambar, tindakan, dan banyak lagi. Anda dapat menemukan semua elemen yang didukung di sini. Kode ini menggunakan skema yang sangat sederhana dengan dua baris teks: judul dan isinya. Setelah kode menentukan payload XML dan memuatnya dalam objek XmlDocument, kode membungkus XML dalam objek ToastNotification dan menunjukkannya dengan menggunakan kelas ToastNotificationManager.
Dalam proyek ContosoExpenses.Core, perluas folder ViewModels dan buka file AddNewExpenseViewModel.cs.
SaveExpenseCommand
Temukan metode , yang dipicu ketika pengguna menekan tombol untuk menyimpan pengeluaran baru. Tambahkan kode berikut ke metode ini, tepat setelah panggilan keSaveExpense
metode .NotificationService notificationService = new NotificationService(); notificationService.ShowNotification(expense.Description, expense.Cost);
Setelah selesai,
SaveExpenseCommand
metode akan terlihat seperti ini.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; } }
Tekan F5 untuk membuat dan menjalankan aplikasi di debugger. Pilih karyawan dari daftar lalu klik tombol Tambahkan pengeluaran baru. Lengkapi semua bidang dalam formulir dan tekan Simpan.
Anda akan menerima pengecualian berikut.
Pengecualian ini disebabkan oleh fakta bahwa aplikasi Pengeluaran Contoso belum memiliki identitas paket. Beberapa API WinRT, termasuk API pemberitahuan, memerlukan identitas paket sebelum dapat digunakan dalam aplikasi. Aplikasi UWP menerima identitas paket secara default karena hanya dapat didistribusikan melalui paket MSIX. Jenis aplikasi Windows lainnya, termasuk aplikasi WPF, juga dapat disebarkan melalui paket MSIX untuk mendapatkan identitas paket. Bagian berikutnya dari tutorial ini akan mengeksplorasi cara melakukan ini.
Langkah berikutnya
Pada titik ini dalam tutorial, Anda telah berhasil menambahkan aktivitas pengguna ke aplikasi yang terintegrasi dengan Garis Waktu Windows, dan Anda juga telah menambahkan pemberitahuan ke aplikasi yang dipicu saat pengguna membuat pengeluaran baru. Namun, pemberitahuan belum berfungsi karena aplikasi memerlukan identitas paket untuk menggunakan API pemberitahuan. Untuk mempelajari cara membuat paket MSIX untuk aplikasi guna mendapatkan identitas paket dan mendapatkan manfaat penyebaran lainnya, lihat Bagian 5: Paket dan sebarkan dengan MSIX.
Windows developer