Общие сведения о событиях и перенаправленных событияхEvents and routed events overview

Важные APIImportant APIs

Мы описываем концепцию программирования событий в среда выполнения Windows приложении, при использовании C#Visual Basic или расширений визуальных C++ компонентов (C++/CX) в качестве языка программирования, а также XAML для определения пользовательского интерфейса.We describe the programming concept of events in a Windows Runtime app, when using C#, Visual Basic or Visual C++ component extensions (C++/CX) as your programming language, and XAML for your UI definition. Обработчики событий можно назначить при объявлении элементов пользовательского интерфейса в XAML. Можно также добавить обработчики в код.You can assign handlers for events as part of the declarations for UI elements in XAML, or you can add the handlers in code. Среда выполнения Windows поддерживает перенаправленные события: отдельные события ввода и события данных могут обрабатываться не теми объектами, которые вызвали эти события.Windows Runtime supports routed events: certain input events and data events can be handled by objects beyond the object that fired the event. Перенаправленные события удобны при определении шаблонов элементов управления или использовании страниц либо контейнеров макета.Routed events are useful when you define control templates, or use pages or layout containers.

События как концепция программированияEvents as a programming concept

В общем случае концепции событий при программировании приложения среды выполнения Windows подобны модели событий в самых популярных языках программирования.Generally speaking, event concepts when programming a Windows Runtime app are similar to the event model in most popular programming languages. Если вы уже умеете работать с событиями Microsoft .NET или C++, вам будет проще.If you know how to work with Microsoft .NET or C++ events already, you have a head start. Но для того, чтобы выполнять такие простые задачи, как присоединение обработчиков, глубоких знаний о концепциях модели событий не требуется.But you don't need to know that much about event model concepts to perform some basic tasks, such as attaching handlers.

Если в качестве языка программирования вы используете C#, Visual Basic или C++/CX, пользовательский интерфейс определяется при помощи разметки (XAML).When you use C#, Visual Basic or C++/CX as your programming language, the UI is defined in markup (XAML). В синтаксисе разметки XAML некоторые принципы присоединения событий, возникших в элементах разметки, к сущностям в коде среды выполнения аналогичны другим веб-технологиям, например ASP.NET или HTML5.In XAML markup syntax, some of the principles of connecting events between markup elements and runtime code entities are similar to other Web technologies, such as ASP.NET, or HTML5.

Обратите внимание  , что код, который предоставляет логику среды выполнения для пользовательского интерфейса, определяемого XAML, часто называется кодом программной части или файлом кода программной части.Note  The code that provides the runtime logic for a XAML-defined UI is often referred to as code-behind or the code-behind file. В представлениях решений Microsoft Visual Studio это отношение изображено графически: файл кода программной части является зависимым и вложенным файлом в отличие от страницы XAML, на которую он ссылается.In the Microsoft Visual Studio solution views, this relationship is shown graphically, with the code-behind file being a dependent and nested file versus the XAML page it refers to.

Button.Click: введение в события и XAMLButton.Click: an introduction to events and XAML

Одной из самых распространенных задач программирования для приложений среды выполнения Windows является захват пользовательского ввода в пользовательском интерфейсе.One of the most common programming tasks for a Windows Runtime app is to capture user input to the UI. Например, в пользовательском интерфейсе может быть кнопка, которую пользователь должен нажать, чтобы отправить информацию или изменить состояние.For example, your UI might have a button that the user must click to submit info or to change state.

Интерфейс для приложения среды выполнения Windows определяется созданием кода XAML.You define the UI for your Windows Runtime app by generating XAML. Этот код XAML обычно выдается поверхностью разработки в Visual Studio.This XAML is usually the output from a design surface in Visual Studio. Вы также можете написать код XAML в простом текстовом редакторе или стороннем редакторе XAML.You can also write the XAML in a plain-text editor or a third-party XAML editor. При создании кода XAML вы можете подключить к отдельным элементам пользовательского интерфейса обработчики событий одновременно с определением всех остальных атрибутов XAML, которые устанавливают значения свойств этих элементов интерфейса.While generating that XAML, you can wire event handlers for individual UI elements at the same time that you define all the other XAML attributes that establish property values of that UI element.

Для подключения событий в XAML укажите в форме строки имя метода обработчика, который уже определен или будет определен позже в коде программной части.To wire the events in XAML, you specify the string-form name of the handler method that you've already defined or will define later in your code-behind. Например, следующий код XAML определяет объект Button с некоторыми свойствами (атрибут x:Name, Content), присвоенными в виде атрибутов, и подключает обработчик для события Click кнопки при помощи ссылки на метод, именуемый ShowUpdatesButton_Click:For example, this XAML defines a Button object with other properties (x:Name attribute, Content) assigned as attributes, and wires a handler for the button's Click event by referencing a method named ShowUpdatesButton_Click:

<Button x:Name="showUpdatesButton"
  Content="{Binding ShowUpdatesText}"
  Click="ShowUpdatesButton_Click"/>

Подсказка.   Подключение событий — это термин из области программирования.Tip  Event wiring is a programming term. Он относится к процессу или коду, при помощи которого вы обозначаете, что события должны вызывать метод обработчика с заданным именем.It refers to the process or code whereby you indicate that occurrences of an event should invoke a named handler method. В большинстве моделей кода процедур подключение событий представляет собой явный или неявный код «AddHandler», задающий имя событию и методу и обычно использующий экземпляр конечного объекта.In most procedural code models, event wiring is implicit or explicit "AddHandler" code that names both the event and method, and usually involves a target object instance. В языке XAML код «AddHandler» неявный, а подключение событий состоит исключительно в том, что событию присваивается имя, являющееся именем атрибута элемента объекта, а обработчику — имя, являющееся значением этого атрибута.In XAML, the "AddHandler" is implicit, and event wiring consists entirely of naming the event as the attribute name of an object element, and naming the handler as that attribute's value.

