Propriétés jointes personnaliséesCustom attached properties

Une propriété jointe est un concept XAML.An attached property is a XAML concept. Les propriétés jointes sont généralement définies comme une forme spécialisée de propriété de dépendance.Attached properties are typically defined as a specialized form of dependency property. Cette rubrique explique comment implémenter une propriété jointe en tant que propriété de dépendance et comment définir la convention d’accesseur nécessaire pour que votre propriété jointe soit utilisable en XAML.This topic explains how to implement an attached property as a dependency property and how to define the accessor convention that is necessary for your attached property to be usable in XAML.

PrérequisPrerequisites

Nous supposons que vous comprenez les propriétés de dépendance du point de vue d’un consommateur de propriétés de dépendance existantes et que vous avez lu la vue d’ensemble des propriétés de dépendance.We assume that you understand dependency properties from the perspective of a consumer of existing dependency properties, and that you have read the Dependency properties overview. Vous devez aussi avoir lu la vue d’ensemble des propriétés jointes.You should also have read Attached properties overview. Pour suivre les exemples de cette rubrique, vous devez également comprendre le langage XAML et savoir comment écrire une application Windows Runtime de base en C++, C# ou Visual Basic.To follow the examples in this topic, you should also understand XAML and know how to write a basic Windows Runtime app using C++, C#, or Visual Basic.

Scénarios de propriétés jointesScenarios for attached properties

Vous pourriez créer une propriété jointe quand il y a une raison de disposer d’un mécanisme de définition de propriété pour les classes autres que la classe de définition.You might create an attached property when there is a reason to have a property-setting mechanism available for classes other than the defining class. Les scénarios les plus courants concernent la prise en charge des services et de la disposition.The most common scenarios for this are layout and services support. Canvas. ZIndex et Canvas. Topsont des exemples de propriétés de disposition existantes.Examples of existing layout properties are Canvas.ZIndex and Canvas.Top. Dans un scénario de disposition, les éléments qui existent en tant qu’éléments enfants d’éléments de contrôle de disposition peuvent exprimer des exigences de disposition à leurs éléments parents individuellement, chacun définissant une valeur de propriété que le parent définit comme une propriété jointe.In a layout scenario, elements that exist as child elements to layout-controlling elements can express layout requirements to their parent elements individually, each setting a property value that the parent defines as an attached property. Un exemple de scénario de prise en charge de services dans l’API Windows Runtime est l’ensemble de propriétés jointes de ScrollViewer, tel que ScrollViewer.IsZoomChainingEnabled.An example of the services-support scenario in the Windows Runtime API is set of the attached properties of ScrollViewer, such as ScrollViewer.IsZoomChainingEnabled.

Avertissement

Une limitation existante de l’implémentation XAML de Windows Runtime est que vous ne pouvez pas animer votre propriété jointe personnalisée.An existing limitation of the Windows Runtime XAML implementation is that you cannot animate your custom attached property.

Inscription d’une propriété jointe personnaliséeRegistering a custom attached property

Si vous définissez la propriété jointe strictement pour une utilisation sur d’autres types, la classe dans laquelle la propriété est inscrite n’a pas besoin d’être dérivée de DependencyObject.If you are defining the attached property strictly for use on other types, the class where the property is registered does not have to derive from DependencyObject. En revanche, vous devez faire en sorte que le paramètre cible des accesseurs utilise DependencyObject si vous suivez le modèle ordinaire selon lequel votre propriété jointe est également une propriété de dépendance, de manière à pouvoir utiliser la banque de propriétés de stockage.But you do need to have the target parameter for accessors use DependencyObject if you follow the typical model of having your attached property also be a dependency property, so that you can use the backing property store.

