Bagikan melalui


Bagian 3: Menambahkan kontrol UWP CalendarView menggunakan Kepulauan XAML

Ini adalah bagian ketiga 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 2.

Dalam skenario fiktif tutorial ini, tim pengembangan Contoso ingin mempermudah memilih tanggal untuk laporan pengeluaran pada perangkat yang mendukung sentuhan. Di bagian tutorial ini, Anda akan menambahkan kontrol UWP CalendarView ke aplikasi. Ini adalah kontrol yang sama yang digunakan dalam fungsionalitas tanggal dan waktu Windows pada taskbar.

Gambar CalendarViewControl

Tidak seperti kontrol InkCanvas yang Anda tambahkan di bagian 2, Windows Community Toolkit tidak menyediakan versi yang dibungkus dari UWP CalendarView yang dapat digunakan di aplikasi WPF. Sebagai alternatif, Anda akan menghosting InkCanvas di kontrol WindowsXamlHost generik. Anda dapat menggunakan kontrol ini untuk menghosting kontrol UWP pihak pertama yang disediakan oleh pustaka Windows SDK atau WinUI atau kontrol UWP kustom apa pun yang dibuat oleh pihak ketiga. Kontrol WindowsXamlHost disediakan oleh Microsoft.Toolkit.Wpf.UI.XamlHost paket NuGet paket. Paket ini disertakan dengan Microsoft.Toolkit.Wpf.UI.Controls paket NuGet yang Anda instal di bagian 2.

Catatan

Tutorial ini hanya menunjukkan cara menggunakan WindowsXamlHost untuk menghosting kontrol CalendarView pihak pertama yang disediakan oleh Windows SDK. Untuk panduan yang menunjukkan cara menghosting kontrol kustom, lihat Menghosting kontrol UWP kustom di aplikasi WPF menggunakan Kepulauan XAML.

Untuk menggunakan kontrol WindowsXamlHost , Anda harus langsung memanggil API WinRT dari kode di aplikasi WPF. Paket Microsoft.Windows.SDK.Contracts NuGet berisi referensi yang diperlukan untuk memungkinkan Anda memanggil API WinRT dari aplikasi. Paket ini juga termasuk dalam Microsoft.Toolkit.Wpf.UI.Controls paket NuGet yang Anda instal di bagian 2.

Menambahkan kontrol WindowsXamlHost

  1. Di Penjelajah Solusi, perluas folder Tampilan di proyek ContosoExpenses.Core dan klik dua kali file AddNewExpense.xaml. Ini adalah formulir yang digunakan untuk menambahkan pengeluaran baru ke daftar. Berikut adalah bagaimana tampilannya di versi aplikasi saat ini.

    Tambahkan pengeluaran baru

    Kontrol pemilih tanggal yang disertakan dalam WPF dimaksudkan untuk komputer tradisional dengan mouse dan keyboard. Memilih tanggal dengan layar sentuh tidak benar-benar layak, karena ukuran kontrol yang kecil dan ruang terbatas antara setiap hari di kalender.

  2. Di bagian atas file AddNewExpense.xaml , tambahkan atribut berikut ke elemen Window .

    xmlns:xamlhost="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost"
    

    Setelah menambahkan atribut ini, elemen Window sekarang akan terlihat seperti ini.

    <Window x:Class="ContosoExpenses.Views.AddNewExpense"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:xamlhost="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost"
            DataContext="{Binding Source={StaticResource ViewModelLocator},Path=AddNewExpenseViewModel}"
            xmlns:local="clr-namespace:ContosoExpenses"
            mc:Ignorable="d"
            Title="Add new expense" Height="450" Width="800"
            Background="{StaticResource AddNewExpenseBackground}">
    
  3. Ubah atribut Tinggi elemen Window dari 450 menjadi 800. Ini diperlukan karena kontrol UWP CalendarView membutuhkan lebih banyak ruang daripada pemilih tanggal WPF.

    <Window x:Class="ContosoExpenses.Views.AddNewExpense"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:xamlhost="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost"
            DataContext="{Binding Source={StaticResource ViewModelLocator},Path=AddNewExpenseViewModel}"
            xmlns:local="clr-namespace:ContosoExpenses"
            mc:Ignorable="d"
            Title="Add new expense" Height="800" Width="800"
            Background="{StaticResource AddNewExpenseBackground}">
    
  4. DatePicker Temukan elemen di dekat bagian bawah file, dan ganti elemen ini dengan XAML berikut.

    <xamlhost:WindowsXamlHost InitialTypeName="Windows.UI.Xaml.Controls.CalendarView" Grid.Column="1" Grid.Row="6" Margin="5, 0, 0, 0" x:Name="CalendarUwp"  />
    

    XAML ini menambahkan kontrol WindowsXamlHost . Properti InitialTypeName menunjukkan nama lengkap kontrol UWP yang ingin Anda host (dalam hal ini, Windows.UI.Xaml.Controls.CalendarView).

  5. Tekan F5 untuk membuat dan menjalankan aplikasi di debugger. Pilih karyawan dari daftar lalu tekan tombol Tambahkan pengeluaran baru. Konfirmasikan bahwa halaman berikut menghosting kontrol UWP CalendarView baru.

    Pembungkus CalendarView

  6. Tutup aplikasi.