Вы создаете собственно обработчик событий на языке программирования, который вы используете для всего кода приложения и кода программной части.You write the actual handler in the programming language that you're using for all your app's code and code-behind. С помощью атрибута Click="ShowUpdatesButton_Click" вы создаете контракт, чтобы при компиляции и анализе XAML-документа как компиляция разметки XAML при операции сборки IDE, так и последующая операция анализа файла XAML при загрузке приложения могли найти метод с именем ShowUpdatesButton_Click.With the attribute Click="ShowUpdatesButton_Click", you have created a contract that when the XAML is markup-compiled and parsed, both the XAML markup compile step in your IDE's build action and the eventual XAML parse when the app loads can find a method named ShowUpdatesButton_Click as part of the app's code. ShowUpdatesButton_Click должен быть методом, реализующим совместимую сигнатуру метода (с использованием делегата) для любого обработчика события Click.ShowUpdatesButton_Click must be a method that implements a compatible method signature (based on a delegate) for any handler of the Click event. Например, следующий код определяет обработчик ShowUpdatesButton_Click.For example, this code defines the ShowUpdatesButton_Click handler.

private void ShowUpdatesButton_Click (object sender, RoutedEventArgs e) 
{
    Button b = sender as Button;
    //more logic to do here...
}
Private Sub ShowUpdatesButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim b As Button = CType(sender, Button)
    '  more logic to do here...
End Sub
void winrt::MyNamespace::implementation::BlankPage::ShowUpdatesButton_Click(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e)
{
    auto b{ sender.as<Windows::UI::Xaml::Controls::Button>() };
    // More logic to do here.
}
void MyNamespace::BlankPage::ShowUpdatesButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) 
{
    Button^ b = (Button^) sender;
    //more logic to do here...
}

В этом примере метод ShowUpdatesButton_Click основан на делегате RoutedEventHandler.In this example, the ShowUpdatesButton_Click method is based on the RoutedEventHandler delegate. Использовать нужно делегат, имя которого указано в синтаксисе для метода Click на странице справки MSDN.You'd know that this is the delegate to use because you'll see that delegate named in the syntax for the Click method on the MSDN reference page.

Совет. VisualStudio предоставляет удобный способ именования обработчика событий и определения метода обработчика при редактировании XAML.  Tip  Visual Studio provides a convenient way to name the event handler and define the handler method while you're editing XAML. Когда вы указываете имя атрибута для события в текстовом редакторе XAML, дождитесь отображения списка Microsoft IntelliSense.When you provide the attribute name of the event in the XAML text editor, wait a moment until a Microsoft IntelliSense list displays. После выбора из списка пункта <Новый обработчик событий> Microsoft Visual Studio предлагает имя метода, основанное на имени x:Name (или имени типа) элемента, имя события и числовой суффикс.If you click <New Event Handler> from the list, Microsoft Visual Studio will suggest a method name based on the element's x:Name (or type name), the event name, and a numeric suffix. Затем вы можете щелкнуть правой кнопкой мыши имя выбранного обработчика событий и выбрать Перейти к обработчику событий.You can then right-click the selected event handler name and click Navigate to Event Handler. При этом осуществляется переход прямо к вставленному определению обработчика событий, как показано в представлении вашего файла кода программной части для страницы XAML в редакторе кода.This will navigate directly to the newly inserted event handler definition, as seen in the code editor view of your code-behind file for the XAML page. Обработчик событий уже имеет правильную подпись, включая параметр sender и класс данных события, который использует событие.The event handler already has the correct signature, including the sender parameter and the event data class that the event uses. Если же метод обработчика с правильной подписью уже существует в вашем коде программной части, имя этого метода появляется в автоматически заполняющемся раскрывающемся списке вместе с параметром <Новый обработчик событий> .Also, if a handler method with the correct signature already exists in your code-behind, that method's name appears in the auto-complete drop-down along with the <New Event Handler> option. Вы также можете нажать клавишу TAB для быстрого вызова вместо того, чтобы щелкать элементы списка IntelliSense.You can also press the Tab key as a shortcut instead of clicking the IntelliSense list items.

Определение обработчика событийDefining an event handler

Для объектов, принадлежащих элементам пользовательского интерфейса и объявленных в XAML, код обработчика события определен в разделяемом классе, который служит кодом программной части для XAML-страницы.For objects that are UI elements and declared in XAML, event handler code is defined in the partial class that serves as the code-behind for a XAML page. Обработчики событий — это методы, которые вы создаете как часть разделяемого класса, который связан с вашим XAML.Event handlers are methods that you write as part of the partial class that is associated with your XAML. Эти обработчики событий основаны на делегатах, которые используются конкретным событием.These event handlers are based on the delegates that a particular event uses. Методы вашего обработчика событий могут быть общими или частными.Your event handler methods can be public or private. Закрытый доступ действует, потому что обработчик и экземпляр, созданные XAML, окончательно соединяются в процессе создания кода.Private access works because the handler and instance created by the XAML are ultimately joined by code generation. В целом мы рекомендуем делать методы обработчиков событий в классе частными.In general, we recommend that you make your event handler methods private in the class.

Обратите внимание  , C++ что обработчики событий для не определяются в разделяемых классах, они объявляются в заголовке как член закрытого класса.Note  Event handlers for C++ don't get defined in partial classes, they are declared in the header as a private class member. Действия при сборке для проекта C++ обеспечивают создание кода, поддерживающего систему типов XAML и модели кода программной части для C++.The build actions for a C++ project take care of generating code that supports the XAML type system and code-behind model for C++.

Параметр sender и данные событияThe sender parameter and event data

Обработчик, созданный вами для события, может обращаться к двум значениям, которые доступны как вводные при каждом вызове обработчика.The handler you write for the event can access two values that are available as input for each case where your handler is invoked. Первое значение — это sender, представляющий собой ссылку на объект, к которому прикреплен обработчик.The first such value is sender, which is a reference to the object where the handler is attached. Параметр sender типизирован как базовый тип Object.The sender parameter is typed as the base Object type. Часто используется такой прием, как преобразование sender в тип с большей точностью.A common technique is to cast sender to a more precise type. Этот прием полезен, если предполагаются проверки или изменения состояния самого объекта sender.This technique is useful if you expect to check or change state on the sender object itself. Исходя из проекта приложения вы выбираете тип, в который можно безопасно преобразовать sender, учитывая участок прикрепления обработчика или другую специфику проекта.Based on your own app design, you usually know a type that is safe to cast sender to, based on where the handler is attached or other design specifics.

