Share via


Création de composants Windows Runtime en C# et Visual Basic

Avec .NET Framework 4.5, vous pouvez utiliser du code managé pour créer vos propres types Windows Runtime, empaquetés dans un composant Windows Runtime. Vous pouvez utiliser votre composant dans les applications de Windows Store avec C++, JavaScript, Visual Basic ou C#. Cet article décrit la création des règles d'un composant, et présente certains aspects de la prise en charge du .NET Framework pour Windows Runtime. Cette prise en charge est en général conçue pour être transparente au programmeur .NET Framework. Toutefois, lorsque vous créez un composant à utiliser avec JavaScript ou C++, vous devez connaître les différences quant à la manière dont ces langages prennent en charge Windows Runtime.

Notes

Si vous créez un composant destiné uniquement aux applications de Windows Store avec Visual Basic ou C#, et qu'il ne contient pas de contrôles Windows Store, utilisez le modèle Bibliothèque de classes (applications du Windows Store) au lieu du modèle du Composant Windows Runtime. Il existe moins de restrictions sur une bibliothèque de classes simple.

Cet article contient les sections suivantes :

  • Déclaration des types dans les composants Windows Runtime

  • Débogage de votre composant

  • Passage des types Windows Runtime au code managé

  • Passage des types gérés au Windows Runtime

  • Tableaux de passage

  • Méthodes surchargées

  • Opérations asynchrones

  • Levée des exceptions

  • Déclaration et déclenchement des événements

Déclaration des types dans des composants Windows Runtime

En interne, les types Windows Runtime de votre composant peuvent utiliser toutes les fonctionnalités du .NET Framework qui sont autorisées dans une application Windows Store. (Consultez Vue d'ensemble de .NET pour les applications Windows Store pour plus d'informations.) En externe, les membres de vos types peuvent exposer uniquement les types Windows Runtime pour leurs paramètres et valeurs de retour. La liste suivante décrit les restrictions relatives aux types.NET Framework qui sont exposées à partir des composants Windows Runtime.

  • Les champs, les paramètres et les valeurs de retour de tous les membres et les types publics de votre composant doivent être des types Windows Runtime.

    Cette restriction inclut les types Windows Runtime que vous créez ainsi que des types fournis par Windows Runtime lui-même. Elle inclut également un certain nombre de types .NET Framework. L'inclusion de ces types fait partie du support que le .NET Framework fournit pour activer l'utilisation naturelle de Windows Runtime dans le code managé : votre code donne l'impression d'utiliser les types familiers .NET Framework au lieu des types Windows Runtime sous-jacents. Par exemple, vous pouvez utiliser des types primitifs .NET Framework tels que Int32 et Double, certains types fondamentaux tels que DateTimeOffset et Uri, et certains types d'interfaces génériques couramment utilisés comme IEnumerable<T> (IEnumerable(Of T) en Visual Basic) et IDictionary<TKey,TValue>. (Notez que les arguments de type de ces types génériques doivent être des types Windows Runtime.) Cela est décrit dans les sections Passage des types Windows Runtime au code managé et Passage des types gérés au Windows Runtime, ultérieurement dans cet article.

  • Les classes et les interfaces publiques peuvent contenir des méthodes, des propriétés, et des événements. Vous pouvez déclarer des délégués pour les événements, ou utilisez le délégué EventHandler<T>. Une classe ou une interface publique ne peut pas :

    • Être générique.

    • Implémenter une interface qui n'est pas une interface Windows Runtime racine. (Toutefois, vous pouvez créer vos propres interfaces Windows Runtime et les implémenter.)

    • Dériver de types qui ne sont pas dans Windows Runtime, tels que System.Exception et System.EventArgs.

  • Tous les types publics doivent avoir un espace de noms racine qui correspond au nom de l'assembly, et le nom de l'assembly ne doit pas commencer par « Windows ».

    Notes

    Par défaut, les projets Visual Studio ont des noms d'espaces de noms qui correspondent au nom de l'assembly. En Visual Basic, l'instruction Namespace pour cet espace de noms par défaut n'est pas affichée dans votre code.

  • Les structures publiques ne peuvent pas avoir d'autres membres que les champs publics, et ces champs doivent être des types valeur ou des chaînes.

  • Les classes public doivent être sealed (NotInheritable en Visual Basic). Si votre modèle de programmation requiert le polymorphisme, vous pouvez créer une interface publique et implémenter cette interface sur les classes qui doivent être polymorphes.

