- Часть 4. Добавление действий пользователей и уведомлений для Windows 10 Part 4: Add Windows 10 user activities and notifications
- Добавление действия пользователя Add a user activity
- Введение в адаптивные карточки Introduction to Adaptive Cards
- Добавление адаптивной карточки Add an Adaptive Card
- О коде About the code
- Определение действия пользователя Define the user activity
- О коде About the code
- Интеграция приложения с временной шкалой Integrate the application with Timeline
- Добавление уведомления Add a notification
- Дальнейшие действия Next steps
Часть 4. Добавление действий пользователей и уведомлений для Windows 10 Part 4: Add Windows 10 user activities and notifications
Это четвертая часть руководства, в которой рассматривается модернизация примера классического приложения WPF, которое называется Contoso Expenses. This is the fourth part of a tutorial that demonstrates how to modernize a sample WPF desktop app named Contoso Expenses. Общие сведения об этом руководстве, предварительные требования и инструкции по скачиванию примера приложения см. в разделе Руководство. Модернизация приложения WPF. For an overview of the tutorial, prerequisites, and instructions for downloading the sample app, see Tutorial: Modernize a WPF app. В этой статье предполагается, что вы уже выполнили часть 3. This article assumes you have already completed part 3.
В предыдущих частях этого руководства вы добавили в приложение элементы управления UWP XAML, используя области XAML. In the previous parts of this tutorial you added UWP XAML controls to the app using XAML Islands. В результате этого вы также обеспечили возможность вызова любого API WinRT в приложении. As a by product of this, you also enabled the app to call any WinRT API. Это позволяет приложению использовать множество других функций, предлагаемых Windows 10, а не только элементы управления UWP XAML. This opens up the opportunity for the app to use many other features offered by Windows 10, not just UWP XAML controls.
В вымышленном сценарии, рассматриваемом в этом руководстве, группа разработки Contoso решила добавить в приложение две новые функции: действия и уведомления. In the fictional scenario of this tutorial, the Contoso development team has decided to add two new features to the app: activities and notifications. В этой части руководства показано, как реализовать данные функции. This part of the tutorial shows how to implement these features.
Добавление действия пользователя Add a user activity
В Windows 10 приложения могут отслеживать действия, выполняемые пользователем, например открытие файла или просмотр определенной страницы. In Windows 10, apps can track activities performed by the user such as opening a file or displaying a specific page. Затем эти действия добавляются на временную шкалу — компонент, появившийся в Windows 10 версии 1803. Временная шкала позволяет пользователю быстро вернуться к начатому ранее действию и возобновить его выполнение. These activities are then made available through Timeline, a feature introduced in Windows 10 version 1803, which allows the user to quickly go back to the past and resume an activity they started previously.
Для отслеживания действий пользователя используется Microsoft Graph. User activities are tracked using Microsoft Graph. Однако при создании приложения Windows 10 вам не нужно напрямую взаимодействовать с конечными точками REST, предоставленными Microsoft Graph. However, when you’re building a Windows 10 app, you don’t need to interact directly with the REST endpoints provided by Microsoft Graph. Вместо этого можно использовать удобный набор API WinRT. Instead, you can use a convenient set of WinRT APIs. Мы будем использовать эти API WinRT в приложении Contoso Expenses, чтобы отслеживать, когда пользователь открывает страницу расходов в приложении, и использовать адаптивные карточки, чтобы пользователи могли создавать действия. We’re going to use these WinRT APIs in the Contoso Expenses app to track every time the user opens an expense within the app, and use Adaptive Cards to enable users to create the activity.
Введение в адаптивные карточки Introduction to Adaptive Cards
В этом разделе кратко описываются адаптивные карточки. This section provides a brief overview of Adaptive Cards. Если эти сведения вам не нужны, можно пропустить данный раздел и сразу перейти к инструкциям по добавлению адаптивной карточки. If you don’t need this information, you can skip this and go right to the add an Adaptive Card instructions.
Адаптивные карточки дают разработчикам возможность обмениваться содержимым карточек обычным и стандартным способом. Adaptive Cards enable developers to exchange card content in a common and consistent way. Адаптивная карточка описывается полезными данными JSON, определяющими ее содержимое: текст, изображения, действия и многое другое. An Adaptive Card is described by a JSON payload that defines its content, which can include text, images, actions, and more.
Адаптивная карточка определяет только содержимое, а не его внешний вид. An Adaptive Card defines just the content and not the visual appearance of the content. Платформа, в которой получена адаптивная карточка, может визуализировать ее содержимое с помощью наиболее подходящего стиля. The platform where the Adaptive Card is received can render the content using the most appropriate styling. В основе адаптивных карточек лежит отрисовщик, который может принять полезные данные JSON и преобразовать их в собственный пользовательский интерфейс. The way Adaptive Cards are designed is through a renderer, which is able to take the JSON payload and to convert it into native UI. Например, это может быть пользовательский интерфейс XAML для приложения WPF или UWP, пользовательский интерфейс AXML для приложения Android или пользовательский интерфейс HTML для веб-сайта или чат-бота. For example, the UI could be XAML for a WPF or UWP app, AXML for an Android app, or HTML for a website or a bot chat.
Ниже приведен пример простых полезных данных адаптивной карточки. Here is an example of a simple Adaptive Card payload.
На рисунке ниже показано, как этот код JSON визуализируется различными способами — в канале Teams, Кортане и уведомлении Windows. The image below shows how this JSON is rendered in different ways by ta Teams channel, Cortana and a Windows notification.
Адаптивные карточки играют важную роль на временной шкале, так как определяют способ отображения действий в Windows. Adaptive cards play an important role in Timeline because it’s the way Windows renders activities. Каждый эскиз, отображаемый во временной шкале, на самом деле является адаптивной карточкой. Each thumbnail displayed inside Timeline is actually an Adaptive Card. Таким образом, когда вы соберетесь создать действие пользователя в приложении, вам будет предложено предоставить адаптивную карточку для его визуализации. As such, when you’re going to create a user activity inside your app, you will be asked to provide an Adaptive Card to render it.
Для мозгового штурма оформления адаптивной карточки удобно использовать конструктор в Интернете. A great way to brainstorm the design of an Adaptive Card is using the online designer. Вы сможете спроектировать карточку с помощью стандартных блоков (изображений, блоков текста, столбцов и т. д.) и получить соответствующий код JSON. You will have the chance to design the card with building blocks (images, texts, columns, etc) and get the corresponding JSON. Окончательно выбрав оформление, вы сможете использовать библиотеку Adaptive Cards, чтобы упростить создание адаптивной карточки с помощью классов C# вместо простого кода JSON, отладка и сборка которого сопряжена со сложностями. After you have an idea of the final design, you can use a library called Adaptive Cards to make it easier to build your Adaptive Card using C# classes instead of plain JSON, which might be hard to debug and build.
Добавление адаптивной карточки Add an Adaptive Card
Щелкните правой кнопкой мыши проект ContosoExpenses.Core в Обозревателе решений и выберите Управление пакетами NuGet. Right click on the ContosoExpenses.Core project in Solution Explorer and choose Manage NuGet packages.
В окне диспетчера пакетов NuGet щелкните Обзор. In the NuGet Package Manager window, click Browse. Найдите пакет Newtonsoft.Json и установите последнюю доступную версию. Search for the Newtonsoft.Json package and install the latest available version. Это популярная библиотека для работы с JSON, с помощью которой вы будете обрабатывать строки JSON, необходимые для адаптивных карточек. This is a popular JSON manipulation library that you will use to help mainipulate the JSON strings required by Adaptive Cards.
Если не установить пакет Newtonsoft.Json отдельно, библиотека Adaptive Cards будет ссылаться на более раннюю версию пакета Newtonsoft.Json , который не поддерживает платформу .NET Core 3.0. If you don’t install the Newtonsoft.Json package separately, The Adaptive Cards library will reference an older version of the Newtonsoft.Json package that doesn’t support .NET Core 3.0.
В окне диспетчера пакетов NuGet щелкните Обзор. In the NuGet Package Manager window, click Browse. Найдите пакет AdaptiveCards и установите последнюю доступную версию. Search for the AdaptiveCards package and install the latest available version.
В обозревателе решений щелкните правой кнопкой мыши проект ContosoExpenses.Core и выберите Добавить > Класс. In Solution Explorer, right-click the ContosoExpenses.Core project, choose Add -> Class. Присвойте классу имя TimelineService.cs и нажмите кнопку ОК. Name the class TimelineService.cs and click OK.
В начало файла TimelineService.cs добавьте следующие операторы. In the TimelineService.cs file, add the following statements to the top of the file.
Измените пространство имен ContosoExpenses.Core , объявленное в файле, на ContosoExpenses . Change the namespace declared in the file from ContosoExpenses.Core to ContosoExpenses .
Добавьте следующий метод в класс TimelineService . Add the following method to the TimelineService class.
О коде About the code
Этот метод получает объект Expense со всеми сведениями о затратах для визуализации и создает объект AdaptiveCard. This method receives an Expense object with all the information about the expense to render and it builds a new AdaptiveCard object. Этот метод добавляет в карточку: The method adds the following to the card:
- заголовок, содержащий описание расходов; A title, which uses the description of the expense.
- изображение — логотип Contoso; An image, which is the Contoso logo.
- сумму расходов; The amount of the expense.
- дату расходов. The date of the expense.
Последние 3 элемента разбиты на два отдельных столбца, чтобы логотип Contoso и подробные сведения о расходах можно было разместить параллельно. The last 3 elements are split into two different columns, so that the Contoso logo and the details about the expense can be placed side by side. После создания объекта метод возвращает соответствующую строку JSON с помощью метода ToJson. After the object is built, the method returns the corresponding JSON string with the help of the ToJson method.
Определение действия пользователя Define the user activity
Теперь, когда вы определили адаптивную карточку, на ее основе можно создать действие пользователя. Now that you have defined the Adaptive Card, you can create a user activity based on it.
В начало файла TimelineService.cs добавьте следующие операторы. Add the following statements to the top of TimelineService.cs file:
Это пространства имен UWP. These are UWP namespaces. Они разрешаются, так как пакет NuGet Microsoft.Toolkit.Wpf.UI.Controls , установленный на шаге 2, содержит ссылку на пакет Microsoft.Windows.SDK.Contracts . Это позволяет проекту ContosoExpenses.Core ссылаться на интерфейсы API WinRT, даже если это проект на основе .NET Core 3. These resolve because the Microsoft.Toolkit.Wpf.UI.Controls NuGet package that you installed in step 2 includes a reference to the Microsoft.Windows.SDK.Contracts package, which enables the ContosoExpenses.Core project to reference WinRT APIs even though it is a .NET Core 3 project.
Добавьте в класс TimelineService приведенные ниже объявления полей. Add the following field declarations to the TimelineService class.
Добавьте следующий метод в класс TimelineService . Add the following method to the TimelineService class.
Сохраните изменения в файле TimelineService.cs. Save the changes to TimelineService.cs.
О коде About the code
Метод AddToTimeline сначала получает объект UserActivityChannel, необходимый для хранения действий пользователя. The AddToTimeline method first gets a UserActivityChannel object that is required to store user activities. Затем он создает действие пользователя с помощью метода GetOrCreateUserActivityAsync, для чего требуется уникальный идентификатор. Then it creates a new user activity using the GetOrCreateUserActivityAsync method, which requires a unique identifier. В этом случае, если действие уже существует, приложение сможет его обновить. В противном случае будет создано новое действие. This way, if an activity already exists, the app can update it; otherwise it will create a new one. Передаваемый идентификатор зависит от типа приложения, которое вы создаете. The identifier to pass depends by the kind of application you’re building:
- Если вы хотите постоянно обновлять одно и то же действие, чтобы на временной шкале отображалось только самое последнее действие, можно использовать фиксированный идентификатор (например, Expenses). If you want to always update the same activity so that Timeline will only show the most recent one, you can use a fixed identifier (such as Expenses).
- Если вы хотите отслеживать каждое действие по отдельности, чтобы они все отображались на временной шкале, можно использовать динамический идентификатор. If you want to track every activity as a different one, so that Timeline will display all of them, you can use a dynamic identifier.
В этом случае приложение будет отслеживать каждую открытую статью расходов как отдельное действие пользователя, поэтому код создает каждый идентификатор с помощью ключевого слова Expense- , за которым следует уникальный идентификатор расходов. In this scenario, the app will track each opened expense as a different user activity, so the code creates each identifier by using the keyword Expense- followed by the unique expense ID.
После того как метод создает объект UserActivity и заполняет его следующими сведениями. After the method creates a UserActivity object, it populates the object with the following info:
- Идентификатор ActivationUri, который вызывается, когда пользователь щелкает действие на временной шкале. An ActivationUri that is invoked when the user clicks on the activity in Timeline. В коде используется настраиваемый протокол contosoexpenses, который приложение обработает позже. The code uses a custom protocol called contosoexpenses that the app will handle later.
- Объект VisualElements, который содержит набор свойств, определяющих внешний вид действия. The VisualElements object, which contains a set of properties that define the visual appearance of the activity. Этот код задает DisplayText (заголовок, отображаемый в верхней части записи на временной шкале) и Content. This code sets the DisplayText (which is the title displayed on top of the entry in Timeline) and the Content.
Именно здесь в действие вступает адаптивная карточка, определенная ранее. This is where the Adaptive Card you defined earlier plays a role. Приложение передает в метод адаптивную карточку, которая была разработана ранее, в качестве содержимого. The app passes the Adaptive Card you designed earlier as content to the method. Однако в Windows 10 для представления карточки используется объект, отличный от аналогичного объекта в пакете NuGet AdaptiveCards . However, Windows 10 uses a different object to represent a card compared to the one used by the AdaptiveCards NuGet package. Таким образом, метод повторно создает карточку с помощью метода CreateAdaptiveCardFromJson, предоставляемого классом AdaptiveCardBuilder. Therefore, the method recreates the card by using the CreateAdaptiveCardFromJson method exposed by the AdaptiveCardBuilder class. После того как метод создает действие пользователя, он сохраняет действие и создает новый сеанс. After the method creates the user activity, it saves the activity and creates a new session.
Когда пользователь щелкает действие на временной шкале, активируется протокол contosoexpenses:// , а URL-адрес будет содержать сведения, необходимые приложению для получения выбранной статьи расходов. When a user clicks on an activity in Timeline, the contosoexpenses:// protocol will be activated and the URL will include the information the app needs to retrieve the selected expense. В качестве дополнительной задачи можно реализовать активацию протокола, чтобы приложение правильно реагировало, когда пользователь использует временную шкалу. As an optional task, you could implement the protocol activation so that the application reacts properly when the user uses Timeline.
Интеграция приложения с временной шкалой Integrate the application with Timeline
Теперь, когда вы создали класс, взаимодействующий с временной шкалой, мы можем использовать его для улучшения работы приложения. Now that you have created a class that interacts with Timeline, we can start using it to enhance the application’s experience. Лучше всего использовать метод AddToTimeline, предоставляемый классом TimelineService, когда пользователь открывает страницу сведений о расходах. The best place to use the AddToTimeline method exposed by the TimelineService class is when the user opens the detail page of an expense.
В проекте ContosoExpenses.Core разверните папку ViewModels и откройте файл ExpenseDetailViewModel.cs. In the ContosoExpenses.Core project, expand the ViewModels folder and open the ExpenseDetailViewModel.cs file. Это объект ViewModel, который поддерживает окно сведений о расходах. This is the ViewModel that supports the expense detail’s window.
Найдите общедоступный конструктор класса ExpenseDetailViewModel и добавьте в его конец приведенный ниже код. Locate the public constructor of the ExpenseDetailViewModel class and add the following code at the end of the constructor. При открытии окна расходов этот метод вызывает метод AddToTimeline и передает текущие данные расходов. Whenever the expense window is opened, the method calls the AddToTimeline method and passes the current expense. Класс TimelineService использует эти данные для создания действия пользователя на основе сведений о расходах. The TimelineService class uses this info to create a user activity using the expense information.
По завершении конструктор должен выглядеть следующим образом. When you are done, the constructor should look like this.
Нажмите клавишу F5, чтобы выполнить сборку приложения и открыть его в отладчике. Press F5 to build and run the app in the debugger. Выберите сотрудника из списка, а затем выберите одну из статей расходов. Choose an employee from the list and then choose an expense. На странице сведений обратите внимание на описание, дату и сумму расходов. In the detail page, note the description of the expense, the date and the amount.
Нажмите Пуск + TAB, чтобы открыть временную шкалу. Press Start + TAB to open Timeline.
Прокрутите вниз список открытых приложений, пока не увидите раздел Ранее сегодня. Scroll down the list of currently opened applications until you see the section titled Earlier today. В этом разделе показаны некоторые из последних действий пользователя. This section shows some of your most recent user activities. Щелкните ссылку Просмотреть все действия рядом с заголовком Ранее сегодня. Click the See all activities link next to the Earlier today heading.
Убедитесь, что вы видите новую карточку со сведениями о расходах, которые вы только что выбрали в приложении. Confirm that you see a new card with the information about the expense you have just selected in the application.
Если теперь открыть другую статью расходов, вы увидите, как добавятся новые карты в качестве действий пользователя. If you now open other expenses, you will see new cards being added as user activities. Помните, что код использует разные идентификаторы для каждого действия, поэтому он создает карточку для каждой статьи расходов, открываемой в приложении. Remember that the code uses a different identifier for each activity, so it creates a card for each expense you open in the app.
Закройте приложение. Close the app.
Добавление уведомления Add a notification
Второй компонент, который группа разработки Contoso хочет добавить, — это уведомление, отображаемое пользователю при каждом сохранении новой статьи расходов в базе данных. The second feature the Contoso development team wants to add is a notification that is shown to the user whenever a new expense is saved to the database. Для этого можно использовать встроенную систему уведомлений Windows 10, которая предоставляется разработчикам через интерфейсы API WinRT. To do this, you can leverage the built-in notifications system in Windows 10, which is exposed to developers via WinRT APIs. Эта система уведомлений имеет множество преимуществ: This notification system has many advantages:
- уведомления согласованы с остальной частью операционной системы; Notifications are consistent with the rest of the OS.
- они позволяют действовать; They are actionable.
- они сохраняются в центре уведомлений, поэтому их можно просмотреть позже. They get stored in Action Center so they can be reviewed later.
Чтобы добавить уведомление в приложение: To add a notification to the app:
В обозревателе решений щелкните правой кнопкой мыши проект ContosoExpenses.Core и выберите Добавить > Класс. In Solution Explorer, right-click the ContosoExpenses.Core project, choose Add -> Class. Присвойте классу имя NotificationService.cs и нажмите кнопку ОК. Name the class NotificationService.cs and click OK.
В начало файла NotificationService.cs добавьте следующие операторы. In the NotificationService.cs file, add the following statements to the top of the file.
Измените пространство имен ContosoExpenses.Core , объявленное в файле, на ContosoExpenses . Change the namespace declared in the file from ContosoExpenses.Core to ContosoExpenses .
Добавьте следующий метод в класс NotificationService . Add the following method to the NotificationService class.
Всплывающие уведомления представлены в виде полезных данных XML, которые могут содержать текст, изображения, действия и многое другое. Toast notifications are represented by an XML payload, which can include text, images, actions, and more. Все поддерживаемые элементы описаны здесь. You can find all the supported elements here. Этот код использует очень простую схему с двумя строками текста: заголовком и основным текстом. This code uses a very simple schema with two lines of text: the title and the body. После того как код определит полезные данные XML и загрузит их в объект XmlDocument, он поместит эти данные XML в объект ToastNotification и отобразит его с помощью класса ToastNotificationManager. After the code defines the XML payload and loads it in a XmlDocument object, it wraps the XML in a ToastNotification object and shows it by using a the ToastNotificationManager class.
В проекте ContosoExpenses.Core разверните папку ViewModels и откройте файл AddNewExpenseViewModel.cs. In the ContosoExpenses.Core project, expand the ViewModels folder and open the AddNewExpenseViewModel.cs file.
Выберите метод SaveExpenseCommand , который активируется при нажатии пользователем кнопки для сохранения новой статьи расходов. Locate the SaveExpenseCommand method, which is triggered when the user presses on the button to save a new expense. Добавьте в этом метод приведенный ниже код, сразу после вызова метода SaveExpense . Add the following code to this method, just after the call to the SaveExpense method.
По завершении метод SaveExpenseCommand должен выглядеть следующим образом. When you are done, the SaveExpenseCommand method should look like this.
Нажмите клавишу F5, чтобы выполнить сборку приложения и открыть его в отладчике. Press F5 to build and run the app in the debugger. Выберите из списка сотрудника и нажмите кнопку Add new expense (Добавить новую статью расходов). Choose an employee from the list and then click the Add new expense button. Заполните все поля в этой форме и щелкните Save (Сохранить). Complete all fields in the form and press Save.
Будет порождено исключение, как показано ниже. You will receive the following exception.
Это исключение вызвано тем, что у приложения Contoso Expenses еще нет идентификатора пакета. This exception is caused by the fact that the Contoso Expenses app doesn’t yet have package identity. Для использования в приложении некоторых API WinRT, включая API уведомлений, требуется идентификатор пакета. Some WinRT APIs, including the notifications API, require package identity before they can be used in an app. Приложения UWP получают идентификатор пакета по умолчанию, так как они могут распространяться только через пакеты MSIX. UWP apps receive package identity by default because they can only be distributed via MSIX packages. Другие типы приложений для Windows, включая приложения WPF, также можно разворачивать с помощью пакетов MSIX, чтобы получить идентификатор пакета. Other types of Windows apps, including WPF apps, can also be deployed via MSIX packages to obtain package identity. В следующей части этого руководства будет описано, как это сделать. The next part of this tutorial will explore how to do this.
Дальнейшие действия Next steps
На этом этапе работы с руководством вы успешно добавили действие пользователя в приложение, которое интегрируется с временной шкалой Windows, а также добавили в это приложение уведомление, которое активируется при создании новой статьи расходов пользователями. At this point in the tutorial, you have successfully added a user activity to the app that integrates with Windows Timeline, and you have also added a notification to the app that is triggered when users create a new expense. Однако это уведомление еще не работает, так как приложению требуется идентификатор пакета для использования API уведомлений. However, the notification doesn’t yet work because the app requires package identity to use the notifications API. Сведения о том, как создать пакет MSIX для приложения, чтобы получить идентификатор пакета и воспользоваться другими преимуществами развертывания, приведены в разделе Часть 5. Упаковка и развертывание с помощью MSIX To learn how to build an MSIX package for the app to obtain package identity and gain other deployment benefits, see Part 5: Package and deploy with MSIX.