Второе значение — это данные события, которые обычно включаются в определения синтаксиса как параметр e.The second value is event data, which generally appears in syntax definitions as the e parameter. Изучив параметр e делегата, который сопоставлен определенному обрабатываемому событию, можно выяснить, какие свойства доступны для данных события, а затем воспользоваться функцией IntelliSense или обозревателем объектов в Visual Studio.You can discover which properties for event data are available by looking at the e parameter of the delegate that is assigned for the specific event you are handling, and then using IntelliSense or Object Browser in Visual Studio. Можно также использовать справочную документацию среды выполнения Windows.Or you can use the Windows Runtime reference documentation.

Для некоторых событий значения определенных свойств данных события не менее важны, чем сам факт возникновения события.For some events, the event data's specific property values are as important as knowing that the event occurred. Это особенно верно для событий ввода.This is especially true of the input events. Для событий указателя может быть важна позиция указателя в момент возникновения события.For pointer events, the position of the pointer when the event occurred might be important. Для событий клавиатуры все возможные нажатия клавиш вызывают события KeyDown и KeyUp.For keyboard events, all possible key presses fire a KeyDown and KeyUp event. Чтобы определить, какую клавишу нажимает пользователь, необходимо обратиться к KeyRoutedEventArgs, который доступен для обработчика событий.To determine which key a user pressed, you must access the KeyRoutedEventArgs that is available to the event handler. Дополнительную информацию об обработке событий ввода см. в разделах Взаимодействие с помощью клавиатуры и Работа с данными указателя.For more info about handling input events, see Keyboard interactions and Handle pointer input. События и сценарии ввода часто имеют дополнительные особенности, которые в данном разделе не рассматриваются — например, захват указателя для событий указателя или клавиши-модификаторы и коды клавиш определенной платформы для событий клавиатуры.Input events and input scenarios often have additional considerations that are not covered in this topic, such as pointer capture for pointer events, and modifier keys and platform key codes for keyboard events.

Обработчики событий, использующие шаблон asyncEvent handlers that use the async pattern

В некоторых случаях вам может потребоваться использовать API, которые используют шаблон async внутри обработчика событий.In some cases you'll want to use APIs that use an async pattern within an event handler. Например, вы можете использовать Button в AppBar для отображения средства выбора файлов и взаимодействия с ним.For example, you might use a Button in an AppBar to display a file picker and interact with it. Однако следует помнить, что многие API средств выбора файлов являются асинхронными.However, many of the file picker APIs are asynchronous. Их нужно вызывать в области async/awaitable, при этом компилятор применит их.They have to be called within an async/awaitable scope, and the compiler will enforce this. Итак, что можно сделать, добавьте в обработчик событий ключевое слово Async , чтобы обработчик стал асинхронным void.So what you can do is add the async keyword to your event handler such that the handler is now async void. Теперь обработчику событий разрешено выполнять вызовы async/awaitable.Now your event handler is permitted to make async/awaitable calls.

Пример обработки событий взаимодействия с пользователем с помощью шаблона async см. в статье Доступ к файлам и средства выбора файлов (входит в цикл Создание первого приложения среды выполнения Windows на C# или Visual Basic).For an example of user-interaction event handling using the async pattern, see File access and pickers (part of theCreate your first Windows Runtime app using C# or Visual Basic series). См. также [Вызов асинхронных API в C].See also [Call asynchronous APIs in C).

Добавление обработчиков событий в программный кодAdding event handlers in code

XAML — не единственный способ присвоить объекту обработчик события.XAML is not the only way to assign an event handler to an object. Чтобы добавить обработчики событий к любому конкретному объекту в коде, в том числе к объектам, которые не используются в XAML, можно использовать синтаксис добавления обработчиков событий для конкретного языка программирования.To add event handlers to any given object in code, including to objects that are not usable in XAML, you can use the language-specific syntax for adding event handlers.

В C# синтаксис предусматривает использование оператора +=.In C#, the syntax is to use the += operator. Для регистрации обработчика справа от оператора добавляется ссылка на имя метода обработчика событий.You register the handler by referencing the event handler method name on the right side of the operator.

Если для добавления обработчиков событий к объектам, которые отображаются в пользовательском интерфейсе среды выполнения, используется код, обычно такие обработчики добавляют в ответ на событие жизненного цикла объекта или обратный вызов, например Loaded или OnApplyTemplate, чтобы обработчики событий в соответствующих объектах были готовы к инициируемым пользователем событиям во время выполнения.If you use code to add event handlers to objects that appear in the run-time UI, a common practice is to add such handlers in response to an object lifetime event or callback, such as Loaded or OnApplyTemplate, so that the event handlers on the relevant object are ready for user-initiated events at run time. Данный пример показывает каркас XAML для структуры страницы и затем предоставляет синтаксис языка C# для добавления к объекту обработчика событий.This example shows a XAML outline of the page structure and then provides the C# language syntax for adding an event handler to an object.

<Grid x:Name="LayoutRoot" Loaded="LayoutRoot_Loaded">
  <StackPanel>
    <TextBlock Name="textBlock1">Put the pointer over this text</TextBlock>
...
  </StackPanel>
</Grid>
void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    textBlock1.PointerEntered += textBlock1_PointerEntered;
    textBlock1.PointerExited += textBlock1_PointerExited;
}