Débogage de votre composant

Si votre application de Windows Store et votre composant sont générés avec du code managé, vous pouvez les déboguer en même temps.

Lorsque vous testez votre composant dans le cadre d'une application de Windows Store à l'aide de C++, vous pouvez déboguer du code managé et natif en même temps. La valeur par défaut est le code natif uniquement.

Pour déboguer à la fois du code C++ natif et managé

  1. Ouvrez le menu contextuel pour votre projet Visual C++, puis choisissez Propriétés.

  2. Dans les pages de propriétés, sous Propriétés de configuration, choisissez Débogage.

  3. Choisissez Type de débogueur, et dans la zone de liste déroulante remplacez Natif uniquement par Mixte (managé et natif). Cliquez sur OK.

  4. Définissez les points d'arrêt dans le code natif et managé.

Lorsque vous testez votre composant dans le cadre d'une application de Windows Store à l'aide de JavaScript, par défaut la solution figure dans la procédure de débogage JavaScript. Dans Visual Studio 2012 et Visual Studio Express 2012 pour Windows 8, vous ne pouvez pas déboguer en même temps JavaScript et le code managé.

Pour déboguer du code managé au lieu de JavaScript

  1. Ouvrez le menu contextuel pour votre projet JavaScript, puis choisissez Propriétés.

  2. Dans les pages de propriétés, sous Propriétés de configuration, choisissez Débogage.

  3. Choisissez Type de débogueur, et dans la zone de liste déroulante remplacez Script uniquement par Managé uniquement. Cliquez sur OK.

  4. Définissez les points d'arrêt dans le code managé et procédez au débogage comme d'habitude.

Passage des types Windows Runtime au code managé

Comme indiqué précédemment dans la section Déclaration des types dans les composants Windows Runtime, certains types.NET Framework peuvent s'afficher dans les signatures des membres des classes publiques. Cela fait partie du support que .NET Framework fournit pour activer l'utilisation naturelle de Windows Runtime en code managé. Il inclut des types primitifs et certaines classes et interfaces. Lorsque votre composant est utilisé à partir de JavaScript ou du code C++, il est important de savoir comment vos types .NET Framework s'affichent pour l'appelant. Consultez Procédure pas à pas : création d'un composant simple en C# ou Visual Basic et appel de ce composant depuis JavaScript pour obtenir des exemples de JavaScript. Cette section décrit les types utilisés.

Dans .NET Framework, les types primitifs, comme la structure Int32 ont de nombreuses propriétés et méthodes utiles, telles que la méthode TryParse. En revanche, les types primitifs et les structures dans Windows Runtime ont uniquement des champs. Lorsque vous transmettez ces types au code managé, ils semblent être des types .NET Framework, et vous pouvez en utiliser les propriétés et les méthodes comme vous le faites habituellement. La liste suivante résume les substitutions qui sont effectuées automatiquement dans l'IDE :

  • Pour les primitives Windows Runtime Int32, Int64, Single, Double, Boolean, String (une collection immuables de caractères Unicode), Enum, UInt32, UInt64 et Guid, utilisez le type portant le même nom que dans l'espace de noms System.

  • Pour UInt8, utilisez System.Byte.

  • Pour Char16, utilisez System.Char.

  • Pour l'interface IInspectable, utilisez System.Object.

Si C# ou Visual Basic fournit un mot clé de langage pour l'un de ces types, vous pouvez utiliser le mot clé de langage à la place.

