EventSource Класс
Определение
Важно!
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Предоставляет возможность создавать события для трассировки событий на разных платформах.
public ref class EventSource : IDisposable
public class EventSource : IDisposable
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes)]
public class EventSource : IDisposable
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)]
public class EventSource : IDisposable
type EventSource = class
interface IDisposable
[<System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicNestedTypes)>]
type EventSource = class
interface IDisposable
[<System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)>]
type EventSource = class
interface IDisposable
Public Class EventSource
Implements IDisposable
- Наследование
-
EventSource
- Производный
- Атрибуты
- Реализации
Примеры
В следующем примере показана простая реализация EventSource класса.
using System.Diagnostics.Tracing;
namespace Demo
{
sealed class MyCompanyEventSource : EventSource
{
public static MyCompanyEventSource Log = new MyCompanyEventSource();
public void Startup() { WriteEvent(1); }
public void OpenFileStart(string fileName) { WriteEvent(2, fileName); }
public void OpenFileStop() { WriteEvent(3); }
}
class Program
{
static void Main(string[] args)
{
MyCompanyEventSource.Log.Startup();
// ...
MyCompanyEventSource.Log.OpenFileStart("SomeFile");
// ...
MyCompanyEventSource.Log.OpenFileStop();
}
}
}
Imports System.Diagnostics.Tracing
Class MyCompanyEventSource
Inherits EventSource
Public Shared Log As New MyCompanyEventSource()
Public Sub Startup()
WriteEvent(1)
End Sub
Public Sub OpenFileStart(ByVal fileName As String)
WriteEvent(2, fileName)
End Sub
Public Sub OpenFileStop()
WriteEvent(3)
End Sub
End Class
Class Program
Shared Sub Main(ByVal args() As String)
MyCompanyEventSource.Log.Startup()
' ...
MyCompanyEventSource.Log.OpenFileStart("SomeFile")
' ...
MyCompanyEventSource.Log.OpenFileStop()
End Sub
End Class
В следующем примере показана более сложная реализация EventSource класса.
using System.Diagnostics.Tracing;
namespace Demo1
{
sealed class MyCompanyEventSource : EventSource
{
public static MyCompanyEventSource Log = new MyCompanyEventSource();
public void Startup() { WriteEvent(1); }
public void OpenFileStart(string fileName) { WriteEvent(2, fileName); }
public void OpenFileStop() { WriteEvent(3); }
}
class Program
{
static void Main(string[] args)
{
MyCompanyEventSource.Log.Startup();
// ...
MyCompanyEventSource.Log.OpenFileStart("SomeFile");
// ...
MyCompanyEventSource.Log.OpenFileStop();
}
}
}
Imports System.Diagnostics.Tracing
Enum MyColor
Red
Yellow
Blue
End Enum 'MyColor
<EventSource(Name:="MyCompany")>
Class MyCompanyEventSource1
Inherits EventSource
Public Class Keywords
Public Const Page As EventKeywords = CType(1, EventKeywords)
Public Const DataBase As EventKeywords = CType(2, EventKeywords)
Public Const Diagnostic As EventKeywords = CType(4, EventKeywords)
Public Const Perf As EventKeywords = CType(8, EventKeywords)
End Class
Public Class Tasks
Public Const Page As EventTask = CType(1, EventTask)
Public Const DBQuery As EventTask = CType(1, EventTask)
End Class
<[Event](1, Message:="Application Failure: {0}", Level:=EventLevel.Error, Keywords:=Keywords.Diagnostic)>
Public Sub Failure(ByVal message As String)
WriteEvent(1, message)
End Sub
<[Event](2, Message:="Starting up.", Keywords:=Keywords.Perf, Level:=EventLevel.Informational)>
Public Sub Startup()
WriteEvent(2)
End Sub
<[Event](3, Message:="loading page {1} activityID={0}", Opcode:=EventOpcode.Start, Task:=Tasks.Page, Keywords:=Keywords.Page, Level:=EventLevel.Informational)>
Public Sub PageStart(ByVal ID As Integer, ByVal url As String)
If IsEnabled() Then
WriteEvent(3, ID, url)
End If
End Sub
<[Event](4, Opcode:=EventOpcode.Stop, Task:=Tasks.Page, Keywords:=Keywords.Page, Level:=EventLevel.Informational)>
Public Sub PageStop(ByVal ID As Integer)
If IsEnabled() Then
WriteEvent(4, ID)
End If
End Sub
<[Event](5, Opcode:=EventOpcode.Start, Task:=Tasks.DBQuery, Keywords:=Keywords.DataBase, Level:=EventLevel.Informational)>
Public Sub DBQueryStart(ByVal sqlQuery As String)
WriteEvent(5, sqlQuery)
End Sub
<[Event](6, Opcode:=EventOpcode.Stop, Task:=Tasks.DBQuery, Keywords:=Keywords.DataBase, Level:=EventLevel.Informational)>
Public Sub DBQueryStop()
WriteEvent(6)
End Sub
<[Event](7, Level:=EventLevel.Verbose, Keywords:=Keywords.DataBase)>
Public Sub Mark(ByVal ID As Integer)
If IsEnabled() Then
WriteEvent(7, ID)
End If
End Sub
<[Event](8)>
Public Sub LogColor(ByVal color As MyColor)
WriteEvent(8, Fix(color))
End Sub
Public Shared Log As New MyCompanyEventSource1()
End Class
Class Program1
Shared Sub Main(ByVal args() As String)
MyCompanyEventSource1.Log.Startup()
Console.WriteLine("Starting up")
MyCompanyEventSource1.Log.DBQueryStart("Select * from MYTable")
Dim url As String = "http:'localhost"
Dim i As Integer
For i = 0 To 9
MyCompanyEventSource1.Log.PageStart(i, url)
MyCompanyEventSource1.Log.Mark(i)
MyCompanyEventSource1.Log.PageStop(i)
Next i
MyCompanyEventSource1.Log.DBQueryStop()
MyCompanyEventSource1.Log.LogColor(MyColor.Blue)
MyCompanyEventSource1.Log.Failure("This is a failure 1")
MyCompanyEventSource1.Log.Failure("This is a failure 2")
MyCompanyEventSource1.Log.Failure("This is a failure 3")
End Sub
End Class
Расширенное использование
Традиционно определяемые EventSource пользователем объекты ожидают наследовать непосредственно от EventSource. Однако для расширенных сценариев можно создавать abstractEventSource объекты, называемые источниками служебной программы, и реализовывать интерфейсы. Использование одного или обоих из этих методов позволяет совместно использовать код между различными производными источниками.
Important
Абстрактные EventSource объекты не могут определять ключевые слова, задачи, опкоды, каналы или события.
Important
Чтобы избежать конфликтов имен во время выполнения при создании метаданных события, не реализуйте явным образом методы интерфейса при использовании интерфейсов с EventSource.
В следующем примере показана реализация EventSource, использующая интерфейс.
public interface IMyLogging
{
void Error(int errorCode, string message);
void Warning(string message);
}
public sealed class MySource : EventSource, IMyLogging
{
public static MySource Log = new();
[Event(1)]
public void Error(int errorCode, string message) => WriteEvent(1, errorCode, message);
[Event(2)]
public void Warning(string message) => WriteEvent(2, message);
}
В следующем примере показана реализация EventSource , которая использует шаблон Utility EventSource.
public abstract class UtilBaseEventSource : EventSource
{
protected UtilBaseEventSource()
: base()
{ }
protected UtilBaseEventSource(bool throwOnEventWriteErrors)
: base(throwOnEventWriteErrors)
{ }
// helper overload of WriteEvent for optimizing writing an event containing
// payload properties that don't align with a provided overload. This prevents
// EventSource from using the object[] overload which is expensive.
protected unsafe void WriteEvent(int eventId, int arg1, short arg2, long arg3)
{
if (IsEnabled())
{
EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
descrs[0] = new EventData { DataPointer = (IntPtr)(&arg1), Size = 4 };
descrs[1] = new EventData { DataPointer = (IntPtr)(&arg2), Size = 2 };
descrs[2] = new EventData { DataPointer = (IntPtr)(&arg3), Size = 8 };
WriteEventCore(eventId, 3, descrs);
}
}
}
public sealed class OptimizedEventSource : UtilBaseEventSource
{
public static OptimizedEventSource Log = new();
public static class Keywords
{
public const EventKeywords Kwd1 = (EventKeywords)1;
}
[Event(1, Keywords = Keywords.Kwd1, Level = EventLevel.Informational, Message = "LogElements called {0}/{1}/{2}.")]
public void LogElements(int n, short sh, long l) => WriteEvent(1, n, sh, l); // uses the overload we added!
}
В следующем примере показана реализация EventSource для отслеживания информации о компоненте в библиотеке.
public class ComplexComponent : IDisposable
{
internal static Dictionary<string, string> _internalState = new();
private string _name;
public ComplexComponent(string name)
{
_name = name ?? throw new ArgumentNullException(nameof(name));
ComplexSource.Log.NewComponent(_name);
}
public void SetState(string key, string value)
{
lock (_internalState)
{
_internalState[key] = value;
ComplexSource.Log.SetState(_name, key, value);
}
}
private void ExpensiveWork1() => System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(250));
private void ExpensiveWork2() => System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(250));
private void ExpensiveWork3() => System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(250));
private void ExpensiveWork4() => System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(250));
public void DoWork()
{
ComplexSource.Log.ExpensiveWorkStart(_name);
ExpensiveWork1();
ExpensiveWork2();
ExpensiveWork3();
ExpensiveWork4();
ComplexSource.Log.ExpensiveWorkStop(_name);
}
public void Dispose()
{
ComplexSource.Log.ComponentDisposed(_name);
}
}
internal sealed class ComplexSource : EventSource
{
public static ComplexSource Log = new();
public static class Keywords
{
public const EventKeywords ComponentLifespan = (EventKeywords)1;
public const EventKeywords StateChanges = (EventKeywords)(1 << 1);
public const EventKeywords Performance = (EventKeywords)(1 << 2);
public const EventKeywords DumpState = (EventKeywords)(1 << 3);
// A utility keyword for a common combination of
// keywords users might enable.
public const EventKeywords StateTracking = ComponentLifespan | StateChanges | DumpState;
}
protected override void OnEventCommand(EventCommandEventArgs args)
{
base.OnEventCommand(args);
if (args.Command == EventCommand.Enable)
{
DumpComponentState();
}
}
[Event(1, Keywords = Keywords.ComponentLifespan, Message = "New component with name '{0}'.")]
public void NewComponent(string name) => WriteEvent(1, name);
[Event(2, Keywords = Keywords.ComponentLifespan, Message = "Component with name '{0}' disposed.")]
public void ComponentDisposed(string name) => WriteEvent(2, name);
[Event(3, Keywords = Keywords.StateChanges)]
public void SetState(string name, string key, string value) => WriteEvent(3, name, key, value);
[Event(4, Keywords = Keywords.Performance)]
public void ExpensiveWorkStart(string name) => WriteEvent(4, name);
[Event(5, Keywords = Keywords.Performance)]
public void ExpensiveWorkStop(string name) => WriteEvent(5, name);
[Event(6, Keywords = Keywords.DumpState)]
public void ComponentState(string key, string value) => WriteEvent(6, key, value);
[NonEvent]
public void DumpComponentState()
{
if (IsEnabled(EventLevel.Informational, Keywords.DumpState))
{
lock (ComplexComponent._internalState)
{
foreach (var (key, value) in ComplexComponent._internalState)
ComponentState(key, value);
}
}
}
}
Комментарии
Класс EventSource должен наследоваться пользовательским классом, предоставляющим определенные события для трассировки событий. Методы EventSource.WriteEvent вызываются для регистрации событий.
Базовые функциональные возможности EventSource достаточно для большинства приложений. Если требуется больше контроля над созданными метаданными события, можно применить EventAttribute атрибут к методам. Для расширенных приложений с источниками событий можно перехватывать команды, отправляемые в производный источник событий, и менять параметры фильтрации или вызывать действия (такие как сброс структуры данных) для выполнения наследником. Источник событий можно активировать внутрипроцессным использованием EventListener и внепроцессным использованием инструментов на основе EventPipe, таких как dotnet-trace, или инструментов на основе Трассировки событий для Windows (ETW), таких как PerfView или Logman. Кроме того, можно программно осуществлять контроль и перехват диспетчера данных. Класс EventListener предоставляет дополнительные функциональные возможности.
Conventions
EventSourceПроизводные классы должны соответствовать следующим соглашениям:
- Определяемые пользователем классы должны реализовывать единый шаблон. Одиночный экземпляр традиционно называется
Log. Пользователи не должны вызыватьIDisposable.Disposeвручную, а должны позволить среде выполнения очистить одноэлементный экземпляр в конце выполнения управляемого кода. - Определяемый пользователем производный класс должен быть помечен как
sealed, если он не реализует расширенную конфигурацию "Служебный EventSource", описанную в разделе "Дополнительное использование". - Вызов IsEnabled() перед выполнением любой ресурсоемкой работы, связанной с запуском события.
- Можно неявно создавать EventTask объекты, объявляя два метода, обрабатывающих события, с последующими идентификаторами событий в соответствии с шаблоном именования
<EventName>Startи<EventName>Stop. Эти события должны быть объявлены рядом друг с другом в определении класса, и<EventName>Startметод должен быть первым. - Попробуйте поддерживать EventSource обратную совместимость объектов и версионировать их соответствующим образом. Версия по умолчанию для события
0. Версию можно изменить с помощью параметра Version. Изменяйте версию события всякий раз, когда изменяете свойства полезной нагрузки. Всегда добавляйте новые свойства полезных данных в конец объявления события. Если это невозможно, создайте событие с новым идентификатором, чтобы заменить старый. - При объявлении методов событий задайте параметры полезной нагрузки фиксированного размера перед параметрами переменного размера.
-
EventKeywords используется в качестве битовой маски для указания определенных событий при подписке на поставщика. Ключевые слова можно указать, определив класс
public static class Keywords, который содержитpublic const EventKeywordsучастников. - Ассоциируйте дорогие события с EventKeywords, используя EventAttribute. Этот шаблон позволяет пользователям EventSource отказаться от этих дорогостоящих операций.
Самоописывающиеся (трассировочные) события против форматов событий манифеста
EventSource можно настроить для двух различных режимов в зависимости от конструктора, который используется, или установленных флагов на EventSourceOptions.
Исторически эти два формата являются производными от двух форматов, используемых трассировкой событий для Windows (ETW). Хотя эти два режима не влияют на вашу возможность использовать трассировку событий для Windows (ETW) или прослушиватели, основанные на EventPipe, они создают метаданные для событий различными способами.
Формат события по умолчанию — это EtwManifestEventFormat, который устанавливается, если не указан на EventSourceSettings. Объекты на основе EventSource манифеста создают XML-документ, представляющий события, определенные в классе при инициализации. Это требует, чтобы EventSource отражался через себя для создания поставщика и метаданных событий.
Чтобы использовать формат событий с самостоятельным описанием (tracelogging), создайте ваш EventSource с помощью конструктора EventSource(String) или конструктора EventSource(String, EventSourceSettings), или установите флаг EtwSelfDescribingEventFormat на EventSourceSettings. Самостоятельно описывающие источники создают минимальные метаданные поставщика при инициализации и создают только метаданные события при Write(String) вызове. В отличие от формата на основе манифеста, при прослушивании через ETW из атрибута EventAttribute включаются только метаданные уровня, ключевое слово и Opcode. Другие свойства, такие как EventId или Message, не включены.
На практике эти параметры формата событий влияют только на использование считывателей, основанных на Event Tracing for Windows (ETW). Однако они могут иметь небольшое влияние на время инициализации и время записи на событие из-за времени, необходимого для отражения и создания метаданных.
Конструкторы
| Имя | Описание |
|---|---|
| EventSource() |
Создает новый экземпляр класса EventSource. |
| EventSource(Boolean) |
Создает новый экземпляр класса EventSource и указывает, следует ли вызывать исключение при возникновении ошибки в базовом коде Windows. |
| EventSource(EventSourceSettings, String[]) |
Инициализирует новый экземпляр используемого EventSource с событиями, не содержащими контракт, которые содержат указанные параметры и признаки. |
| EventSource(EventSourceSettings) |
Создает новый экземпляр EventSource класса с указанными параметрами конфигурации. |
| EventSource(String, EventSourceSettings, String[]) |
Создает новый экземпляр EventSource класса с указанными параметрами конфигурации. |
| EventSource(String, EventSourceSettings) |
Создает новый экземпляр EventSource класса с указанным именем и параметрами. |
| EventSource(String, Guid, EventSourceSettings, String[]) |
Предоставляет возможность создавать события для трассировки событий на разных платформах. |
| EventSource(String, Guid) |
Предоставляет возможность создавать события для трассировки событий на разных платформах. |
| EventSource(String) |
Создает новый экземпляр EventSource класса с указанным именем. |
Свойства
| Имя | Описание |
|---|---|
| ConstructionException |
Получает любое исключение, которое было создано во время построения источника события. |
| CurrentThreadActivityId |
Возвращает идентификатор действия текущего потока. |
| Guid |
Уникальный идентификатор источника событий. |
| Name |
Понятное имя класса, производного от источника событий. |
| Settings |
Возвращает параметры, примененные к этому источнику событий. |
Методы
| Имя | Описание |
|---|---|
| Dispose() |
Освобождает все ресурсы, используемые текущим экземпляром класса EventSource. |
| Dispose(Boolean) |
Освобождает неуправляемые ресурсы, используемые классом EventSource , и при необходимости освобождает управляемые ресурсы. |
| Equals(Object) |
Определяет, равен ли указанный объект текущему объекту. (Унаследовано от Object) |
| Finalize() |
EventSource Позволяет объекту пытаться освободить ресурсы и выполнять другие операции очистки перед восстановлением объекта сборкой мусора. |
| GenerateManifest(Type, String, EventManifestOptions) |
Возвращает строку XML-манифеста, связанного с текущим источником событий. |
| GenerateManifest(Type, String) |
Возвращает строку XML-манифеста, связанного с текущим источником событий. |
| GetGuid(Type) |
Возвращает уникальный идентификатор для этой реализации источника событий. |
| GetHashCode() |
Служит хэш-функцией по умолчанию. (Унаследовано от Object) |
| GetName(Type) |
Возвращает понятное имя источника событий. |
| GetSources() |
Получает моментальный снимок всех источников событий для домена приложения. |
| GetTrait(String) |
Возвращает значение признака, связанное с указанным ключом. |
| GetType() |
Возвращает Type текущего экземпляра. (Унаследовано от Object) |
| IsEnabled() |
Определяет, включен ли текущий источник событий. |
| IsEnabled(EventLevel, EventKeywords, EventChannel) |
Определяет, включен ли текущий источник событий для событий с указанным уровнем, ключевыми словами и каналом. |
| IsEnabled(EventLevel, EventKeywords) |
Определяет, включен ли текущий источник событий с указанным уровнем и ключевым словом. |
| MemberwiseClone() |
Создает неглубокую копию текущей Object. (Унаследовано от Object) |
| OnEventCommand(EventCommandEventArgs) |
Вызывается при обновлении текущего источника событий контроллером. |
| SendCommand(EventSource, EventCommand, IDictionary<String,String>) |
Отправляет команду в указанный источник событий. |
| SetCurrentThreadActivityId(Guid, Guid) |
Задает идентификатор действия в текущем потоке и возвращает предыдущий идентификатор действия. |
| SetCurrentThreadActivityId(Guid) |
Задает идентификатор действия в текущем потоке. |
| ToString() |
Получает строковое представление текущего экземпляра источника события. |
| Write(String, EventSourceOptions) |
Записывает событие без полей, но с указанным именем и параметрами. |
| Write(String) |
Записывает событие без полей, но с указанным именем и параметрами по умолчанию. |
| Write<T>(String, EventSourceOptions, Guid, Guid, T) |
Записывает событие с указанным именем, параметрами, связанными данными о действиях и событиях. |
| Write<T>(String, EventSourceOptions, T) |
Записывает событие с указанным именем, данными событий и параметрами. |
| Write<T>(String, EventSourceOptions, T) |
Записывает событие с указанным именем, параметрами и данными о событиях. |
| Write<T>(String, T) |
Записывает событие с указанным именем и данными. |
| WriteEvent(Int32, Byte[]) |
Записывает событие с помощью предоставленного идентификатора события и аргумента массива байтов. |
| WriteEvent(Int32, EventSource+EventSourcePrimitive[]) |
Записывает событие с помощью предоставленного идентификатора события и переменного числа примитивов источника событий. |
| WriteEvent(Int32, Int32, Int32, Int32) |
Записывает событие с помощью предоставленного идентификатора события и 32-разрядных целых аргументов. |
| WriteEvent(Int32, Int32, Int32) |
Записывает событие с помощью предоставленного идентификатора события и 32-разрядных целых аргументов. |
| WriteEvent(Int32, Int32, String) |
Записывает событие с помощью предоставленного идентификатора события и 32-разрядного целого числа и строковых аргументов. |
| WriteEvent(Int32, Int32) |
Записывает событие с помощью предоставленного идентификатора события и 32-разрядного целого числа. |
| WriteEvent(Int32, Int64, Byte[]) |
Записывает данные события с помощью указанного идентификатора и 64-разрядного целого числа и аргументов массива байтов. |
| WriteEvent(Int32, Int64, Int64, Int64) |
Записывает событие с помощью предоставленного идентификатора события и 64-разрядных аргументов. |
| WriteEvent(Int32, Int64, Int64) |
Записывает событие с помощью предоставленного идентификатора события и 64-разрядных аргументов. |
| WriteEvent(Int32, Int64, String) |
Записывает событие с помощью предоставленного идентификатора события и 64-разрядного целого числа и строковых аргументов. |
| WriteEvent(Int32, Int64) |
Записывает событие с помощью предоставленного идентификатора события и 64-разрядного целого числа. |
| WriteEvent(Int32, Object[]) |
Записывает событие с помощью предоставленного идентификатора события и массива аргументов. |
| WriteEvent(Int32, String, Int32, Int32) |
Записывает событие с помощью предоставленного идентификатора и аргументов события. |
| WriteEvent(Int32, String, Int32) |
Записывает событие с помощью предоставленного идентификатора и аргументов события. |
| WriteEvent(Int32, String, Int64) |
Записывает событие с помощью предоставленного идентификатора и аргументов события. |
| WriteEvent(Int32, String, String, String) |
Записывает событие с помощью предоставленного идентификатора события и строковых аргументов. |
| WriteEvent(Int32, String, String) |
Записывает событие с помощью предоставленного идентификатора события и строковых аргументов. |
| WriteEvent(Int32, String) |
Записывает событие с помощью предоставленного идентификатора события и аргумента строки. |
| WriteEvent(Int32) |
Записывает событие с помощью предоставленного идентификатора события. |
| WriteEventCore(Int32, Int32, EventSource+EventData*) |
Создает новую WriteEvent перегрузку с помощью предоставленного идентификатора события и данных событий. |
| WriteEventWithRelatedActivityId(Int32, Guid, Object[]) |
Записывает событие, указывающее, что текущее действие связано с другим действием. |
| WriteEventWithRelatedActivityIdCore(Int32, Guid*, Int32, EventSource+EventData*) |
Записывает событие, указывающее, что текущее действие связано с другим действием. |
События
| Имя | Описание |
|---|---|
| EventCommandExecuted |
Происходит, когда команда поступает из прослушивателя событий. |
Применяется к
Потокобезопасность
Этот тип является потокобезопасной.