Обратите внимание  , что существует более подробный синтаксис.Note  A more verbose syntax exists. В 2005 году в язык программирования C# была добавлена концепция вывода делегата, которая позволяет компилятору выводить новый экземпляр делегата и использовать более ранний простой синтаксис.In 2005, C# added a feature called delegate inference, which enables a compiler to infer the new delegate instance and enables the previous, simpler syntax. По функциональности подробный синтаксис идентичен приведенному в предыдущем примере, но явно создает новый экземпляр делегата до его регистрации, не пользуясь, таким образом, преимуществами вывода делегатов.The verbose syntax is functionally identical to the previous example, but explicitly creates a new delegate instance before registering it, thus not taking advantage of delegate inference. Этот подробный синтаксис не получил широкого распространения, но он все же представлен в некоторых примерах кода.This explicit syntax is less common, but you might still see it in some code examples.

void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
    textBlock1.PointerEntered += new PointerEventHandler(textBlock1_PointerEntered);
    textBlock1.PointerExited += new MouseEventHandler(textBlock1_PointerExited);
}

Синтаксис Visual Basic предусматривает две возможности добавления обработчика.There are two possibilities for Visual Basic syntax. Первая аналогична синтаксису C# и прикрепляет обработчики непосредственно к экземплярам.One is to parallel the C# syntax and attach handlers directly to instances. Для этого используется ключевое слово AddHandler и оператор AddressOf, который разыменовывает метод обработчика события.This requires the AddHandler keyword and also the AddressOf operator that dereferences the handler method name.

Второй вариант синтаксиса Visual Basic заключается в использовании ключевого слова Handles в обработчиках событий.The other option for Visual Basic syntax is to use the Handles keyword on event handlers. Этот способ подходит для случаев, когда предполагается существование обработчиков в объектах во время загрузки и на протяжении всего жизненного цикла объекта.This technique is appropriate for cases where handlers are expected to exist on objects at load time and persist throughout the object lifetime. Для использования Handles в объекте, определенном в XAML, необходимо указать Name / x:Name.Using Handles on an object that is defined in XAML requires that you provide a Name / x:Name. Это имя становится квалификатором экземпляра, который необходим для части Instance.Event синтаксиса Handles.This name becomes the instance qualifier that is needed for the Instance.Event part of the Handles syntax. В этом случае для того, чтобы прикрепить другие обработчики событий, нам не нужен обработчик событий, рассчитанный на жизненный цикл объекта; подключения Handles создаются при компиляции XAML-страницы.In this case you don't need an object lifetime-based event handler to initiate attaching the other event handlers; the Handles connections are created when you compile your XAML page.

Private Sub textBlock1_PointerEntered(ByVal sender As Object, ByVal e As PointerRoutedEventArgs) Handles textBlock1.PointerEntered
' ...
End Sub

Примечание  . Visual Studio и его поверхность проектирования XAML обычно передают метод обработки экземпляра вместо ключевого слова Handles .Note  Visual Studio and its XAML design surface generally promote the instance-handling technique instead of the Handles keyword. Причина заключается в том, что установка подключения обработчика событий в XAML является частью стандартного рабочего процесса дизайнер-разработчик, а подход с использованием ключевого слова Handles несовместим с подключением обработчиков событий в XAML.This is because establishing the event handler wiring in XAML is part of typical designer-developer workflow, and the Handles keyword technique is incompatible with wiring the event handlers in XAML.

В C++языке/CX также используется += синтаксис, но существуют отличия от базовой C# формы:In C++/CX, you also use the += syntax, but there are differences from the basic C# form:

  • Вывод делегатов не поддерживается, поэтому для экземпляра делегата необходимо использовать ref new.No delegate inference exists, so you must use ref new for the delegate instance.
  • Конструктор делегата имеет два параметра и требует в качестве первого параметра целевой объект.The delegate constructor has two parameters, and requires the target object as the first parameter. Обычно нужно определить this.Typically you specify this.
  • Конструктору делегата в качестве второго параметра необходим адрес метода, поэтому перед именем метода указан оператор ссылки & .The delegate constructor requires the method address as the second parameter, so the & reference operator precedes the method name.
textBlock1().PointerEntered({this, &MainPage::TextBlock1_PointerEntered });
textBlock1->PointerEntered += 
ref new PointerEventHandler(this, &BlankPage::textBlock1_PointerEntered);

Удаление обработчиков событий из кодаRemoving event handlers in code

Даже если вы добавили обработчики событий в код, то их не всегда требуется удалять.It's not usually necessary to remove event handlers in code, even if you added them in code. В соответствии с логикой времени жизни для большинства объектов среды выполнения Windows, например страниц и элементов управления, объекты уничтожаются при их отделении от основного объекта Window и его визуального дерева. При этом уничтожаются и ссылки делегата.The object lifetime behavior for most Windows Runtime objects such as pages and controls will destroy the objects when they are disconnected from the main Window and its visual tree, and any delegate references are destroyed too. В среде .NET объекты уничтожаются во время сборки мусора, а в среде выполнения Windows с компонентами расширения Visual C++ (C++/CX) по умолчанию используются слабые ссылки..NET does this through garbage collection and Windows Runtime with C++/CX uses weak references by default.

В некоторых случаях требуется явное удаление обработчиков событий.There are some rare cases where you do want to remove event handlers explicitly. К ним можно отнести следующие.These include:

  • Обработчики статических событий, которые невозможно удалить обычным способом.Handlers you added for static events, which can't get garbage-collected in a conventional way. Примеры статических событий в API среды выполнения Windows — события классов CompositionTarget и Clipboard.Examples of static events in the Windows Runtime API are the events of the CompositionTarget and Clipboard classes.
  • Проверяйте код, если синхронизация удаления обработчиков должна быть незамедлительной, а также в тех случаях, когда вы переключаете старый обработчик события на новый во время выполнения.Test code where you want the timing of handler removal to be immediate, or code where you what to swap old/new event handlers for an event at run time.
  • Реализация пользовательского метода доступа remove.The implementation of a custom remove accessor.
  • Пользовательские статические события.Custom static events.
  • Обработчики для перемещения по страницам.Handlers for page navigations.

