Поделиться через


Часть 3. Добавление элемента управления UWP CalendarView с помощью XAML Islands

Это третья часть руководства, в которой рассматривается модернизация примера классического приложения WPF Contoso Expenses. Общие сведения о руководстве, предварительных требованиях и инструкциях по скачиванию примера приложения см. в руководстве по модернизации приложения WPF. В этой статье предполагается, что вы уже выполнили инструкции из части 2.

В вымышленном сценарии, рассматриваемом в рамках этого руководства, группа разработки Contoso хочет упростить выбор даты для отчета о расходах на устройстве с сенсорным вводом. В этой части руководства вы добавите в приложение элемент управления UWP CalendarView. Это элемент управления, который используется в функциях даты и времени Windows на панели задач.

Изображение элемента управления CalendarView

В отличие от элемента управления InkCanvas, добавленного в части 2, набор средств сообщества Windows Community не предоставляет упакованную версию UWP CalendarView, которую можно использовать в приложениях WPF. В качестве альтернативы можно разместить InkCanvas в универсальном элементе управления WindowsXamlHost. Этот элемент управления можно использовать для размещения любого основного элемента управления UWP из Windows SDK или библиотеки WinUI либо любого пользовательского элемента управления UWP, созданного сторонним производителем. Элемент управления WindowsXamlHost предоставляется в пакете NuGet Microsoft.Toolkit.Wpf.UI.XamlHost. Этот пакет входит в состав пакета NuGet Microsoft.Toolkit.Wpf.UI.Controls, установленного в части 2.

Примечание.

В этом руководстве показано, как использовать WindowsXamlHost для размещения основного элемента управления CalendarView из Windows SDK. Пошаговое руководство, в котором показано, как разместить пользовательский элемент управления, приведено в разделе Размещение настраиваемого элемента управления UWP в приложении WPF, использующем XAML Islands.

Чтобы использовать элемент управления WindowsXamlHost, потребуется напрямую вызывать интерфейсы API WinRT из кода в приложении WPF. Пакет NuGet Microsoft.Windows.SDK.Contracts содержит ссылки, необходимые для вызова интерфейсов API WinRT из приложения. Этот пакет также входит в состав пакета NuGet Microsoft.Toolkit.Wpf.UI.Controls, установленного в части 2.

Добавление элемента управления WindowsXamlHost

  1. В обозревателе решений разверните папку Представления для проекта ContosoExpenses.Core и дважды щелкните файл AddNewExpense.xaml. Это форма, используемая для добавления новой статьи расходов в список. Ниже показано, как она выглядит в текущей версии приложения.

    Добавление новой статьи расходов

    Элемент управления "Выбор даты", включенный в WPF, предназначен для традиционных компьютеров с мышью и клавиатурой. Выбор даты на сенсорном экране не слишком удобен из-за маленького размера элемента управления и ограниченного расстояния между днями в календаре.

  2. В начало файла AddNewExpense.xaml добавьте в элемент Window следующий атрибут.

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

    Когда вы добавите этот атрибут, элемент Окно будет выглядеть следующим образом.

    <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. Измените значение атрибута Height элемента Window с 450 на 800. Это необходимо, так как элемент управления UWP CalendarView занимает больше пространства, чем элемент управления "Выбор даты" 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 в нижней части файла и замените этот элемент приведенным ниже кодом XAML.

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

    Этот код XAML добавляет элемент управления WindowsXamlHost. Свойство InitialTypeName указывает полное имя элемента управления UWP, который требуется разместить (в данном случае это Windows.UI.XAML.Controls.CalendarView).

  5. Нажмите клавишу F5, чтобы выполнить сборку приложения и открыть его в отладчике. Выберите из списка сотрудника и нажмите кнопку Add new expense (Добавить новую статью расходов). Убедитесь, что на следующей странице размещен новый элемент управления UWP CalendarView.

    Оболочка CalendarView

  6. Закройте приложение.

Взаимодействие с элементом управления WindowsXamlHost

Далее следует обновить приложение для обработки выбранной даты, отобразить ее на экране и заполнить объект Expense, чтобы сохранить его в базе данных.

Элемент управления UWP CalendarView содержит два элемента, которые относятся к этому сценарию:

  • свойство SelectedDates, содержащее дату, которую выбрал пользователь;
  • событие SelectedDatesChanged, возникающее, когда пользователь выбирает дату.

