Создание компонентов среды выполнения Windows с помощью C++/CXWindows Runtime components with C++/CX

Примечание

В этом разделе представлена вспомогательная информация для поддержки приложений на C++/CX.This topic exists to help you maintain your C++/CX application. Однако в новых приложениях мы рекомендуем использовать C++/WinRT.But we recommend that you use C++/WinRT for new applications. C++/WinRT — это полностью стандартная проекция языка C++17 для API среды выполнения Windows (WinRT), реализованная как библиотека на основе файлов заголовков и предназначенная для предоставления вам первоклассного доступа к современным интерфейсам API Windows.C++/WinRT is an entirely standard modern C++17 language projection for Windows Runtime (WinRT) APIs, implemented as a header-file-based library, and designed to provide you with first-class access to the modern Windows API. Сведения о создании компонента среды выполнения Windows с помощью C++/WinRT см. в статье Создание компонентов среды выполнения Windows с помощью C++/WinRT.To learn how to create a Windows Runtime component using C++/WinRT, see Windows Runtime components with C++/WinRT.

В этом разделе показано, как использовать C++/CX для создания среда выполнения Windows компонента — , который можно вызвать из универсального приложения Windows, созданного с помощью любого языка среда выполнения Windows (C#, Visual Basic, C++ или JavaScript).This topic shows how to use C++/CX to create a Windows Runtime component—a component that's callable from a Universal Windows app built using any Windows Runtime language (C#, Visual Basic, C++, or Javascript).

Существует несколько причин для создания компонента среда выполнения Windows в C++.There are several reasons for building a Windows Runtime component in C++.

  • Использование повышенной производительности C++ при сложных или требующих большого объема вычислений операциях.To get the performance advantage of C++ in complex or computationally intensive operations.
  • Повторное использование уже написанного и протестированного кода.To reuse code that's already written and tested.

При создании решения, содержащего проект JavaScript или .NET и проект компонента среды выполнения Windows, файлы проекта JavaScript и скомпилированная библиотека DLL объединяются в один пакет, отладку которого вы можете выполнить локально в имитаторе или удаленно на связанном устройстве.When you build a solution that contains a JavaScript or .NET project, and a Windows Runtime component project, the JavaScript project files and the compiled DLL are merged into one package, which you can debug locally in the simulator or remotely on a tethered device. Вы также можете распространять проект компонента отдельно в виде пакета SDK расширения.You can also distribute just the component project as an Extension SDK. Дополнительные сведения о пакетах SDK см. в статье Создание пакета средств разработки программного обеспечения.For more information, see Creating a Software Development Kit.

Как правило, при написании компонента C++/CX используйте обычную библиотеку C++ и встроенные типы, за исключением границ абстрактного двоичного интерфейса (ABI), в которых данные передаются в код и из другого пакета WinMD.In general, when you code your C++/CX component, use the regular C++ library and built-in types, except at the abstract binary interface (ABI) boundary where you are passing data to and from code in another .winmd package. В нем используются типы среда выполнения Windows и Специальный синтаксис, который поддерживает C++/CX для создания этих типов и управления ими.There, use Windows Runtime types and the special syntax that C++/CX supports for creating and manipulating those types. Кроме того, в коде C++/CX используйте такие типы, как делегат и Event, для реализации событий, которые могут быть вызваны из компонента и обрабатываться в JavaScript, Visual Basic, C++ или C#.In addition, in your C++/CX code, use types such as delegate and event to implement events that can be raised from your component and handled in JavaScript, Visual Basic, C++, or C#. Дополнительные сведения о синтаксисе C++/CX см. в разделе Справочник по языку Visual C++ (c++/CX).For more information about the C++/CX syntax, see Visual C++ Language Reference (C++/CX).

Регистр символов и правила именованияCasing and naming rules

JavaScriptJavaScript

В языке JavaScript учитывается регистр символов.JavaScript is case-sensitive. Поэтому необходимо следовать следующим соглашениям об использовании регистров.Therefore, you must follow these casing conventions:

  • При создании ссылок на пространства имен и классы C++ используйте тот же стиль, который используется в C++.When you reference C++ namespaces and classes, use the same casing that's used on the C++ side.
  • При вызове методов используйте "верблюжий" стиль, даже если в компоненте C++ имя метода написано прописными буквами.When you call methods, use camel casing even if the method name is capitalized on the C++ side. Например, метод GetDate() C++ следует вызывать из JavaScript как getDate().For example, a C++ method GetDate() must be called from JavaScript as getDate().
  • Активируемые имена классов и пространств имен не могут содержать символы Юникода.An activatable class name and namespace name can't contain UNICODE characters.

.NET.NET

В языках .NET действуют их обычные правила использования регистров.The .NET languages follow their normal casing rules.

Создание экземпляра объектаInstantiating the object

Через границу интерфейса ABI можно передавать только типы среды выполнения Windows.Only Windows Runtime types can be passed across the ABI boundary. Если компонент содержит тип, подобный std::wstring в качестве возвращаемого типа или параметра открытого метода, компилятор создает ошибку.The compiler will raise an error if the component has a type like std::wstring as a return type or parameter in a public method. Встроенные типы расширений компонентов Visual C++ (C++/CX) содержат обычные скаляры, такие как int и double, а также их эквиваленты typedef — int32, float64 и т. д.The Visual C++ component extensions (C++/CX) built-in types include the usual scalars such as int and double, and also their typedef equivalents int32, float64, and so on. Дополнительные сведения см. в разделе Система типов (C++/CX).For more information, see Type System (C++/CX).

// ref class definition in C++
public ref class SampleRefClass sealed
{
    // Class members...

    // #include <valarray>
public:
    double LogCalc(double input)
    {
        // Use C++ standard library as usual.
        return std::log(input);
    }

};
//Instantiation in JavaScript (requires "Add reference > Project reference")
var nativeObject = new CppComponent.SampleRefClass();
//Call a method and display result in a XAML TextBlock
var num = nativeObject.LogCalc(21.5);
ResultText.Text = num.ToString();

Встроенные типы C++/CX, типы библиотек и типы среда выполнения WindowsC++/CX built-in types, library types, and Windows Runtime types

Экземпляр активируемого класса (также называемого классом ссылки) может быть создан из другого языка, например из JavaScript, C# или Visual Basic.An activatable class (also known as a ref class) is one that can be instantiated from another language such as JavaScript, C# or Visual Basic. Чтобы компонент можно было использовать в другом языке, он должен содержать по крайней мере один активируемый класс.To be consumable from another language, a component must contain at least one activatable class.

Компонент среды выполнения Windows может содержать несколько открытых активируемых классов, а также дополнительные классы, которые доступны только для внутреннего использования в компоненте.A Windows Runtime component can contain multiple public activatable classes as well as additional classes that are known only internally to the component. Примените атрибут WebHostHidden к типам C++/CX, которые не должны быть видимыми для JavaScript.Apply the WebHostHidden attribute to C++/CX types that are not intended to be visible to JavaScript.

Все открытые классы должны располагаться в одном и том же корневом пространстве имен, имя которого совпадает с именем файла метаданных компонента.All public classes must reside in the same root namespace which has the same name as the component metadata file. Например, экземпляр класса с именем A.B.C.MyClass может быть создан, только если он определен в файле метаданных с именем A.winmd, A.B.winmd или A.B.C.winmd.For example, a class that's named A.B.C.MyClass can be instantiated only if it's defined in a metadata file that's named A.winmd or A.B.winmd or A.B.C.winmd. Имя DLL-файла не обязательно должно соответствовать имени WINMD-файла.The name of the DLL is not required to match the .winmd file name.

Клиентский код создает экземпляр компонента с помощью ключевого слова new (New в Visual Basic) точно так же, как для любого другого класса.Client code creates an instance of the component by using the new (New in Visual Basic) keyword just as for any class.

Активируемый класс должен быть объявлен как открытый запечатанный класс ссылки.An activatable class must be declared as public ref class sealed. Ключевое слово ref class указывает компилятору, что нужно создать класс как тип, совместимый со средой выполнения Windows, а ключевое слово sealed запрещает наследование от этого класса.The ref class keyword tells the compiler to create the class as a Windows Runtime compatible type, and the sealed keyword specifies that the class cannot be inherited. Среда выполнения Windows в настоящее время не поддерживает обобщенную модель наследования; ограниченная модель наследования поддерживает создание пользовательских элементов управления XAML.The Windows Runtime does not currently support a generalized inheritance model; a limited inheritance model supports creation of custom XAML controls. Дополнительные сведения см. в разделе Классы и структуры ссылки (C++/CX).For more information, see Ref classes and structs (C++/CX).

Для C++/CX все числовые примитивы определены в пространстве имен по умолчанию.For C++/CX, all the numeric primitives are defined in the default namespace. Пространство имен Platform содержит классы C++/CX, относящиеся к системе типов Среда выполнения Windows.The Platform namespace contains C++/CX classes that are specific to the Windows Runtime type system. К ним относятся классы Platform::String и Platform::Object.These include Platform::String class and Platform::Object class. Конкретные типы коллекций, такие как Platform::Collections::Map и Platform::Collections::Vector, определяются в пространстве имен Platform::Collections.The concrete collection types such as Platform::Collections::Map class and Platform::Collections::Vector class are defined in the Platform::Collections namespace. Открытые интерфейсы, реализуемые этими типами, определяются в пространстве имен Windows::Foundation::Collections (C++/CX).The public interfaces that these types implement are defined in Windows::Foundation::Collections Namespace (C++/CX). Именно эти типы интерфейсов используются кодом JavaScript, C# и Visual Basic.It is these interface types that are consumed by JavaScript, C# and Visual Basic. Дополнительные сведения см. в разделе Система типов (C++/CX).For more information, see Type System (C++/CX).

Метод, возвращающий значение встроенного типаMethod that returns a value of built-in type

    // #include <valarray>
public:
    double LogCalc(double input)
    {
        // Use C++ standard library as usual.
        return std::log(input);
    }
//Call a method
var nativeObject = new CppComponent.SampleRefClass;
var num = nativeObject.logCalc(21.5);
document.getElementById('P2').innerHTML = num;

Метод, возвращающий пользовательскую структуру значенияMethod that returns a custom value struct

namespace CppComponent
{
    // Custom struct
    public value struct PlayerData
    {
        Platform::String^ Name;
        int Number;
        double ScoringAverage;
    };

    public ref class Player sealed
    {
    private:
        PlayerData m_player;
    public:
        property PlayerData PlayerStats
        {
            PlayerData get(){ return m_player; }
            void set(PlayerData data) {m_player = data;}
        }
    };
}

Чтобы передать структуры определяемых пользователем значений в ABI, определите объект JavaScript, который имеет те же члены, что и структура значения, определенная в C++/CX.To pass user-defined value structs across the ABI, define a JavaScript object that has the same members as the value struct that's defined in C++/CX. Затем этот объект можно передать в качестве аргумента в метод C++/CX, чтобы объект был неявно преобразован в тип C++/CX.You can then pass that object as an argument to a C++/CX method so that the object is implicitly converted to the C++/CX type.

// Get and set the value struct
function GetAndSetPlayerData() {
    // Create an object to pass to C++
    var myData =
        { name: "Bob Homer", number: 12, scoringAverage: .357 };
    var nativeObject = new CppComponent.Player();
    nativeObject.playerStats = myData;

    // Retrieve C++ value struct into new JavaScript object
    var myData2 = nativeObject.playerStats;
    document.getElementById('P3').innerHTML = myData.name + " , " + myData.number + " , " + myData.scoringAverage.toPrecision(3);
}

Другой способ состоит в определении класса, который реализует интерфейс IPropertySet (не показан).Another approach is to define a class that implements IPropertySet (not shown).

На языках .NET вы просто создаете переменную типа, которая определена в компоненте C++/CX.In the .NET languages, you just create a variable of the type that's defined in the C++/CX component.

private void GetAndSetPlayerData()
{
    // Create a ref class
    var player = new CppComponent.Player();

    // Create a variable of a value struct
    // type that is defined in C++
    CppComponent.PlayerData myPlayer;
    myPlayer.Name = "Babe Ruth";
    myPlayer.Number = 12;
    myPlayer.ScoringAverage = .398;

    // Set the property
    player.PlayerStats = myPlayer;

    // Get the property and store it in a new variable
    CppComponent.PlayerData myPlayer2 = player.PlayerStats;
    ResultText.Text += myPlayer.Name + " , " + myPlayer.Number.ToString() +
        " , " + myPlayer.ScoringAverage.ToString();
}

Перегруженные методыOverloaded Methods

Открытый класс ссылки C++/CX может содержать перегруженные методы, но JavaScript имеет ограниченную возможность отличать перегруженные методы.A C++/CX public ref class can contain overloaded methods, but JavaScript has limited ability to differentiate overloaded methods. Например, он может найти разницу между следующими сигнатурами:For example, it can tell the difference between these signatures:

public ref class NumberClass sealed
{
public:
    int GetNumber(int i);
    int GetNumber(int i, Platform::String^ str);
    double GetNumber(int i, MyData^ d);
};

Но он не может определить разницу между ними:But it can't tell the difference between these:

int GetNumber(int i);
double GetNumber(double d);

В случаях неоднозначности можно добиться того, что код JavaScript всегда будет вызывать конкретную перегрузку, применив атрибут Windows::Foundation::Metadata::DefaultOverload к сигнатуре метода в файле заголовка.In ambiguous cases, you can ensure that JavaScript always calls a specific overload by applying the Windows::Foundation::Metadata::DefaultOverload attribute to the method signature in the header file.

Этот код JavaScript всегда вызывает перегрузку с атрибутом:This JavaScript always calls the attributed overload:

var nativeObject = new CppComponent.NumberClass();
var num = nativeObject.getNumber(9);
document.getElementById('P4').innerHTML = num;

.NET.NET

Языки .NET распознают перегрузки в классе ссылки C++/CX точно так же, как и в любом классе .NET.The .NET languages recognize overloads in a C++/CX ref class just as in any .NET class.

Дата и времяDateTime

В среде выполнения в Windows объект Windows::Foundation::DateTime является лишь 64-разрядным знаковым целым числом, представляющим количество 100-наносекундных интервалов до или после 1 января 1601 г.In the Windows Runtime, a Windows::Foundation::DateTime object is just a 64-bit signed integer that represents the number of 100-nanosecond intervals either before or after January 1, 1601. У объекта Windows:Foundation::DateTime нет методов.There are no methods on a Windows:Foundation::DateTime object. Вместо этого каждый язык проецирует значение DateTime в направлении, присущем этому языку: объект Date в JavaScript, а также типы System. DateTime и System. DateTimeOffset в .NET.Instead, each language projects the DateTime in the way that is native to that language: the Date object in JavaScript and the System.DateTime and System.DateTimeOffset types in .NET.

public  ref class MyDateClass sealed
{
public:
    property Windows::Foundation::DateTime TimeStamp;
    void SetTime(Windows::Foundation::DateTime dt)
    {
        auto cal = ref new Windows::Globalization::Calendar();
        cal->SetDateTime(dt);
        TimeStamp = cal->GetDateTime(); // or TimeStamp = dt;
    }
};

При передаче значения DateTime из C++/CX в JavaScript, JavaScript принимает его как объект Date и по умолчанию отображает его как строку даты в длинном формате.When you pass a DateTime value from C++/CX to JavaScript, JavaScript accepts it as a Date object and displays it by default as a long-form date string.

function SetAndGetDate() {
    var nativeObject = new CppComponent.MyDateClass();

    var myDate = new Date(1956, 4, 21);
    nativeObject.setTime(myDate);

    var myDate2 = nativeObject.timeStamp;

    //prints long form date string
    document.getElementById('P5').innerHTML = myDate2;

}

Когда язык .NET передает System. DateTime в компонент C++/CX, метод принимает его как Windows:: Foundation::D Атетиме.When a .NET language passes a System.DateTime to a C++/CX component, the method accepts it as a Windows::Foundation::DateTime. Когда компонент передает методу .NET Windows:: Foundation::D Атетиме, метод Framework принимает его как DateTimeOffset.When the component passes a Windows::Foundation::DateTime to a .NET method, the Framework method accepts it as a DateTimeOffset.

private void DateTimeExample()
{
    // Pass a System.DateTime to a C++ method
    // that takes a Windows::Foundation::DateTime
    DateTime dt = DateTime.Now;
    var nativeObject = new CppComponent.MyDateClass();
    nativeObject.SetTime(dt);

    // Retrieve a Windows::Foundation::DateTime as a
    // System.DateTimeOffset
    DateTimeOffset myDate = nativeObject.TimeStamp;

    // Print the long-form date string
    ResultText.Text += myDate.ToString();
}

Коллекции и массивыCollections and arrays

Коллекции всегда передаются через границу ABI в виде дескрипторов типов среды выполнения Windows, таких как Windows::Foundation::Collections::IVector^ и Windows::Foundation::Collections::IMap^.Collections are always passed across the ABI boundary as handles to Windows Runtime types such as Windows::Foundation::Collections::IVector^ and Windows::Foundation::Collections::IMap^. Например, если возвращается дескриптор типа Platform::Collections::Map, он будет неявно преобразован в Windows::Foundation::Collections::IMap^.For example, if you return a handle to a Platform::Collections::Map, it implicitly converts to a Windows::Foundation::Collections::IMap^. Интерфейсы коллекции определяются в пространстве имен, отдельном от классов C++/CX, которые предоставляют конкретные реализации.The collection interfaces are defined in a namespace that's separate from the C++/CX classes that provide the concrete implementations. Эти интерфейсы используются в языках JavaScript и .NET.JavaScript and .NET languages consume the interfaces. Дополнительные сведения см. в разделах Коллекции (C++/CX) и Классы Array и WriteOnlyArray (C++/CX).For more information, see Collections (C++/CX) and Array and WriteOnlyArray (C++/CX).

Передача IVectorPassing IVector

// Windows::Foundation::Collections::IVector across the ABI.
//#include <algorithm>
//#include <collection.h>
Windows::Foundation::Collections::IVector<int>^ SortVector(Windows::Foundation::Collections::IVector<int>^ vec)
{
    std::sort(begin(vec), end(vec));
    return vec;
}
var nativeObject = new CppComponent.CollectionExample();
// Call the method to sort an integer array
var inVector = [14, 12, 45, 89, 23];
var outVector = nativeObject.sortVector(inVector);
var result = "Sorted vector to array:";
for (var i = 0; i < outVector.length; i++)
{
    outVector[i];
    result += outVector[i].toString() + ",";
}
document.getElementById('P6').innerHTML = result;

В языках .NET IVector<T> представляется как IList<T>.The .NET languages see IVector<T> as IList<T>.

private void SortListItems()
{
    IList<int> myList = new List<int>();
    myList.Add(5);
    myList.Add(9);
    myList.Add(17);
    myList.Add(2);

    var nativeObject = new CppComponent.CollectionExample();
    IList<int> mySortedList = nativeObject.SortVector(myList);

    foreach (var item in mySortedList)
    {
        ResultText.Text += " " + item.ToString();
    }
}

Передача IMapPassing IMap

// #include <map>
//#include <collection.h>
Windows::Foundation::Collections::IMap<int, Platform::String^> ^GetMap(void)
{    
    Windows::Foundation::Collections::IMap<int, Platform::String^> ^ret =
        ref new Platform::Collections::Map<int, Platform::String^>;
    ret->Insert(1, "One ");
    ret->Insert(2, "Two ");
    ret->Insert(3, "Three ");
    ret->Insert(4, "Four ");
    ret->Insert(5, "Five ");
    return ret;
}
// Call the method to get the map
var outputMap = nativeObject.getMap();
var mStr = "Map result:" + outputMap.lookup(1) + outputMap.lookup(2)
    + outputMap.lookup(3) + outputMap.lookup(4) + outputMap.lookup(5);
document.getElementById('P7').innerHTML = mStr;

В языках .NET IMap представляется как IDictionary<K, V>.The .NET languages see IMap and IDictionary<K, V>.

private void GetDictionary()
{
    var nativeObject = new CppComponent.CollectionExample();
    IDictionary<int, string> d = nativeObject.GetMap();
    ResultText.Text += d[2].ToString();
}

СвойстваProperties

Открытый класс ссылки в расширениях компонентов C++/CX предоставляет открытые члены данных в виде свойств с помощью ключевого слова Property.A public ref class in C++/CX component extensions exposes public data members as properties, by using the property keyword. Концепция идентична свойствам .NET.The concept is identical to .NET properties. Простое свойство похоже на элемент данных, поскольку его функциональность является неявной.A trivial property resembles a data member because its functionality is implicit. Нетривиальное свойство имеет явные методы доступа get и set и закрытую переменную с именем, которая является «резервным хранилищем» для значения.A non-trivial property has explicit get and set accessors and a named private variable that's the "backing store" for the value. В этом примере закрытая переменная-член _ пропертявалуе является резервным хранилищем для свойства a.In this example, the private member variable _propertyAValue is the backing store for PropertyA. Свойство может инициировать событие при изменении значения свойства, а клиентское приложение может зарегистрироваться для получения этого события.A property can fire an event when its value changes, and a client app can register to receive that event.

//Properties
public delegate void PropertyChangedHandler(Platform::Object^ sender, int arg);
public ref class PropertyExample  sealed
{
public:
    PropertyExample(){}

    // Event that is fired when PropertyA changes
    event PropertyChangedHandler^ PropertyChangedEvent;

    // Property that has custom setter/getter
    property int PropertyA
    {
        int get() { return m_propertyAValue; }
        void set(int propertyAValue)
        {
            if (propertyAValue != m_propertyAValue)
            {
                m_propertyAValue = propertyAValue;
                // Fire event. (See event example below.)
                PropertyChangedEvent(this, propertyAValue);
            }
        }
    }

    // Trivial get/set property that has a compiler-generated backing store.
    property Platform::String^ PropertyB;

private:
    // Backing store for propertyA.
    int m_propertyAValue;
};
var nativeObject = new CppComponent.PropertyExample();
var propValue = nativeObject.propertyA;
document.getElementById('P8').innerHTML = propValue;

//Set the string property
nativeObject.propertyB = "What is the meaning of the universe?";
document.getElementById('P9').innerHTML += nativeObject.propertyB;

Языки .NET обращаются к свойствам собственного объекта C++/CX точно так же, как и к объекту .NET.The .NET languages access properties on a native C++/CX object just as they would on a .NET object.

private void GetAProperty()
{
    // Get the value of the integer property
    // Instantiate the C++ object
    var obj = new CppComponent.PropertyExample();

    // Get an integer property
    var propValue = obj.PropertyA;
    ResultText.Text += propValue.ToString();

    // Set a string property
    obj.PropertyB = " What is the meaning of the universe?";
    ResultText.Text += obj.PropertyB;

}

Делегаты и событияDelegates and events

Делегат — это тип среды выполнения Windows, представляющий объект функции.A delegate is a Windows Runtime type that represents a function object. Делегаты можно использовать в связи с событиями, обратными вызовами и асинхронными вызовами методов, чтобы задать действие, которое будет выполнено позже.You can use delegates in connection with events, callbacks, and asynchronous method calls to specify an action to be performed later. Подобно объекту функции, делегат обеспечивает безопасность типа, позволяя компилятору проверять тип возвращаемого значения и типы параметров функции.Like a function object, the delegate provides type-safety by enabling the compiler to verify the return type and parameter types of the function. Объявление делегата напоминает сигнатуру функции, реализация аналогична определению класса, а его вызов похож на вызов функции.The declaration of a delegate resembles a function signature, the implementation resembles a class definition, and the invocation resembles a function invocation.

Добавление прослушивателя событийAdding an event listener

Можно использовать ключевое слово event для объявления открытого члена конкретного типа делегата.You can use the event keyword to declare a public member of a specified delegate type. Клиентский код подписывается на событие с помощью стандартных механизмов, которые содержатся в используемом языке.Client code subscribes to the event by using the standard mechanisms that are provided in the particular language.

public:
    event SomeHandler^ someEvent;

В этом примере используется тот же код C++, что и в предыдущем разделе, посвященном свойствам.This example uses the same C++ code as for the previous properties section.

function Button_Click() {
    var nativeObj = new CppComponent.PropertyExample();
    // Define an event handler method
    var singlecasthandler = function (ev) {
        document.getElementById('P10').innerHTML = "The button was clicked and the value is " + ev;
    };

    // Subscribe to the event
    nativeObj.onpropertychangedevent = singlecasthandler;

    // Set the value of the property and fire the event
    var propValue = 21;
    nativeObj.propertyA = 2 * propValue;

}

В языках .NET подписка на событие в компоненте C++ аналогична подписке на событие в классе .NET:In the .NET languages, subscribing to an event in a C++ component is the same as subscribing to an event in a .NET class:

//Subscribe to event and call method that causes it to be fired.
private void TestMethod()
{
    var objWithEvent = new CppComponent.PropertyExample();
    objWithEvent.PropertyChangedEvent += objWithEvent_PropertyChangedEvent;

    objWithEvent.PropertyA = 42;
}

//Event handler method
private void objWithEvent_PropertyChangedEvent(object __param0, int __param1)
{
    ResultText.Text = "the event was fired and the result is " +
         __param1.ToString();
}

Добавление нескольких прослушивателей событий для одного событияAdding multiple event listeners for one event

В JavaScript имеется метод addEventListener, который позволяет нескольким обработчикам подписываться на одно событие.JavaScript has an addEventListener method that enables multiple handlers to subscribe to a single event.

public delegate void SomeHandler(Platform::String^ str);

public ref class LangSample sealed
{
public:
    event SomeHandler^ someEvent;
    property Platform::String^ PropertyA;

    // Method that fires an event
    void FireEvent(Platform::String^ str)
    {
        someEvent(Platform::String::Concat(str, PropertyA->ToString()));
    }
    //...
};
// Add two event handlers
var multicast1 = function (ev) {
    document.getElementById('P11').innerHTML = "Handler 1: " + ev.target;
};
var multicast2 = function (ev) {
    document.getElementById('P12').innerHTML = "Handler 2: " + ev.target;
};

var nativeObject = new CppComponent.LangSample();
//Subscribe to the same event
nativeObject.addEventListener("someevent", multicast1);
nativeObject.addEventListener("someevent", multicast2);

nativeObject.propertyA = "42";

// This method should fire an event
nativeObject.fireEvent("The answer is ");

В C# любое количество обработчиков событий может подписаться на событие с помощью оператора +=, как показано в предыдущем примере.In C#, any number of event handlers can subscribe to the event by using the += operator as shown in the previous example.

ПеречисленияEnums

Перечисление среда выполнения Windows в C++/CX объявляется с помощью перечислителя открытого класса. Он напоминает перечисление с областью действия в стандартном C++.A Windows Runtime enum in C++/CX is declared by using public class enum; it resembles a scoped enum in standard C++.

public enum class Direction {North, South, East, West};

public ref class EnumExampleClass sealed
{
public:
    property Direction CurrentDirection
    {
        Direction  get(){return m_direction; }
    }

private:
    Direction m_direction;
};

Значения перечисления передаются между C++/CX и JavaScript как целыми числами.Enum values are passed between C++/CX and JavaScript as integers. При необходимости можно объявить объект JavaScript, содержащий те же именованные значения, что и перечисление C++/CX, и использовать его следующим образом.You can optionally declare a JavaScript object that contains the same named values as the C++/CX enum and use it as follows.

var Direction = { 0: "North", 1: "South", 2: "East", 3: "West" };
//. . .

var nativeObject = new CppComponent.EnumExampleClass();
var curDirection = nativeObject.currentDirection;
document.getElementById('P13').innerHTML =
Direction[curDirection];

Перечисления поддерживаются как в C#, так и в Visual Basic.Both C# and Visual Basic have language support for enums. Эти языки видят открытый класс enum C++ так же, как и перечисление .NET.These languages see a C++ public enum class just as they would see a .NET enum.

Асинхронные методыAsynchronous methods

Чтобы использовать асинхронные методы, предоставляемые другими объектами среды выполнения Windows, используйте класс task (среда выполнения с параллелизмом).To consume asynchronous methods that are exposed by other Windows Runtime objects, use the task Class (Concurrency Runtime). Дополнительные сведения см. в разделе Параллелизм задач (среда выполнения с параллелизмом).For more information, see and Task Parallelism (Concurrency Runtime).

Чтобы реализовать асинхронные методы в C++/CX, используйте функцию Create _ Async , определенную в из ppltasks. h.To implement asynchronous methods in C++/CX, use the create_async function that's defined in ppltasks.h. Дополнительные сведения см. в разделе Создание асинхронных операций в C++/CX для приложений UWP.For more information, see Creating Asynchronous Operations in C++/CX for UWP apps. Пример см. в разделе Пошаговое руководство по созданию компонента C++/cx среда выполнения Windows и его вызов из JavaScript или C#.For an example, see Walkthrough of creating a C++/CX Windows Runtime component, and calling it from JavaScript or C#. Языки .NET используют асинхронные методы C++/CX так же, как и любой асинхронный метод, определенный в .NET.The .NET languages consume C++/CX asynchronous methods just as they would any asynchronous method that's defined in .NET.

ИсключенияExceptions

Можно создавать исключения любого типа, определенного в среде выполнения Windows.You can throw any exception type that's defined by the Windows Runtime. От типов исключений среды выполнения Windows нельзя наследовать пользовательские типы.You cannot derive custom types from any Windows Runtime exception type. Однако можно создать исключение COMException и предоставить пользовательский объект HRESULT, который может быть доступен для кода, перехватывающего исключение.However, you can throw COMException and provide a custom HRESULT that can be accessed by the code that catches the exception. Способы задания пользовательского сообщения в исключении COMException не предусмотрены.There's no way to specify a custom Message in a COMException.

Советы по отладкеDebugging tips

При отладке решения JavaScript, содержащего библиотеку DLL компонента, можно настроить отладчик для пошагового выполнения скрипта или машинного кода в компоненте, однако нельзя отлаживать эти части одновременно.When you debug a JavaScript solution that has a component DLL, you can set the debugger to enable either stepping through script, or stepping through native code in the component, but not both at the same time. Чтобы изменить этот параметр, разверните узел проекта JavaScript в обозревателе решений, а затем последовательно выберите пункты Свойства, Отладка, Тип отладчика.To change the setting, select the JavaScript project node in Solution Explorer and then choose Properties, Debugging, Debugger Type.

Обязательно выберите соответствующие возможности в конструкторе пакетов.Be sure to select appropriate capabilities in the package designer. Например, если вы пытаетесь открыть файл образа в библиотеке изображений пользователя с помощью интерфейсов API среды выполнения Windows, необходимо установить флажок Библиотека изображений в области Возможности конструктора манифестов.For example, if you are attempting to open an image file in the user's Pictures library by using the Windows Runtime APIs, be sure to select the Pictures Library check box in the Capabilities pane of the manifest designer.

Если коду JavaScript не удается распознать открытые свойства или методы в компоненте, убедитесь, что в JavaScript используется "верблюжий" стиль имен.If your JavaScript code doesn't seem to be recognizing the public properties or methods in the component, make sure that in JavaScript you are using camel casing. Например, в JavaScript метод Логкалк C++/CX должен ссылаться как на Логкалк.For example, the LogCalc C++/CX method must be referenced as logCalc in JavaScript.

Если удалить проект компонента C++/CX среда выполнения Windows из решения, необходимо также вручную удалить ссылку на проект из проекта JavaScript.If you remove a C++/CX Windows Runtime component project from a solution, you must also manually remove the project reference from the JavaScript project. Невыполнение этого требования приведет к невозможности последующей отладки и сборки.Failure to do so prevents subsequent debug or build operations. При необходимости можно добавить ссылку на сборку в библиотеку DLL.If necessary, you can then add an assembly reference to the DLL.