FrameworkElement. выгруженные или Page. навигатедфром — это возможные триггеры событий, которые имеют соответствующие позиции в управлении состоянием и времени существования объектов, так что их можно использовать для удаления обработчиков для других событий.FrameworkElement.Unloaded or Page.NavigatedFrom are possible event triggers that have appropriate positions in state management and object lifetime such that you can use them for removing handlers for other events.

Например, можно удалить обработчик событий с именем _textblock1 поинтерентеред из целевого объекта textblock1 , используя этот код.For example, you can remove an event handler named textBlock1_PointerEntered from the target object textBlock1 using this code.

textBlock1.PointerEntered -= textBlock1_PointerEntered;
RemoveHandler textBlock1.PointerEntered, AddressOf textBlock1_PointerEntered

Также вы можете удалять обработчики, если событие было добавлено через атрибут XAML, что означает добавление обработчика в сформированный код.You can also remove handlers for cases where the event was added through a XAML attribute, which means that the handler was added in generated code. Если у вас есть значение Name для элемента, для которого был прикреплен обработчик, то удалить его будет проще, так как в коде создается ссылка на объект. Если объект не имеет Name, возможен вариант обхода дерева объектов для обнаружения ссылки на объект.This is easier to do if you provided a Name value for the element where the handler was attached, because that provides an object reference for code later; however, you could also walk the object tree in order to find the necessary object reference in cases where the object has no Name.

Если требуется удалить обработчик событий в C++/CX, то вам необходим токен регистрации, который может быть получен из возвращаемого значения регистрации обработчика событий +=.If you need to remove an event handler in C++/CX, you'll need a registration token, which you should've received from the return value of the += event handler registration. В синтаксисе C++/CX значение, используемое в правой стороне отмены регистрации -=, является токеном, а не названием метода.That's because the value you use for the right side of the -= deregistration in the C++/CX syntax is the token, not the method name. В C++/CX невозможно удалить обработчики, добавленные через атрибут XAML, так как в сформированном коде C++ токены не сохраняются.For C++/CX, you can't remove handlers that were added as a XAML attribute because the C++/CX generated code doesn't save a token.

Перенаправленные событияRouted events

Среда выполнения Windows c C#, Microsoft Visual Basic или C++/CX поддерживает концепцию перенаправленных событий для набора событий, которые имеются в большинстве элементов пользовательского интерфейса.The Windows Runtime with C#, Microsoft Visual Basic or C++/CX supports the concept of a routed event for a set of events that are present on most UI elements. Эти события выполняются для сценариев ввода и взаимодействия с пользователем и реализованы в базовом классе UIElement.These events are for input and user interaction scenarios, and they are implemented on the UIElement base class. Список событий ввода, которые являются перенаправленными:Here's a list of input events that are routed events:

Перенаправленное событие — это событие, которое можно передать (перенаправить) от дочернего объекта к каждому из его родительских объектов в последовательности дерева объектов.A routed event is an event that is potentially passed on (routed) from a child object to each of its successive parent objects in an object tree. Это дерево приблизительно соответствует XAML-структуре пользовательского интерфейса, причем корневой элемент дерева является корневым элементом в XAML.The XAML structure of your UI approximates this tree, with the root of that tree being the root element in XAML. Реальное дерево объектов может отличаться от элементов вложений XAML, так как это дерево объектов не содержит средств языка XAML, например тегов элементов свойств.The true object tree might vary somewhat from the XAML element nesting, because the object tree doesn't include XAML language features such as property element tags. Перенаправленные события можно представить как восходящую маршрутизацию событий от дочерних элементов объекта XAML, которые вызывают событие, к родительскому элементу объекта, который их содержит.You can conceive of the routed event as bubbling from any XAML object element child element that fires the event, toward the parent object element that contains it. Событие и его данные могут обрабатываться несколькими объектами по маршруту события.The event and its event data can be handled on multiple objects along the event route. Если элементы не имеют обработчиков, маршрут потенциально длится до достижения корневого элемента.If no element has handlers, the route potentially keeps going until the root element is reached.

Если у вас есть опыт использования веб-технологий, например Dynamic HTML (DHTML) или HTML5, возможно, концепция восходящей маршрутизации событий вам уже знакома.If you know Web technologies such as Dynamic HTML (DHTML) or HTML5, you might already be familiar with the bubbling event concept.

Когда перенаправленное событие передается вверх по маршруту события, все прикрепленные обработчики событий обращаются к общему экземпляру данных события.When a routed event bubbles through its event route, any attached event handlers all access a shared instance of event data. Следовательно, если обработчик событий может перезаписать какие-либо данные события, любые изменения, внесенные в данные события, будут переданы следующему обработчику, и, возможно, эти данные будут отличаться от исходных данных события, которые были переданы при возникновении события.Therefore, if any of the event data is writeable by a handler, any changes made to event data will be passed on to the next handler, and may no longer represent the original event data from the event. Если событие работает как перенаправленное, в справочной документации обязательно будут комментарии по этому поводу.When an event has a routed event behavior, the reference documentation will include remarks or other notations about the routed behavior.

Свойство OriginalSource элемента RoutedEventArgsThe OriginalSource property of RoutedEventArgs

Когда событие передается вверх по маршруту события, объект, в котором возникло событие, перестает быть sender.When an event bubbles up an event route, sender is no longer the same object as the event-raising object. Вместо этого sender становится объект, к которому прикреплен вызываемый в данный момент обработчик.Instead, sender is the object where the handler that is being invoked is attached.