Définissez votre propriété jointe en tant que propriété de dépendance en déclarant une propriété public static readonly de type DependencyProperty.Define your attached property as a dependency property by declaring a public static readonly property of type DependencyProperty. Vous définissez cette propriété à l’aide de la valeur de retour de la méthode RegisterAttached.You define this property by using the return value of the RegisterAttached method. Le nom de la propriété doit correspondre à celui de la propriété jointe que vous spécifiez comme paramètre RegisterAttached name, avec la chaîne « Property » ajoutée à la fin.The property name must match the attached property name you specify as the RegisterAttached name parameter, with the string "Property" added to the end. Il s’agit de la convention établie pour l’affectation de noms aux identificateurs de propriétés de dépendance en fonction des propriétés qu’ils représentent.This is the established convention for naming the identifiers of dependency properties in relation to the properties that they represent.

La définition d’une propriété jointe personnalisée et d’une propriété de dépendance personnalisée diffèrent principalement dans la manière dont vous définissez les accesseurs ou wrappers.The main area where defining a custom attached property differs from a custom dependency property is in how you define the accessors or wrappers. Au lieu d’utiliser la technique d’enveloppement décrite dans Propriétés de dépendance personnalisées, vous devez également fournir des méthodes GetPropertyName et SetPropertyName statiques en tant qu’accesseurs pour la propriété jointe.Instead of the using the wrapper technique described in Custom dependency properties, you must also provide static GetPropertyName and SetPropertyName methods as accessors for the attached property. Les accesseurs sont utilisés principalement par l’analyseur XAML, bien que n’importe quel autre appelant puisse aussi les utiliser pour définir des valeurs dans les scénarios non-XAML.The accessors are used mostly by the XAML parser, although any other caller can also use them to set values in non-XAML scenarios.

Important

Si vous ne définissez pas correctement les accesseurs, le processeur XAML ne peut pas accéder à la propriété jointe et toute personne qui essaie de l’utiliser obtiendra probablement une erreur d’analyse XAML.If you don't define the accessors correctly, the XAML processor can't access your attached property and anyone who tries to use it will probably get a XAML parser error. En outre, les outils de conception et de codage s’appuient souvent sur les * conventions « propriété » pour nommer des identificateurs lorsqu’ils rencontrent une propriété de dépendance personnalisée dans un assembly référencé.Also, design and coding tools often rely on the "*Property" conventions for naming identifiers when they encounter a custom dependency property in a referenced assembly.

AccesseursAccessors

La signature de l’accesseur GetPropertyName doit être la suivante.The signature for the GetPropertyName accessor must be this.

public static valueType GetPropertyName (DependencyObject target)public static valueType GetPropertyName (DependencyObject target)

Pour Microsoft Visual Basic, il s’agit de ceci.For Microsoft Visual Basic, it is this.

Public Shared Function GetPropertyName (ByVal target As DependencyObject) As ValueType)Public Shared Function GetPropertyName(ByVal target As DependencyObject) As valueType)

L’objet target peut être d’un type plus spécifique dans votre implémentation, mais il doit dériver de DependencyObject.The target object can be of a more specific type in your implementation, but must derive from DependencyObject. La valeur de retour valueType peut aussi être d’un type plus spécifique dans votre implémentation.The valueType return value can also be of a more specific type in your implementation. Le type Object de base est acceptable, mais bien souvent vous souhaiterez que votre propriété jointe applique la sécurité de type.The basic Object type is acceptable, but often you'll want your attached property to enforce type safety. Le recours au typage dans les signatures getter et setter est une technique de sécurisation de type recommandée.The use of typing in the getter and setter signatures is a recommended type-safety technique.

La signature de l’accesseur SetPropertyName doit être la suivante.The signature for the SetPropertyName accessor must be this.

public static void SetPropertyName (DependencyObject target , ValueType value)public static void SetPropertyName(DependencyObject target ,valueType value)

Pour Visual Basic, il s’agit de ceci.For Visual Basic, it is this.

Public Shared Sub SetPropertyName (ByVal target As DependencyObject, ByVal value As ValueType)Public Shared Sub SetPropertyName(ByVal target As DependencyObject, ByVal value AsvalueType)

