Bagikan melalui


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.

Windows Timeline image

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.

Adaptive Card rendering image

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

  1. Klik kanan pada proyek ContosoExpenses.Core di Penjelajah Solusi dan pilih Kelola paket NuGet.

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

    NewtonSoft.Json NuGet package

    Catatan

    Jika Anda tidak menginstal Newtonsoft.Json paket secara terpisah, pustaka Kartu Adaptif akan mereferensikan versi Newtonsoft.Json paket lama yang tidak mendukung .NET Core 3.0.

  3. Di jendela Manajer Paket NuGet, klik Telusuri. Cari AdaptiveCards paket dan instal versi terbaru yang tersedia.

    Adaptive Cards NuGet package

  4. Di Penjelajah Solusi, klik kanan proyek ContosoExpenses.Core, pilih Tambahkan -> Kelas. Beri nama kelas TimelineService.cs dan klik OK.

  5. Dalam file TimelineService.cs, tambahkan pernyataan berikut ke bagian atas file.

    using AdaptiveCards;
    using ContosoExpenses.Data.Models;
    
  6. Ubah namespace yang dideklarasikan dalam file dari ContosoExpenses.Core ke ContosoExpenses.

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

  1. 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 ke Microsoft.Windows.SDK.Contracts paket, yang memungkinkan proyek ContosoExpenses.Core untuk mereferensikan API WinRT meskipun itu adalah proyek .NET Core 3.

  2. Tambahkan deklarasi bidang berikut ke TimelineService kelas .

    private UserActivityChannel _userActivityChannel;
    private UserActivity _userActivity;
    private UserActivitySession _userActivitySession;
    
  3. 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();
    }
    
  4. 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.

  1. Dalam proyek ContosoExpenses.Core, perluas folder ViewModels dan buka file ExpenseDetailViewModel.cs. Ini adalah ViewModel yang mendukung jendela detail pengeluaran.

  2. 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);
    }
    
  3. 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.

  4. Tekan Mulai + TAB untuk membuka Garis Waktu.

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

  6. Konfirmasikan bahwa Anda melihat kartu baru dengan informasi tentang pengeluaran yang baru saja Anda pilih dalam aplikasi.

    Contoso Expenses Timeline

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

  8. 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:

  1. Di Penjelajah Solusi, klik kanan proyek ContosoExpenses.Core, pilih Tambahkan -> Kelas. Beri nama kelas NotificationService.cs dan klik OK.

  2. Dalam file NotificationService.cs, tambahkan pernyataan berikut ke bagian atas file.

    using Windows.Data.Xml.Dom;
    using Windows.UI.Notifications;
    
  3. Ubah namespace yang dideklarasikan dalam file dari ContosoExpenses.Core ke ContosoExpenses.

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

  5. Dalam proyek ContosoExpenses.Core, perluas folder ViewModels dan buka file AddNewExpenseViewModel.cs.

  6. SaveExpenseCommand Temukan metode , yang dipicu ketika pengguna menekan tombol untuk menyimpan pengeluaran baru. Tambahkan kode berikut ke metode ini, tepat setelah panggilan ke SaveExpense 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;
        }
    }
    
  7. 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.

  8. Anda akan menerima pengecualian berikut.

    Toast notification error

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.