В некоторых случаях вас может интересовать не sender, а информация о том, к какому из возможных дочерних объектов подведен указатель при запуске события указателя или какой объект пользовательского интерфейса оказывается в фокусе, когда пользователь нажимает клавишу на клавиатуре.In some cases, sender is not interesting, and you are instead interested in info such as which of the possible child objects the pointer is over when a pointer event fired, or which object in a larger UI held focus when a user pressed a keyboard key. В таких случаях используется значение свойства OriginalSource.For these cases, you can use the value of the OriginalSource property. В каждой точке маршрута OriginalSource сообщает информацию о первоначальном объекте, в котором возникло событие, а не об объекте, к которому прикреплен его обработчик.At all points on the route, OriginalSource reports the original object that fired the event, instead of the object where the handler is attached. Но для событий ввода UIElement этот первоначальный объект часто оказывается объектом, который не виден на уровне страницы определения пользовательского интерфейса XAML.However, for UIElement input events, that original object is often an object that is not immediately visible in the page-level UI definition XAML. Такой исходный объект может являться шаблонной частью элемента управления.Instead, that original source object might be a templated part of a control. Например, если пользователь подводит указатель мыши к самому краю Button, для большинства событий указателя OriginalSource является частью шаблона Border в Template, а не самой Button.For example, if the user hovers the pointer over the very edge of a Button, for most pointer events the OriginalSource is a Border template part in the Template, not the Button itself.

  Передача всплывающего события TIP особенно полезна, если вы создаете шаблонный элемент управления.Tip  Input event bubbling is especially useful if you are creating a templated control. Любому элементу управления, использующему шаблон, пользователь может назначить новый шаблон.Any control that has a template can have a new template applied by its consumer. При попытке повторно создать рабочий шаблон пользователь может непреднамеренно исключить некоторые обработки событий, объявленные в шаблоне по умолчанию.The consumer that's trying to recreate a working template might unintentionally eliminate some event handling declared in the default template. Тем не менее можно обеспечить обработку событий на уровне элемента управления, прикрепив обработчики в процессе переопределения OnApplyTemplate в определении класса.You can still provide control-level event handling by attaching handlers as part of the OnApplyTemplate override in the class definition. Далее можно перехватывать события ввода, следующие вверх по маршруту к корню элемента управления, в момент создания экземпляра.Then you can catch the input events that bubble up to the control's root on instantiation.

Свойство HandledThe Handled property

Некоторые классы данных события для определенных перенаправленных событий содержат свойство Handled.Several event data classes for specific routed events contain a property named Handled. Например, PointerRoutedEventArgs.Handled, KeyRoutedEventArgs.Handled, DragEventArgs.Handled.For examples, see PointerRoutedEventArgs.Handled, KeyRoutedEventArgs.Handled, DragEventArgs.Handled. Во всех случаях Handled — это настраиваемое свойство логического типа.In all cases Handled is a settable Boolean property.

Если задать для свойства Handled значение true, это повлияет на поведение системы событий.Setting the Handled property to true influences the event system behavior. Когда значение свойства Handled равно true, для большинства обработчиков событий перенаправление прекращается. Событие не передается дальше по маршруту и не уведомляет остальные прикрепленные обработчики об этом конкретном случае события.When Handled is true, the routing stops for most event handlers; the event doesn't continue along the route to notify other attached handlers of that particular event case. Какое событие считается «обработанным» и как приложение отвечает на обрабатываемое событие, решать вам.What "handled" means in the context of the event and how your app responds to it is up to you. По сути Handled представляет собой простой протокол, который позволяет коду приложения заявлять, что событию не требуется передаваться любым контейнерам. Логика приложения решает, какие действия должны быть выполнены.Basically, Handled is a simple protocol that enables app code to state that an occurrence of an event doesn't need to bubble to any containers, your app logic has taken care of what needs done. С другой стороны, необходимо быть уверенным, что не обрабатываются события, которым следует передаваться, чтобы могло выполняться поведение системы или элемента управления. Например, обработка низкоуровневых событий в элементах управления выбором может быть нежелательной.Conversely though, you do have to be careful that you aren't handling events that probably should bubble so that built-in system or control behaviors can act. For example, handling low-level events within the parts or items of a selection control can be detrimental. Элемент управления выбором может выполнять поиск событий ввода для изменения выбора.The selection control might be looking for input events to know that the selection should change.

Не для всех перенаправляемых событий можно отменить маршрут указанным способом. Такие события можно распознать, так как у них отсутствует свойство Handled.Not all of the routed events can cancel a route in this way, and you can tell that because they won't have a Handled property. Например, события GotFocus и LostFocus передаются, но они всегда полностью проходят весь маршрут до корневого элемента, а их классы данных события не имеют свойства Handled, которое могло бы изменить это поведение.For example, GotFocus and LostFocus do bubble, but they always bubble all the way to the root, and their event data classes don't have a Handled property that can influence that behavior.

Обработчики событий ввода в элементах управленияInput event handlers in controls

Специальные элементы управления среды выполнения Windows иногда неявным образом используют концепцию Handled для событий ввода.Specific Windows Runtime controls sometimes use the Handled concept for input events internally. Может показаться, что событие ввода никогда не происходит, потому что ваш пользовательский код не может обработать его.This can make it seem like an input event never occurs, because your user code can't handle it. Например, класс Button содержит логику, при помощи которой специально обрабатываются обычные события ввода PointerPressed.For example, the Button class includes logic that deliberately handles the general input event PointerPressed. Это сделано потому, что кнопки порождают событие Click, которое инициируется вводом при помощи мыши, а также другими режимами ввода, например обработкой таких клавиш, как ВВОД, которые могут вызвать срабатывание кнопки, когда она находится в фокусе.It does so because buttons fire a Click event that is initiated by pointer-pressed input, as well as by other input modes such as handling keys like the Enter key that can invoke the button when it's focused. В рамках проектирования классов Button необработанное событие ввода концептуально обрабатывается, и потребители класса — например, ваш пользовательский код, — могут вместо этого взаимодействовать с соответствующим элементу управления событием Click.For purposes of the class design of Button, the raw input event is conceptually handled, and class consumers such as your user code can instead interact with the control-relevant Click event. В разделах, посвященных классам элементов управления в API среды выполнения Windows, часто описывается поведение обработки событий, которое реализуется классом.Topics for specific control classes in the Windows Runtime API reference often note the event handling behavior that the class implements. В некоторых случаях можно изменить это поведение, переопределив методы OnEvent.In some cases, you can change the behavior by overriding OnEvent methods. Например, вы можете изменить реакцию производного класса TextBox на ввод с клавиатуры, переопределив Control.OnKeyDown.For example, you can change how your TextBox derived class reacts to key input by overriding Control.OnKeyDown.