En plus des types primitifs, certains types Windows Runtime basiques fréquemment utilisés apparaissent dans le code managé sous la forme de leurs équivalents .NET Framework. Supposons, par exemple, que votre code JavaScript utilise la classe Windows.Foundation.Uri et que vous souhaitiez la passer à une méthode C# ou Visual Basic. Le type équivalent dans le code managé est la classe .NET Framework System.Uri, il s'agit du type à utiliser pour le paramètre de méthode. Vous pouvez indiquer lorsqu'un type Windows Runtime apparaît comme type .NET Framework, car IntelliSense dans Visual Studio masque le type Windows Runtime lorsque vous écrivez du code managé, et répertorie le type .NET Framework équivalent. (Généralement les deux types ont le même nom. Toutefois, notez que la structure Windows.Foundation.DateTime apparaît dans le code managé comme System.DateTimeOffset et non comme System.DateTime.)

Pour certains types de collections fréquemment utilisées, le mappage s'effectue entre les interfaces implémentées par un type Windows Runtime et les interfaces qui sont implémentées par le type .NET Framework correspondant. Comme avec les types mentionnés ci-dessus, vous déclarez les types de paramètre à l'aide du type .NET Framework. Cela masque certaines différences entre les types et rend l'écriture du code.NET Framework plus naturelle. Le tableau suivant répertorie les plus courants de ces types d'interfaces génériques, ainsi que d'autres mappages de classe et d'interface courants. Pour obtenir une liste complète des types Windows Runtime mappés par .NET Framework, consultez Mappages .NET Framework des types Windows Runtime.

Windows Runtime

.NET Framework

IIterable<T>

IEnumerable<T>

IVector<T>

IList<T>

IVectorView<T>

IReadOnlyList<T>

IMap<K, V>

IDictionary<TKey, TValue>

IMapView<K, V>

IReadOnlyDictionary<TKey, TValue>

IKeyValuePair<K, V>

KeyValuePair<TKey, TValue>

IBindableIterable

IEnumerable

IBindableVector

IList

Windows.UI.Xaml.Data.INotifyPropertyChanged

System.ComponentModel.INotifyPropertyChanged

Windows.UI.Xaml.Data.PropertyChangedEventHandler

System.ComponentModel.PropertyChangedEventHandler

Windows.UI.Xaml.Data.PropertyChangedEventArgs

System.ComponentModel.PropertyChangedEventArgs

    

Lorsqu'un type implémente plusieurs interfaces, vous pouvez utiliser n'importe laquelle d'entre elles comme type de paramètre ou type de retour d'un membre. Par exemple, vous pouvez passer ou retourner un Dictionary<int, string> (Dictionary(Of Integer, String) en Visual Basic) comme IDictionary<int, string>, IReadOnlyDictionary<int, string>, ou IEnumerable<System.Collections.Generic.KeyValuePair<TKey, TValue>>.

Important

JavaScript utilise l'interface qui apparaît en premier dans la liste des interfaces implémentées par un type managé. Par exemple, si vous retournez Dictionary<int, string> au code JavaScript, il apparaît comme IDictionary<int, string> quelle que soit l'interface que vous spécifiez comme type de retour. Cela signifie que si la première interface n'inclut pas un membre qui apparaît sur les interfaces ultérieures, ce membre n'est pas visible dans JavaScript.

Dans Windows Runtime, IMap<K, V> et IMapView<K, V> sont itérés à l'aide de IKeyValuePair. Lorsque vous les passez au code managé, ils apparaissent comme IDictionary<TKey, TValue> et IReadOnlyDictionary<TKey, TValue>, donc bien sûr vous utilisez System.Collections.Generic.KeyValuePair<TKey, TValue> pour les énumérer.

La façon dont les interfaces apparaissent dans le code managé affecte la façon dont les types qui implémentent ces interfaces apparaissent. Par exemple, la classe PropertySet implémente IMap<K, V>, qui s'affiche dans le code managé sous la forme de IDictionary<TKey, TValue>. PropertySet apparaît comme s'il a implémenté IDictionary<TKey, TValue> au lieu de IMap<K, V>, donc en code managé une méthode Add semble se comporter comme la méthode Add sur les dictionnaires .NET Framework. Il ne semble pas avoir de méthode Insert. Vous pouvez voir cet exemple dans l'article Procédure pas à pas : création d'un composant simple en C# ou Visual Basic et appel de ce composant depuis JavaScript.