L’objet target peut être d’un type plus spécifique dans votre implémentation, mais il doit dériver de DependencyObject.The target object can be of a more specific type in your implementation, but must derive from DependencyObject. L’objet value et son valueType peuvent aussi être d’un type plus spécifique dans votre implémentation.The value object and its valueType can be of a more specific type in your implementation. Souvenez-vous que la valeur de cette méthode est l’entrée qui provient du processeur XAML quand elle rencontre votre propriété jointe dans le balisage.Remember that the value for this method is the input that comes from the XAML processor when it encounters your attached property in markup. Il doit exister une conversion de type ou une prise en charge de l’extension de balisage existant pour le type que vous utilisez, afin que le type approprié puisse être créé à partir de la valeur d’un attribut (qui n’est en fin de compte qu’une chaîne).There must be type conversion or existing markup extension support for the type you use, so that the appropriate type can be created from an attribute value (which is ultimately just a string). Le type Object de base est acceptable, mais bien souvent vous souhaiterez bénéficier d’une sécurité de type supplémentaire.The basic Object type is acceptable, but often you'll want further type safety. Pour cela, placez l’application du type dans les accesseurs.To accomplish that, put type enforcement in the accessors.

Notes

Il est également possible de définir une propriété jointe dans laquelle l’utilisation prévue s’effectue par le biais de la syntaxe d’élément de propriété.It's also possible to define an attached property where the intended usage is through property element syntax. Dans ce cas, vous n’avez pas besoin de conversion de type pour les valeurs, mais vous devez vous assurer que les valeurs envisagées peuvent être construites en XAML.In that case you don't need type conversion for the values, but you do need to assure that the values you intend can be constructed in XAML. VisualStateManager. VisualStateGroups est un exemple de propriété jointe existante qui prend uniquement en charge l’utilisation des éléments de propriété.VisualStateManager.VisualStateGroups is an example of an existing attached property that only supports property element usage.

Exemple de codeCode example

Cet exemple illustre l’inscription de propriété de dépendance (à l’aide de la méthode RegisterAttached), ainsi que les accesseurs Get et Set, pour une propriété jointe personnalisée.This example shows the dependency property registration (using the RegisterAttached method), as well as the Get and Set accessors, for a custom attached property. Dans cet exemple, le nom de la propriété jointe est IsMovable.In the example, the attached property name is IsMovable. Les accesseurs doivent donc être nommés GetIsMovable et SetIsMovable.Therefore, the accessors must be named GetIsMovable and SetIsMovable. Le propriétaire de la propriété jointe est une classe de service nommée GameService qui ne possède pas sa propre interface utilisateur. Son seul objectif est de fournir les services de propriété jointe lorsque la propriété jointe GameService.IsMovable est utilisée.The owner of the attached property is a service class named GameService that doesn't have a UI of its own; its purpose is only to provide the attached property services when the GameService.IsMovable attached property is used.

La définition de la propriété jointe en C++/CX est un peu plus complexe.Defining the attached property in C++/CX is a bit more complex. Vous devez décider de la factorisation entre fichier de code et en-tête.You have to decide how to factor between the header and code file. De plus, vous devez exposer l’identificateur en tant que propriété uniquement avec un accesseur get, pour les raisons discutées dans Propriétés de dépendance personnalisées.Also, you should expose the identifier as a property with only a get accessor, for reasons discussed in Custom dependency properties. En C++/CX, vous devez définir explicitement cette relation de champ de propriété plutôt que de vous appuyer sur le Keywords ReadOnly .net et la sauvegarde implicite de propriétés simples.In C++/CX you must define this property-field relationship explicitly rather than relying on .NET readonly keywording and implicit backing of simple properties. Vous devez également inscrire la propriété jointe au sein d’une fonction d’assistance. Celle-ci n’est exécutée qu’une seule fois au démarrage de l’application, avant le chargement de toute page XAML nécessitant la propriété jointe.You also need to perform the registration of the attached property within a helper function that only gets run once, when the app first starts but before any XAML pages that need the attached property are loaded. L’emplacement classique où appeler vos fonctions d’assistance d’inscription de propriété pour toutes les dépendances ou propriétés jointes est issu du / constructeur d'application d’application dans le code de votre fichier app. Xaml.The typical place to call your property registration helper functions for any and all dependency or attached properties is from within the App / Application constructor in the code for your app.xaml file.