Регистрация обработчиков для уже обработанных перенаправленных событийRegistering handlers for already-handled routed events

Ранее говорилось, что установка значения Handled для параметра true отменяет вызов большинства обработчиков.Earlier we said that setting Handled to true prevents most handlers from being called. Но метод AddHandler предоставляет способ, позволяющий прикрепить обработчик, который всегда вызывается для маршрута, даже если другие обработчики на предыдущих этапах маршрута установили значение true для Handled в общих данных события.But the AddHandler method provides a technique where you can attach a handler that is always invoked for the route, even if some other handler earlier in the route has set Handled to true in the shared event data. Этот способ полезен в том случае, если используемый элемент управления уже обработал событие внутренним образом или вследствие особой логики элемента управления,This technique is useful if a control you are using has handled the event in its internal compositing or for control-specific logic. но вы тем не менее хотите ответить на это событие в экземпляре элемента управления или выше по маршруту.but you still want to respond to it from a control instance, or your app UI. Используйте этот способ с осторожностью, потому что он может вступить в противоречие с назначением Handled и, возможно, нарушить механизм взаимодействия элемента управления.But use this technique with caution, because it can contradict the purpose of Handled and possibly break a control's intended interactions.

Способ обработки событий при помощи AddHandler можно использовать только для перенаправленных событий, имеющих соответствующий идентификатор перенаправленного события, так как этот идентификатор является обязательным входным значением для метода AddHandler.Only the routed events that have a corresponding routed event identifier can use the AddHandler event handling technique, because the identifier is a required input of the AddHandler method. Список событий, имеющих идентификатор перенаправленного события, можно найти в справочной документации по AddHandler.See the reference documentation for AddHandler for a list of events that have routed event identifiers available. Этот список событий почти совпадает со списком, представленным ранее.For the most part this is the same list of routed events we showed you earlier. Исключение состоит в том, что последние два в списке: Получение и потеря данных не имеют идентификатора перенаправленного события, поэтому для них нельзя использовать AddHandler .The exception is that the last two in the list: GotFocus and LostFocus don't have a routed event identifier, so you can't use AddHandler for those.

Перенаправленные события вне визуального дереваRouted events outside the visual tree

Некоторые объекты являются участниками отношения с главным визуальным деревом, что концептуально равносильно существованию наложений поверх основных визуальных элементов.Certain objects participate in a relationship with the primary visual tree that is conceptually like having an overlay over the main visuals. Такие объекты не являются частью обычных родительско-дочерних отношений, соединяющих все элементы дерева с визуальным корнем.These objects are not part of the usual parent-child relationships that connect all tree elements to the visual root. Это справедливо для любых отображаемых Popup или ToolTip.This is the case for any displayed Popup or ToolTip. Если вам нужно обрабатывать перенаправленные события от Popup или ToolTip, разместите обработчики в конкретных элементах пользовательского интерфейса, размещенных в Popup или ToolTip, а не в самих элементах Popup или ToolTip.If you want to handle routed events from a Popup or ToolTip, place the handlers on specific UI elements that are within the Popup or ToolTip and not the Popup or ToolTip elements themselves. Не полагайтесь на перенаправление внутри любой компоновки, которая выполняется для содержимого Popup или ToolTip, так какDon't rely on routing inside any compositing that is performed for Popup or ToolTip content. маршрутизация событий для перенаправленных событий работает только вдоль главного визуального дерева.This is because event routing for routed events works only along the main visual tree. Popup и ToolTip не рассматриваются как родительские или дочерние элементы пользовательского интерфейса и никогда не получают перенаправленное событие, даже если попытаться использовать что-нибудь вроде фона по умолчанию Popup в качестве области захвата для события ввода.A Popup or ToolTip is not considered a parent of subsidiary UI elements and never receives the routed event, even if it is trying to use something like the Popup default background as the capture area for input events.

Проверка попадания и события вводаHit testing and input events

Проверка нажатия определяет, в каком месте пользовательского интерфейса находится элемент и является ли он видимым для ввода с помощью мыши или пера либо для сенсорного ввода.Determining whether and where in UI an element is visible to mouse, touch, and stylus input is called hit testing. Для сенсорного ввода, а также событий, связанных с взаимодействием, или событий операций, которые являются следствием сенсорного ввода, элемент должен быть видимым для проверки нажатия. В таком случае элемент становится источником события и вызывает событие, сопоставленное с действием.For touch actions and also for interaction-specific or manipulation events that are consequences of a touch action, an element must be hit-test visible in order to be the event source and fire the event that is associated with the action. Иначе действие передается любым элементам, находящимся под этим элементом, или родительским элементам в визуальном дереве, способным к взаимодействию с вводом.Otherwise, the action passes through the element to any underlying elements or parent elements in the visual tree that could interact with that input. На проверку попадания влияет несколько факторов, но можно определить, может ли данный элемент вызывать события ввода, проверив его свойство IsHitTestVisible.There are several factors that affect hit testing, but you can determine whether a given element can fire input events by checking its IsHitTestVisible property. Это свойство возвращает значение true, только если элемент удовлетворяет следующим критериям:This property returns true only if the element meets these criteria:

  • Для его свойства Visibility установлено значение Visible.The element's Visibility property value is Visible.
  • Значение свойства элемента Background или Fill не равно null.The element's Background or Fill property value is not null. Значение null кисти приводит к прозрачности и невидимости проверки попадания.A null Brush value results in transparency and hit test invisibility. (Чтобы сделать элемент прозрачным, но доступным для проверки нажатия, используйте значение свойства кисти Transparent, а не null.)(To make an element transparent but also hit testable, use a Transparent brush instead of null.)