Berinteraksi dengan kontrol WindowsXamlHost

Selanjutnya, Anda akan memperbarui aplikasi untuk memproses tanggal yang dipilih, menampilkannya di layar, dan mengisi objek Pengeluaran untuk disimpan dalam database.

CalendarView UWP berisi dua anggota yang relevan untuk skenario ini:

  • Properti SelectedDates berisi tanggal yang dipilih oleh pengguna.
  • Peristiwa SelectedDatesChanged dimunculkan saat pengguna memilih tanggal.

Namun, kontrol WindowsXamlHost adalah kontrol host generik untuk segala jenis kontrol UWP. Dengan demikian, properti tidak mengekspos properti yang disebut SelectedDates atau peristiwa yang disebut SelectedDatesChanged, karena khusus kontrol CalendarView . Untuk mengakses anggota ini, Anda harus menulis kode yang melemparkan WindowsXamlHost ke jenis CalendarView . Tempat terbaik untuk melakukan ini adalah sebagai respons terhadap peristiwa ChildChanged dari kontrol WindowsXamlHost , yang dinaikkan ketika kontrol yang dihosting telah dirender.

  1. Dalam file AddNewExpense.xaml, tambahkan penanganan aktivitas untuk peristiwa ChildChanged dari kontrol WindowsXamlHost yang Anda tambahkan sebelumnya. Setelah selesai, elemen WindowsXamlHost akan terlihat seperti ini.

    <xamlhost:WindowsXamlHost InitialTypeName="Windows.UI.Xaml.Controls.CalendarView" Grid.Column="1" Grid.Row="6" Margin="5, 0, 0, 0" x:Name="CalendarUwp"  ChildChanged="CalendarUwp_ChildChanged" />
    
  2. Dalam file yang sama, temukan elemen Grid.RowDefinitions dari Grid utama. Tambahkan satu elemen RowDefinition lagi dengan Tinggi sama dengan Otomatis di akhir daftar elemen turunan. Setelah selesai, elemen Grid.RowDefinitions akan terlihat seperti ini (sekarang harus ada 9 elemen RowDefinition ).

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    
  3. Tambahkan XAML berikut setelah elemen WindowsXamlHost dan sebelum elemen Tombol di dekat akhir file.

    <TextBlock Text="Selected date:" FontSize="16" FontWeight="Bold" Grid.Row="7" Grid.Column="0" />
    <TextBlock Text="{Binding Path=Date}" FontSize="16" Grid.Row="7" Grid.Column="1" />
    
  4. Temukan elemen Tombol di dekat akhir file dan ubah properti Grid.Row dari 7 menjadi 8. Ini menggeser tombol ke bawah satu baris di kisi karena Anda menambahkan baris baru.

    <Button Content="Save" Grid.Row="8" Grid.Column="0" Command="{Binding Path=SaveExpenseCommand}" Margin="5, 12, 0, 0" HorizontalAlignment="Left" Width="180" />
    
  5. Buka file kode AddNewExpense.xaml.cs.

  6. Tambahkan pernyataan berikut ke bagian atas file.

    using Microsoft.Toolkit.Wpf.UI.XamlHost;
    
  7. Tambahkan penanganan aktivitas berikut ke AddNewExpense kelas . Kode ini mengimplementasikan peristiwa ChildChanged dari kontrol WindowsXamlHost yang Anda nyatakan sebelumnya dalam file XAML.

    private void CalendarUwp_ChildChanged(object sender, System.EventArgs e)
    {
        WindowsXamlHost windowsXamlHost = (WindowsXamlHost)sender;
    
        Windows.UI.Xaml.Controls.CalendarView calendarView =
            (Windows.UI.Xaml.Controls.CalendarView)windowsXamlHost.Child;
    
        if (calendarView != null)
        {
            calendarView.SelectedDatesChanged += (obj, args) =>
            {
                if (args.AddedDates.Count > 0)
                {
                    Messenger.Default.Send<SelectedDateMessage>(new SelectedDateMessage(args.AddedDates[0].DateTime));
                }
            };
        }
    }
    

    Kode ini menggunakan properti Turunan dari kontrol WindowsXamlHost untuk mengakses kontrol UWP CalendarView . Kode kemudian berlangganan peristiwa SelectedDatesChanged , yang dipicu saat pengguna memilih tanggal dari kalender. Penanganan aktivitas ini meneruskan tanggal yang dipilih ke ViewModel tempat objek Pengeluaran baru dibuat dan disimpan ke database. Untuk melakukan ini, kode menggunakan infrastruktur olahpesan yang disediakan oleh paket MVVM Light NuGet. Kode mengirim pesan yang disebut SelectedDateMessage ke ViewModel, yang akan menerimanya dan mengatur properti Tanggal dengan nilai yang dipilih. Dalam skenario ini, kontrol CalendarView dikonfigurasi untuk mode pilihan tunggal, sehingga koleksi hanya akan berisi satu elemen.

    Pada titik ini, proyek masih tidak akan dikompilasi karena tidak memiliki implementasi untuk kelas SelectedDateMessage . Langkah-langkah berikut menerapkan kelas ini.

  8. Di Penjelajah Solusi, klik kanan folder Pesan dan pilih Tambahkan -> Kelas. Beri nama kelas baru SelectedDateMessage dan klik Tambahkan.

  9. Ganti konten file kode SelectedDateMessage.cs dengan kode berikut. Kode ini menambahkan pernyataan penggunaan untuk GalaSoft.MvvmLight.Messaging namespace layanan (dari paket MVVM Light NuGet), mewarisi dari kelas MessageBase , dan menambahkan properti DateTime yang diinisialisasi melalui konstruktor publik. Setelah selesai, file akan terlihat seperti ini.

    using GalaSoft.MvvmLight.Messaging;
    using System;
    
    namespace ContosoExpenses.Messages
    {
        public class SelectedDateMessage: MessageBase
        {
            public DateTime SelectedDate { get; set; }
    
            public SelectedDateMessage(DateTime selectedDate)
            {
                this.SelectedDate = selectedDate;
            }
        }
    }
    
  10. Selanjutnya, Anda akan memperbarui ViewModel untuk menerima pesan ini dan mengisi properti Tanggal ViewModel. Di Penjelajah Solusi, perluas folder ViewModels dan buka file AddNewExpenseViewModel.cs.

  11. Temukan konstruktor publik untuk AddNewExpenseViewModel kelas dan tambahkan kode berikut ke akhir konstruktor. Kode ini mendaftar untuk menerima SelectedDateMessage, mengekstrak tanggal yang dipilih darinya melalui properti SelectedDate , dan kami menggunakannya untuk mengatur properti Tanggal yang diekspos oleh ViewModel. Karena properti ini terikat dengan kontrol TextBlock yang Anda tambahkan sebelumnya, Anda dapat melihat tanggal yang dipilih oleh pengguna.

    Messenger.Default.Register<SelectedDateMessage>(this, message =>
    {
        Date = message.SelectedDate;
    });
    

    Setelah selesai, AddNewExpenseViewModel konstruktor akan terlihat seperti ini.

    public AddNewExpenseViewModel(IDatabaseService databaseService, IStorageService storageService)
    {
        this.databaseService = databaseService;
        this.storageService = storageService;
    
        Date = DateTime.Today;
    
        Messenger.Default.Register<SelectedDateMessage>(this, message =>
        {
            Date = message.SelectedDate;
        });
    }
    

    Catatan

    Metode SaveExpenseCommand dalam file kode yang sama melakukan pekerjaan menyimpan pengeluaran ke database. Metode ini menggunakan properti Tanggal untuk membuat objek Pengeluaran baru. Properti ini sekarang sedang diisi oleh kontrol CalendarView melalui pesan yang SelectedDateMessage baru saja Anda buat.

  12. Tekan F5 untuk membuat dan menjalankan aplikasi di debugger. Pilih salah satu karyawan yang tersedia lalu klik tombol Tambahkan pengeluaran baru. Lengkapi semua bidang dalam formulir dan pilih tanggal dari kontrol CalendarView baru. Konfirmasikan tanggal terpilih ditampilkan sebagai untai (karakter) di bawah kontrol.

  13. Tekan tombol Simpan . Formulir akan ditutup dan pengeluaran baru ditambahkan ke akhir daftar pengeluaran. Kolom pertama dengan tanggal pengeluaran harus menjadi tanggal yang Anda pilih di kontrol CalendarView .

Langkah berikutnya

Pada titik ini dalam tutorial, Anda telah berhasil mengganti kontrol waktu tanggal WPF dengan kontrol UWP CalendarView , yang mendukung sentuhan dan pena digital selain mouse dan input keyboard. Meskipun Windows Community Toolkit tidak menyediakan versi yang dibungkus dari kontrol UWP CalendarView yang dapat digunakan langsung di aplikasi WPF, Anda dapat menghosting kontrol dengan menggunakan kontrol WindowsXamlHost generik.

Anda sekarang siap untuk Bagian 4: Tambahkan aktivitas dan pemberitahuan pengguna Windows.