public class GameService : DependencyObject
{
    public static readonly DependencyProperty IsMovableProperty = 
    DependencyProperty.RegisterAttached(
      "IsMovable",
      typeof(Boolean),
      typeof(GameService),
      new PropertyMetadata(false)
    );
    public static void SetIsMovable(UIElement element, Boolean value)
    {
        element.SetValue(IsMovableProperty, value);
    }
    public static Boolean GetIsMovable(UIElement element)
    {
        return (Boolean)element.GetValue(IsMovableProperty);
    }
}
Public Class GameService
    Inherits DependencyObject

    Public Shared ReadOnly IsMovableProperty As DependencyProperty = 
        DependencyProperty.RegisterAttached("IsMovable",  
        GetType(Boolean), 
        GetType(GameService), 
        New PropertyMetadata(False))

    Public Shared Sub SetIsMovable(ByRef element As UIElement, value As Boolean)
        element.SetValue(IsMovableProperty, value)
    End Sub

    Public Shared Function GetIsMovable(ByRef element As UIElement) As Boolean
        GetIsMovable = CBool(element.GetValue(IsMovableProperty))
    End Function
End Class
// GameService.idl
namespace UserAndCustomControls
{
    [default_interface]
    runtimeclass GameService : Windows.UI.Xaml.DependencyObject
    {
        GameService();
        static Windows.UI.Xaml.DependencyProperty IsMovableProperty{ get; };
        static Boolean GetIsMovable(Windows.UI.Xaml.DependencyObject target);
        static void SetIsMovable(Windows.UI.Xaml.DependencyObject target, Boolean value);
    }
}

// GameService.h
...
    static Windows::UI::Xaml::DependencyProperty IsMovableProperty() { return m_IsMovableProperty; }
    static bool GetIsMovable(Windows::UI::Xaml::DependencyObject const& target) { return winrt::unbox_value<bool>(target.GetValue(m_IsMovableProperty)); }
    static void SetIsMovable(Windows::UI::Xaml::DependencyObject const& target, bool value) { target.SetValue(m_IsMovableProperty, winrt::box_value(value)); }

private:
    static Windows::UI::Xaml::DependencyProperty m_IsMovableProperty;
...

// GameService.cpp
...
Windows::UI::Xaml::DependencyProperty GameService::m_IsMovableProperty =
    Windows::UI::Xaml::DependencyProperty::RegisterAttached(
        L"IsMovable",
        winrt::xaml_typename<bool>(),
        winrt::xaml_typename<UserAndCustomControls::GameService>(),
        Windows::UI::Xaml::PropertyMetadata{ winrt::box_value(false) }
);
...
// GameService.h
#pragma once

#include "pch.h"
//namespace WUX = Windows::UI::Xaml;

namespace UserAndCustomControls {
    public ref class GameService sealed : public WUX::DependencyObject {
    private:
        static WUX::DependencyProperty^ _IsMovableProperty;
    public:
        GameService::GameService();
        void GameService::RegisterDependencyProperties();
        static property WUX::DependencyProperty^ IsMovableProperty
        {
            WUX::DependencyProperty^ get() {
                return _IsMovableProperty;
            }
        };
        static bool GameService::GetIsMovable(WUX::UIElement^ element) {
            return (bool)element->GetValue(_IsMovableProperty);
        };
        static void GameService::SetIsMovable(WUX::UIElement^ element, bool value) {
            element->SetValue(_IsMovableProperty,value);
        }
    };
}

// GameService.cpp
#include "pch.h"
#include "GameService.h"

using namespace UserAndCustomControls;

using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Documents;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Media;

GameService::GameService() {};