Passage des types gérés au Windows Runtime

Comme décrit dans la section précédente, certains types Windows Runtime peuvent apparaître comme des types .NET Framework dans les signatures des membres de votre composant, ou dans les signatures des membres Windows Runtime lorsque vous les utilisez dans l'IDE. Lorsque vous passez des types .NET Framework à ces membres ou les utiliser comme valeurs de retour des membres de votre composant, ils apparaissent dans le code de l'autre côté comme type Windows Runtime correspondant. Pour obtenir des exemples des effets que cela peut avoir lorsque votre composant est appelé à partir de JavaScript, consultez la section « Retour des types managés à partir de votre composant » dans Procédure pas à pas : création d'un composant simple en C# ou Visual Basic et appel de ce composant depuis JavaScript.

Tableaux de passage

Dans Windows Runtime, tous les paramètres sont pour l'entrée ou pour la sortie ; il n'y a aucun paramètre ref (ByRef en Visual Basic). Le contenu des tableaux passés à votre composant Windows Runtime doit être destiné pour l'entrée ou la sortie. Autrement dit, les tableaux ne doivent pas être considérés comme mutables. Si un tableau est passé par la valeur (ByVal en Visual Basic), vous devez appliquer l'attribut ReadOnlyArrayAttribute ou l'attribut WriteOnlyArrayAttribute pour générer l'intention. Consultez Transmission de tableaux à un composant Windows Runtime.

Méthodes surchargées

Dans Windows Runtime, les méthodes peuvent être surchargées. Toutefois, si vous déclarez plusieurs surcharges avec le même nombre de paramètres, vous devez appliquer l'attribut Windows.Foundation.Metadata.DefaultOverloadAttribute à une seule de ces surcharges. Cette surcharge est la seule que vous pouvez appeler de JavaScript. Par exemple, dans le code suivant la surcharge qui prend int (Integer en Visual Basic) est la surcharge par défaut.

        public string OverloadExample(string s)
        {
            return s;
        }
        [Windows.Foundation.Metadata.DefaultOverload()] 
        public int OverloadExample(int x)
        {
            return x;
        } 
    Public Function OverloadExample(ByVal s As String) As String
        Return s
    End Function
    <Windows.Foundation.Metadata.DefaultOverload> _
    Public Function OverloadExample(ByVal x As Integer) As Integer
        Return x
    End Function

Avertissement

JavaScript vous permet de passer n'importe quelle valeur à OverloadExample, et force la valeur dans le type requis par le paramètre. Vous pouvez appeler OverloadExample avec « quarante-deux », « 42 ", ou 42,3, mais toutes ces valeurs sont passées à la surcharge par défaut. La surcharge par défaut dans l'exemple précédent retourne 0, 42 et 42, respectivement.

Vous ne pouvez pas appliquer l'attribut DefaultOverloadAttribute aux constructeurs. Tous les constructeurs d'une classe doivent avoir des nombres de paramètres différents.

Opérations asynchrones

Pour implémenter une méthode asynchrone dans votre composant, ajoutez « Async » à la fin du nom de la méthode et retournez une des interfaces Windows Runtime qui représentent des actions ou des opérations asynchrones : IAsyncActionIAsyncActionWithProgress<TProgress>IAsyncOperation<TResult>, ou IAsyncOperationWithProgress<TResult, TProgress>.

Vous pouvez utiliser des tâches .NET Framework (la classe Task et la classe Task<TResult> générique) pour implémenter votre méthode asynchrone. Vous devez retourner une tâche qui représente une opération en cours, telle qu'une tâche qui est retournée à partir d'une méthode asynchrone écrite en C# ou en Visual Basic, ou une tâche retournée à partir de la méthode Task.Run. Si vous utilisez un constructeur pour créer une tâche, vous devez appeler sa méthode Task.Start avant de la retourner.