Однако WindowsXamlHost является универсальным элементом управления ведущего приложения для любого типа элемента управления UWP. Таким образом, он не предоставляет свойство SelectedDates или событие SelectedDatesChanged, так как они относятся к CalendarView. Чтобы получить доступ к этим элементам, необходимо написать код, который приводит WindowsXamlHost к типу CalendarView. Лучше это сделать в ответ на событие ChildChanged элемента управления WindowsXamlHost, которое порождается при отображении размещенного элемента управления.

  1. В файл ddNewExpense.xaml добавьте обработчик событий для события ChildChanged элемента управления WindowsXamlHost, добавленного ранее. По завершении элемент WindowsXamlHost должен выглядеть следующим образом.

    <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. В том же файле найдите элемент Grid.RowDefini основного элемента Grid. Добавьте еще один элемент RowDefinition со свойством Height, имеющим значение Auto, в конец списка дочерних элементов. По завершении элемент Grid.RowDefinitions должен выглядеть следующим образом (теперь должно быть 9 элементов 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. Добавьте приведенный ниже код XAML после элемента WindowsXamlHost и перед элементом Button, указанным ближе к концу файла.

    <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. Найдите элемент Button в конце файла и измените значение свойства Grid.Row с 7 на 8. Это сдвинет кнопку на одну строку в сетке, так как вы добавили новую строку.

    <Button Content="Save" Grid.Row="8" Grid.Column="0" Command="{Binding Path=SaveExpenseCommand}" Margin="5, 12, 0, 0" HorizontalAlignment="Left" Width="180" />
    
  5. Откройте файл кода AddNewExpense.xaml.cs.

  6. Добавьте следующий оператор в начало файла.

    using Microsoft.Toolkit.Wpf.UI.XamlHost;
    
  7. Добавьте следующий обработчик событий в класс AddNewExpense. Этот код реализует событие ChildChanged элемента управления WindowsXamlHost, объявленного ранее в 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));
                }
            };
        }
    }
    

    Этот код использует свойство Child элемента управления WindowsXamlHost для доступа к элементу управления UWP CalendarView. Затем код подписывается на событие SelectedDatesChanged, которое активируется, когда пользователь выбирает дату из календаря. Этот обработчик событий передает выбранную дату в ViewModel, где новый объект Expense создается и сохраняется в базе данных. Для этого в коде используется инфраструктура обмена сообщениями, предоставляемая пакетом NuGet MVVM Light. Код отправляет сообщение SelectedDateMessage в объект ViewModel, который получает его и присваивает свойству Date выбранное значение. В этом сценарии элемент управления CalendarView настроен для режима одиночного выбора, поэтому коллекция будет содержать только один элемент.

    На этом этапе проект по-прежнему не компилируется, так как в нем отсутствует реализация класса SelectedDateMessage. Следующие шаги реализуют этот класс.

  8. В обозревателе решений, щелкните правой кнопкой мыши папку Сообщения и выберите Добавить -> Класс. Присвойте новому классу имя SelectedDateMessage и нажмите кнопку Добавить.

  9. Замените все содержимое файла кода SelectedDateMessage.cs приведенным ниже кодом. Этот код добавляет оператор using для пространства имен GalaSoft.MvvmLight.Messaging (из пакета NuGet MVVM Light), наследует от класса MessageBase и добавляет свойство DateTime, которое инициализируется с помощью общедоступного конструктора. По завершении файл должен выглядеть следующим образом.

    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. Далее следует обновить ViewModel для получения этого сообщения и заполнить свойство Date ViewModel. В обозревателе решений разверните папку ViewModels и откройте файл AddNewExpenseViewModel.cs.

  11. Найдите общедоступный конструктор класса AddNewExpenseViewModel и добавьте в его конец приведенный ниже код. Этот код регистрирует приложение для получения сообщения SelectedDateMessage и получает выбранную дату из его свойства SelectedDate, а затем мы используем ее для задания свойства Date, предоставленного ViewModel. Так как это свойство привязано к элементу управления TextBlock, который вы добавили ранее, можно увидеть дату, выбранную пользователем.

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

    По завершении конструктор AddNewExpenseViewModel должен выглядеть следующим образом.

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

    Примечание.

    Метод SaveExpenseCommand в том же файле кода выполняет сохранение статей расходов в базе данных. Этот метод использует свойство Date для создания нового объекта Expense. Теперь это свойство заполняется элементом управления CalendarView посредством только что созданного сообщения SelectedDateMessage.

  12. Нажмите клавишу F5, чтобы выполнить сборку приложения и открыть его в отладчике. Выберите одного из доступных сотрудников и нажмите кнопку Add new expense (Добавить новую статью расходов). Заполните все поля в форме и выберите дату в новом элементе управления CalendarView. Убедитесь, что выбранная дата отображается в виде строки под элементом управления.

  13. Нажмите кнопку Save (Сохранить). Форма будет закрыта, а новая статья расходов добавлена в конец списка расходов. Первым столбцом с датой расходов должна быть дата, выбранная в элементе управления CalendarView.

Следующие шаги

На этом этапе работы с руководством вы успешно заменили управляющий элемент даты и времени WPF с помощью элемента управления UWP CalendarView, который в дополнение к вводу с помощью мыши и клавиатуры поддерживает сенсорный ввод и ввод с помощью цифрового пера. Несмотря на то, что набор средств сообщества Windows не предоставляет упакованную версию элемента управления UWP CalendarView, которую можно использовать непосредственно в приложении WPF, вы смогли разместить этот элемент управления с помощью универсального элемента управления WindowsXamlHost.

Теперь вы готовы перейти к статье Часть 4. Добавление действий пользователей и уведомлений для Windows