GameService::RegisterDependencyProperties() {
    DependencyProperty^ GameService::_IsMovableProperty = DependencyProperty::RegisterAttached(
         "IsMovable", Platform::Boolean::typeid, GameService::typeid, ref new PropertyMetadata(false));
}

Définition de votre propriété jointe personnalisée à partir du balisage XAMLSetting your custom attached property from XAML markup

Notes

Si vous utilisez C++/WinRT, passez à la section suivante (définition de votre propriété jointe personnalisée de manière impérative avec c++/WinRT).If you're using C++/WinRT, then skip to the following section (Setting your custom attached property imperatively with C++/WinRT).

Après avoir défini votre propriété jointe et inclus ses membres de prise en charge dans le cadre d’un type personnalisé, vous devez rendre les définitions accessibles pour l’utilisation XAML.After you have defined your attached property and included its support members as part of a custom type, you must then make the definitions available for XAML usage. Pour cela, vous devez mapper un espace de noms XAML qui fera référence à l’espace de noms de code qui contient la classe pertinente.To do this, you must map a XAML namespace that will reference the code namespace that contains the relevant class. Dans les cas où vous avez défini la propriété jointe dans le cadre d’une bibliothèque, vous devez inclure cette dernière dans le package de l’application.In cases where you have defined the attached property as part of a library, you must include that library as part of the app package for the app.

Un mappage d’espace de noms XML pour XAML se place généralement dans l’élément racine d’une page XAML.An XML namespace mapping for XAML is typically placed in the root element of a XAML page. Par exemple, pour la classe nommée GameService dans l’espace de noms UserAndCustomControls qui contient les définitions des propriétés jointes indiquées dans les extraits de code précédents, le mappage peut ressembler à ce qui suit.For example, for the class named GameService in the namespace UserAndCustomControls that contains the attached property definitions shown in preceding snippets, the mapping might look like this.

<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:uc="using:UserAndCustomControls"
  ... >

À l’aide du mappage, vous pouvez définir votre propriété jointe GameService.IsMovable sur tout élément qui correspond à votre définition cible, y compris un type existant défini par le Windows Runtime.Using the mapping, you can set your GameService.IsMovable attached property on any element that matches your target definition, including an existing type that Windows Runtime defines.

<Image uc:GameService.IsMovable="True" .../>

Si vous définissez la propriété sur un élément qui se trouve également dans le même espace de noms XML mappé, vous devez quand même inclure le préfixe dans le nom de la propriété jointe,If you are setting the property on an element that is also within the same mapped XML namespace, you still must include the prefix on the attached property name. car le préfixe qualifie le type de propriétaire.This is because the prefix qualifies the owner type. On ne peut pas supposer que l’attribut de la propriété jointe se trouve dans le même espace de noms XML que l’élément où l’attribut est inclus, bien que, selon les règles XML normales, les attributs puissent hériter de l’espace de noms des éléments.The attached property's attribute cannot be assumed to be within the same XML namespace as the element where the attribute is included, even though, by normal XML rules, attributes can inherit namespace from elements. Par exemple, si vous définissez GameService.IsMovable sur un type personnalisé ImageWithLabelControl (définition non illustrée), et même si tous deux ont été définis dans le même espace de noms de code mappé au même préfixe, le XAML sera tout de même le suivant.For example, if you are setting GameService.IsMovable on a custom type of ImageWithLabelControl (definition not shown), and even if both were defined in the same code namespace mapped to same prefix, the XAML would still be this.

<uc:ImageWithLabelControl uc:GameService.IsMovable="True" .../>

Notes