Une méthode qui utilise await (Await en Visual Basic) nécessite le mot clé async (Async en Visual Basic). Si vous exposez une telle méthode à partir d'un composant Windows Runtime, appliquez le mot clé async au délégué que vous passez à la méthode Run.

Pour les actions et les opérations asynchrones qui ne prennent pas en charge l'annulation ou le rapport de progression, vous pouvez utiliser la méthode d'extension WindowsRuntimeSystemExtensions.AsAsyncAction ou AsAsyncOperation<TResult> pour encapsuler la tâche dans l'interface appropriée. Par exemple, le code suivant implémente une méthode asynchrone à l'aide de la méthode Task.Run pour lancer une tâche. La méthode d'extension AsAsyncOperation<TResult> retourne la tâche comme opération asynchrone Windows Runtime.

        public static IAsyncOperation<IList<string>> DownloadAsStringsAsync(string id)
        {
            return Task.Run<IList<string>>(async () =>
            {
                var data = await DownloadDataAsync(id);
                return ExtractStrings(data);
            }).AsAsyncOperation();
        }


    Public Shared Function DownloadAsStringsAsync(ByVal id As String) _
         As IAsyncOperation(Of IList(Of String))

        Return Task.Run(Of IList(Of String))(
            Async Function()
                Dim data = Await DownloadDataAsync(id)
                Return ExtractStrings(data)
            End Function).AsAsyncOperation()
    End Function


Le code JavaScript suivant montre comment la méthode peut être appelée à l'aide d'un objet WinJS.Promise. La fonction qui est passée à la méthode puis est exécutée à la fin de l'appel asynchrone. Le paramètre stringList contient la liste des chaînes qui est retournée par la méthode DownloadAsStringAsync, et la fonction exécute tout ce qui est requis par le traitement.

function asyncExample(id) {

    var result = SampleComponent.Example.downloadAsStringAsync(id).then(
        function (stringList) {
            // Place code that uses the returned list of strings here.
        });
}

Pour les actions et les opérations asynchrones qui prennent en charge l'annulation ou progression l'enregistrement, utilisez la classe d' AsyncInfo pour générer une tâche démarrée et pour connecter l'annulation et la progression des fonctionnalités de création de rapports de la tâche avec l'annulation et la progression des fonctionnalités de création de rapports de l'interface appropriée d' Windows Runtime. Pour obtenir un exemple qui prend en charge à la fois l'annulation et le rapport de progression, consultez Procédure pas à pas : création d'un composant simple en C# ou Visual Basic et appel de ce composant depuis JavaScript.

Notez que vous pouvez utiliser les méthodes de classe AsyncInfo même si votre méthode asynchrone ne prend pas en charge l'annulation ou le rapport de progression. Si vous utilisez une fonction lambda en Visual Basic ou une méthode anonyme C#, ne fournissez pas de paramètres pour le jeton et l'interface IProgress<T>. Si vous utilisez une fonction lambda en C#, fournissez un paramètre de jeton mais ignorez- le. L'exemple précédent, qui a utilisé la méthode AsAsyncOperation<TResult>, ressemble à ceci lorsque vous utilisez la surcharge de méthode AsyncInfo.Run<TResult>(Func<CancellationToken, Task<TResult>>) à la place :

        public static IAsyncOperation<IList<string>> DownloadAsStringsAsync(string id)
        {
            return AsyncInfo.Run<IList<string>>(async (token) =>
            {
                var data = await DownloadDataAsync(id);
                return ExtractStrings(data);
            });
        }
    Public Shared Function DownloadAsStringsAsync(ByVal id As String) _
        As IAsyncOperation(Of IList(Of String))

        Return AsyncInfo.Run(Of IList(Of String))(
            Async Function()
                Dim data = Await DownloadDataAsync(id)
                Return ExtractStrings(data)
            End Function)
    End Function

Si vous créez une méthode asynchrone qui peut également prendre en charge l'enregistrement d'annulation ou de progression, ajoutez des surcharges qui n'ont pas de paramètres pour un jeton d'annulation ou l'interface IProgress<T>.

Levée des exceptions