Примечание.   Background и Fill не определены элементом UIElement, а определены различными производными классами, например Control и Shape.Note  Background and Fill aren't defined by UIElement, and are instead defined by different derived classes such as Control and Shape. Но применения кистей, которые вы используете для свойств переднего и заднего планов, одинаковы для проверки нажатия и событий ввода, независимо от того, какой подкласс реализует свойства.But the implications of brushes you use for foreground and background properties are the same for hit testing and input events, no matter which subclass implements the properties.

  • Если элемент является элементом управления, для его свойства IsEnabled должно быть установлено значение true.If the element is a control, its IsEnabled property value must be true.
  • У элемента в макете должны быть фактические размеры.The element must have actual dimensions in layout. Элемент, ActualHeight и ActualWidth которого равны 0, не вызывает события ввода.An element where either ActualHeight and ActualWidth are 0 won't fire input events.

Некоторые элементы управления имеют особые правила для проверки нажатия.Some controls have special rules for hit testing. Например, TextBlock не обладает свойством Background, но доступен для проверки нажатия в пределах границ его площади.For example, TextBlock has no Background property, but is still hit testable within the entire region of its dimensions. Проверка попадания элементов управления Image и MediaElement осуществляется по определенным размерам прямоугольника независимо от прозрачного содержимого, такого как альфа-канал в отображаемом медиа-файле источника данных.Image and MediaElement controls are hit testable over their defined rectangle dimensions, regardless of transparent content such as alpha channel in the media source file being displayed. Элементы управления WebView имеют особое поведение проверки нажатия, так как входные данные могут обрабатываться размещаемыми HTML и событиями скрипта.WebView controls have special hit testing behavior because the input can be handled by the hosted HTML and fire script events.

Большинство классов Panel и Border недоступны для проверки нажатия в фоновом режиме, но могут обрабатывать события ввода, перенаправляемые от элементов, которые они содержат.Most Panel classes and Border are not hit-testable in their own background, but can still handle the user input events that are routed from the elements that they contain.

Вы можете определить элементы, расположенные на той же позиции, что и событие пользовательского ввода, несмотря на наличие или отсутствие возможности проверки нажатия для этих элементов.You can determine which elements are located at the same position as a user input event, regardless of whether the elements are hit-testable. Для этого вызовите метод FindElementsInHostCoordinates.To do this, call the FindElementsInHostCoordinates method. Как видно из названия, этот метод находит элементы по положению относительно определенных основных элементов.As the name implies, this method finds the elements at a location relative to a specified host element. Но применяемые преобразования и изменения макета могут изменить систему относительных координат элемента и таким образом повлиять на то, какие элементы будут найдены в данном положении.However, applied transforms and layout changes can adjust the relative coordinate system of an element, and therefore affect which elements are found at a given location.

Командные элементыCommanding

Немногие элементы пользовательского интерфейса поддерживают командный интерфейс.A small number of UI elements support commanding. Командный интерфейс использует относящиеся к вводу перенаправленные события в своей базовой реализации и обеспечивает обработку относящегося к пользовательскому интерфейсу ввода (конкретное действие указателя, конкретное сочетание клавиш) вызовом единого обработчика команд.Commanding uses input-related routed events in its underlying implementation and enables processing of related UI input (a certain pointer action, a specific accelerator key) by invoking a single command handler. Если для элемента пользовательского интерфейса доступен командный интерфейс, рекомендуем использовать соответствующие API командного интерфейса вместо любых дискретных событий ввода.If commanding is available for a UI element, consider using its commanding APIs instead of any discrete input events. Обычно используется ссылка Binding на свойства класса, который определяет модель просмотра данных.You typically use a Binding reference into properties of a class that defines the view model for data. Свойства содержат именованные команды, которые реализуют языковой шаблон команд ICommand.The properties hold named commands that implement the language-specific ICommand commanding pattern. Подробнее: ButtonBase.Command.For more info, see ButtonBase.Command.

Пользовательские события в среде выполнения WindowsCustom events in the Windows Runtime

В рамках пользовательских событий способ добавления события и оказываемый эффект этого добавления на проектирование классов очень сильно зависят от используемого языка программирования.For purposes of defining custom events, how you add the event and what that means for your class design is highly dependent on which programming language you are using.

  • Для языков C# и Visual Basic вы определяете событие среды CLR.For C# and Visual Basic, you are defining a CLR event. Если вы не используете пользовательские методы доступа (add/remove), то вы можете использовать стандартный шаблон событий среды .NET.You can use the standard .NET event pattern, so long as you aren't using custom accessors (add/remove). Дополнительные советы.Additional tips:
  • Для C++/CX см. События в C++/CX.For C++/CX, see Events (C++/CX).
    • Присваивайте имена ссылкам даже при использовании собственных пользовательских событий.Use named references even for your own usages of custom events. Не используйте лямбда-выражения для пользовательских событий — может возникнуть циклическая ссылка.Don't use lambda for custom events, it can create a circular reference.

Невозможно объявить пользовательское перенаправленное событие для среды выполнения Windows. Перенаправленные события ограничены набором из среды выполнения Windows.You can't declare a custom routed event for Windows Runtime; routed events are limited to the set that comes from the Windows Runtime.

Определение пользовательского события обычно является частью задачи на определение пользовательского элемента управления.Defining a custom event is usually done as part of the exercise of defining a custom control. Общий шаблон выглядит следующим образом: имеется свойство зависимостей с возможностью обратного вызова при изменении свойства. Также имеется возможность определить пользовательское событие, которое порождается обратным вызовом свойства зависимостей в некоторых или во всех классах.It's a common pattern to have a dependency property that has a property-changed callback, and to also define a custom event that's fired by the dependency property callback in some or all cases. Пользователи вашего элемента управления не имеют доступа к определенному вами обратному вызову при изменении свойства, но лучше иметь возможность получать события уведомления.Consumers of your control don't have access to the property-changed callback you defined, but having a notification event available is the next best thing. Дополнительную информацию см. в разделе Пользовательские свойства зависимостей.For more info, see Custom dependency properties.