Si vous écrivez une interface utilisateur XAML avec C++/CX, vous devez inclure l’en-tête pour le type personnalisé qui définit la propriété jointe, chaque fois qu’une page XAML utilise ce type.If you are writing a XAML UI with C++/CX, then you must include the header for the custom type that defines the attached property, any time that a XAML page uses that type. Chaque page XAML est associée à un en-tête code-behind (. Xaml. h).Each XAML page has an associated code-behind header (.xaml.h). C’est là que vous devez inclure (à l’aide de ** # include**) l’en-tête pour la définition du type de propriétaire de la propriété jointe.This is where you should include (using #include) the header for the definition of the attached property's owner type.

Définition de votre propriété jointe personnalisée de manière impérative avec C++/WinRTSetting your custom attached property imperatively with C++/WinRT

Si vous utilisez C++/WinRT, vous pouvez accéder à une propriété jointe personnalisée à partir du code impératif, mais pas à partir du balisage XAML.If you're using C++/WinRT, then you can access a custom attached property from imperative code, but not from XAML markup. Le code ci-dessous montre comment procéder.The code below shows how.

<Image x:Name="gameServiceImage"/>
// MainPage.h
...
#include "GameService.h"
...

// MainPage.cpp
...
MainPage::MainPage()
{
    InitializeComponent();

    GameService::SetIsMovable(gameServiceImage(), true);
}
...

Type de valeur d’une propriété jointe personnaliséeValue type of a custom attached property

Le type utilisé comme type de valeur d’une propriété jointe personnalisée affecte l’utilisation, la définition ou les deux à la fois.The type that is used as the value type of a custom attached property affects the usage, the definition, or both the usage and definition. Le type de valeur de la propriété jointe est déclaré à plusieurs endroits : dans les signatures des méthodes d’accesseur Get et Set, et également comme paramètre propertyType de l’appel RegisterAttached.The attached property's value type is declared in several places: in the signatures of both the Get and Set accessor methods, and also as the propertyType parameter of the RegisterAttached call.

Le type de valeur le plus courant pour les propriétés jointes (personnalisées ou autres) est une chaîne simple.The most common value type for attached properties (custom or otherwise) is a simple string. En effet, les propriétés jointes sont généralement destinées à des attributs XAML et l’utilisation d’une chaîne comme type de valeur garantit la légèreté des propriétés.This is because attached properties are generally intended for XAML attribute usage, and using a string as the value type keeps the properties lightweight. D’autres primitives qui offrent une méthode de conversion native en chaînes, telles qu’entier, double ou valeur d’énumération, sont également des types de valeurs courants pour les propriétés jointes.Other primitives that have native conversion to string methods, such as integer, double, or an enumeration value, are also common as value types for attached properties. Vous pouvez utiliser d’autres types de valeurs (qui ne prennent pas en charge la conversion de chaîne native) comme valeur de propriété jointe.You can use other value types—ones that don't support native string conversion—as the attached property value. Toutefois, cela implique de faire un choix en matière d’utilisation ou d’implémentation :However, this entails making a choice about either the usage or the implementation:

  • vous pouvez laisser la propriété jointe telle quelle, mais elle peut prendre en charge l’utilisation uniquement quand il s’agit d’un élément de propriété, et la valeur est déclarée en tant qu’élément objet.You can leave the attached property as it is, but the attached property can support usage only where the attached property is a property element, and the value is declared as an object element. Dans ce cas, le type de propriété doit prendre en charge l’utilisation de XAML en tant qu’élément objet.In this case, the property type does have to support XAML usage as an object element. Pour les références existantes au Windows Runtime, vérifiez la syntaxe XAML pour vous assurer que le type prend en charge l’utilisation des éléments objets XAML.For existing Windows Runtime reference classes, check the XAML syntax to make sure that the type supports XAML object element usage.
  • Vous pouvez laisser la propriété jointe telle quelle, mais utilisez-la uniquement dans le cadre d’un attribut par le biais d’une technique de référence XAML telle que Binding ou StaticResource qui peut être exprimée sous forme de chaîne.You can leave the attached property as it is, but use it only in an attribute usage through a XAML reference technique such as a Binding or StaticResource that can be expressed as a string.

En savoir plus sur l’exemple de Canvas.LeftMore about the Canvas.Left example

Dans les exemples précédents d’utilisation de propriétés jointes, nous avons montré différentes façons de définir la propriété Canvas. Left jointe.In earlier examples of attached property usages we showed different ways to set the Canvas.Left attached property. Mais qu’est-ce que cela change à la façon dont une classe Canvas interagit avec votre objet, et quand cela se produit-il ?But what does that change about how a Canvas interacts with your object, and when does that happen? Nous examinerons plus en détail cet exemple particulier, car si vous implémentez une propriété jointe, il est intéressant de voir ce qu’une classe propriétaire de propriété jointe classique a l’intention de faire d’autre avec les valeurs de sa propriété jointe si elle les trouve sur d’autres objets.We'll examine this particular example further, because if you implement an attached property, it's interesting to see what else a typical attached property owner class intends to do with its attached property values if it finds them on other objects.

La fonction principale d’un canevas est un conteneur de disposition à position absolue dans l’interface utilisateur.The main function of a Canvas is to be an absolute-positioned layout container in UI. Les enfants d’une classe Canvas sont stockés dans une propriété définie par une classe de base Children.The children of a Canvas are stored in a base-class defined property Children. De tous les panneaux, Canvas est le seul qui utilise le positionnement absolu.Of all the panels Canvas is the only one that uses absolute positioning. Il aurait encombré le modèle objet du type UIElement courant pour ajouter des propriétés qui ne présenteraient de l’intérêt que pour Canvas et les cas d’UIElement particuliers où ils sont des éléments enfants d’un UIElement.It would've bloated the object model of the common UIElement type to add properties that might only be of concern to Canvas and those particular UIElement cases where they are child elements of a UIElement. La définition des propriétés de contrôle de disposition d’une classe Canvas en tant que propriétés jointes utilisables par n’importe quelle classe UIElement maintient le modèle objet plus propre.Defining the layout control properties of a Canvas to be attached properties that any UIElement can use keeps the object model cleaner.

Pour être un volet pratique, Canvas a un comportement qui remplace les méthodes de mesure au niveau du Framework et de réorganisation .In order to be a practical panel, Canvas has behavior that overrides the framework-level Measure and Arrange methods. C’est en fait l’endroit où Canvas recherche les valeurs de propriétés jointes sur ses enfants.This is where Canvas actually checks for attached property values on its children. Une partie des deux modèles Measure et Arrange est une boucle qui effectue une itération sur n’importe quel contenu, et un panneau a la propriété Children qui rend explicite ce qui est supposé être considéré comme l’enfant d’un panneau.Part of both the Measure and Arrange patterns is a loop that iterates over any content, and a panel has the Children property that makes it explicit what's supposed to be considered the child of a panel. Ainsi, le comportement de la disposition de Canvas procède à une itération dans ces enfants, et effectue des appels des méthodes Canvas.GetLeft et Canvas.GetTop statiques sur chaque enfant pour voir si ces propriétés jointes contiennent une valeur autre que la valeur par défaut (la valeur par défaut est 0).So the Canvas layout behavior iterates through these children, and makes static Canvas.GetLeft and Canvas.GetTop calls on each child to see whether those attached properties contain a non-default value (default is 0). Ces valeurs sont alors utilisées pour positionner de façon absolue chaque enfant dans l’espace réservé à la disposition disponible dans l’objet Canvas en fonction des valeurs spécifiques fournies par chaque enfant, et validées à l’aide de la méthode Arrange.These values are then used to absolutely position each child in the Canvas available layout space according to the specific values provided by each child, and committed using Arrange.

Le code ressemble à ce pseudocode.The code looks something like this pseudocode.

protected override Size ArrangeOverride(Size finalSize)
{
    foreach (UIElement child in Children)
    {
        double x = (double) Canvas.GetLeft(child);
        double y = (double) Canvas.GetTop(child);
        child.Arrange(new Rect(new Point(x, y), child.DesiredSize));
    }
    return base.ArrangeOverride(finalSize); 
    // real Canvas has more sophisticated sizing
}

Notes

Pour plus d’informations sur le fonctionnement des panneaux, consultez vue d’ensemble des panneaux personnalisés XAML.For more info on how panels work, see XAML custom panels overview.