Vous pouvez lever n'importe quel type d'exception qui est inclus dans les .NET pour les applications Windows Store - API prises en charge. Vous ne pouvez pas déclarer vos propres types d'exception publics dans un composant Windows Runtime, mais vous pouvez déclarer et lever des types non publics.

Si votre composant ne gère pas l'exception, une exception correspondante est levée dans le code ayant appelé votre composant. La façon dont l'exception s'affiche pour l'appelant dépend de la méthode dont son langage prend en charge Windows Runtime.

  • Dans JavaScript, l'exception apparaît comme un objet dans lequel le message d'exception est remplacé par une trace de la pile. Lorsque vous déboguez votre application dans Visual Studio, vous pouvez voir le texte du message d'origine affiché dans la boîte de dialogue d'exception du débogueur, identifié comme « WinRT Information ». Vous ne pouvez pas accéder au texte du message d'origine depuis le code JavaScript.

    Notes

    La trace de la pile contient actuellement le type d'exception managé, mais il n'est pas recommandé d'analyser la trace pour identifier le type d'exception. Utilisez plutôt une valeur HRESULT, décrite plus loin dans cette section.

  • En C++, l'exception apparaît comme une exception de plateforme. Si la propriété HResult de l'expression managée peut être mappée au HRESULT d'une exception de plateforme spécifique, l'exception spécifique est utilisée. Dans le cas contraire, une exception Platform::COMException est levée. Le texte du message de l'exception managée n'est pas disponible en code C++. Si une exception de plateforme spécifique est levée, le texte du message par défaut pour ce type d'exception apparaît. Dans le cas contraire, aucun texte de message n'apparaît. Consultez Exceptions (C++/CX).

  • En C# ou en Visual Basic, l'exception est une exception managée normale.

Lorsque vous levez une exception de votre composant, vous pouvez permettre plus facilement à l'appelant de gérer l'exception en levant un type d'exception non public dont la valeur de la propriété HResult est spécifique à votre composant. Le HRESULT est disponible pour un appelant JavaScript via la propriété number de l'objet de l'exception, et pour un appelant C++ via la propriété COMException::HResult.

Notes

Utilisez une valeur négative pour votre HRESULT. Une valeur positive est interprétée comme une réussite et aucune exception n'est levée dans l'appelant JavaScript ou C++.

Déclaration et déclenchement des événements

Lorsque vous déclarez un type pour contenir les données de votre événement, dérivez de Object au lieu de EventArgs, car EventArgs n'est pas un type Windows Runtime. Utilisez EventHandler<TEventArgs> comme type de l'événement, et utilisez votre type d'argument d'événement comme argument de type générique. Déclenchez l'événement comme dans une application .NET Framework.

Lorsque votre composant Windows Runtime est utilisé à partir de JavaScript ou de C++, l'événement respecte le modèle d'événement Windows Runtime que ces langages s'attendent. Lorsque vous utilisez le composant à partir de C# ou de Visual Basic, l'événement apparaît comme un événement ordinaire .NET Framework. Un exemple est fourni dans Procédure pas à pas : création d'un composant simple en C# ou Visual Basic et appel de ce composant depuis JavaScript.

Si vous implémentez les accesseurs d'événement personnalisés (si vous déclarez un événement avec le mot clé Custom, dans Visual Basic), vous devez suivre le modèle d'événement Windows Runtime dans votre implémentation. Consultez Événements personnalisés et accesseurs d'événement dans les composants Windows Runtime. Notez que lorsque vous gérez l'événement à partir de C# ou du code Visual Basic, il apparaît toujours comme un événement ordinaire .NET Framework.

Voir aussi

Concepts

Vue d'ensemble de .NET pour les applications Windows Store

.NET pour les applications Windows Store - API prises en charge

Procédure pas à pas : création d'un composant simple en C# ou Visual Basic et appel de ce composant depuis JavaScript

Création de composants Windows Runtime

Événements personnalisés et accesseurs d'événement dans les composants Windows Runtime

Transmission de tableaux à un composant Windows Runtime

Mappages .NET Framework des types Windows Runtime

Diagnostic des conditions d'erreur du composant Windows Runtime