Megosztás:


Egyéni csatolt tulajdonságok

A csatolt tulajdonság egy XAML-fogalom. A csatolt tulajdonságok általában a függőségi tulajdonság speciális formájaként vannak definiálva. Ez a témakör azt ismerteti, hogyan implementálhat egy csatolt tulajdonságot függőségi tulajdonságként, és hogyan határozhatja meg azt a kiegészítő konvenciót, amely ahhoz szükséges, hogy a csatolt tulajdonság használható legyen az XAML-ben.

Előfeltételek

Feltételezzük, hogy a függőségi tulajdonságokat a meglévő függőségi tulajdonságok fogyasztójának szemszögéből ismeri, és elolvasta a Függőség tulajdonságainak áttekintését. A Csatolt tulajdonságok áttekintését is el kell olvasnia. A jelen témakör példáinak követéséhez ismernie kell az XAML-t is, és tudnia kell, hogyan írhat egy alapszintű Windows-futtatókörnyezeti alkalmazást C++, C# vagy Visual Basic használatával.

A csatolt tulajdonságok forgatókönyvei

Csatolt tulajdonságot akkor hozhat létre, ha oka van annak, hogy a tulajdonságbeállítási mechanizmus a definiáló osztálytól eltérő osztályok számára is elérhető legyen. Ennek leggyakoribb forgatókönyvei az elrendezés és a szolgáltatások támogatása. A meglévő elrendezéstulajdonságok közé tartoznak például a Canvas.ZIndex és a Canvas.Top. Elrendezési forgatókönyvekben az elrendezés-vezérlési elemek gyermekelemeiként létező elemek külön-külön kifejezhetik az elrendezési követelményeket a szülőelemeiknek, és mindegyik beállíthat egy tulajdonságértéket, amelyet a szülő csatolt tulajdonságként határoz meg. A Windows Runtime API szolgáltatástámogatási forgatókönyvére példa a ScrollViewer csatolt tulajdonságainak halmaza, például a ScrollViewer.IsZoomChainingEnabled.

Figyelmeztetés

A Windows Futtatókörnyezet XAML implementációjának meglévő korlátozása, hogy nem lehet animálni az egyéni csatolt tulajdonságot.

Egyéni csatolt tulajdonság regisztrálása

Ha a csatolt tulajdonságot szigorúan más típusokon való használatra definiálja, annak az osztálynak, amelyben a tulajdonság regisztrálva van, nem kell a DependencyObjectből származnia. Ha azonban a szokásos modellt követi, amelyben a csatolt tulajdonság egyben függőségi tulajdonság is, akkor rendelkeznie kell a célparaméterrel az accessorok használatához, hogy használhassa a háttértárolót.

Függőségi tulajdonságként definiálhatja a csatolt tulajdonságot egy nyilvánosstatikusírásvédettDependencyProperty típusú tulajdonság deklarálásával. Ezt a tulajdonságot a RegisterAttached metódus visszatérési értékével definiálhatja. A tulajdonságnévnek meg kell egyeznie a RegisterAttachednévparaméterként megadott csatolt tulajdonságnévvel, és hozzá kell adni a "Property" sztringet a végéhez. Ez a függőségi tulajdonságok azonosítóinak az általuk képviselt tulajdonságokhoz viszonyított elnevezésére szolgáló konvenció.

A fő terület, ahol egy egyéni csatolt tulajdonság definiálása eltér az egyéni függőségi tulajdonságtól, az a kiegészítők vagy burkolók definiálása. Az egyéni függőségi tulajdonságokban leírt burkolótechnika helyett statikus GetPropertyName és Set PropertyName metódusokat is meg kell adnia a csatolt tulajdonság tartozékaként. A tartozékokat többnyire az XAML-elemző használja, bár bármely más hívó is használhatja őket értékek beállítására nem XAML-forgatókönyvekben.

Fontos

Ha nem megfelelően definiálja a tartozékokat, az XAML-processzor nem tud hozzáférni a csatolt tulajdonsághoz, és aki megpróbálja használni, valószínűleg XAML-elemző hibát fog kapni. A tervezési és kódolási eszközök gyakran az "*Property" elnevezési konvenciókra támaszkodnak, amikor egy egyéni függőségi tulajdonságot találnak egy hivatkozott összeállításban.

Accessors

A GetPropertyName hozzáférő aláírásának ilyennek kell lennie.

public static valueTypeGetPropertyName(DependencyObject target)

A Microsoft Visual Basic esetében ez az.

Public Shared Function Get Tulajdonságnév(ByVal target As DependencyObject) As valueType)

A célobjektum lehet egy konkrétabb típusú a megvalósításban, de a DependencyObjectből kell származnia. A ValueType visszatérési értéke is lehet egy konkrétabb típus a megvalósításban. Az alapszintű objektumtípus elfogadható, de gyakran azt szeretné, hogy a csatolt tulajdonság megkövetelje a típusbiztonságot. A gépelés használata a getterben és a setter-aláírásokban ajánlott típusbiztonsági technika.

A SetPropertyName tartozék aláírásának ennek kell lennie.

public static void Set Tulajdonságnév(DependencyObject target ,valueType value)

A Visual Basic esetében ez az.

Public Shared Sub Set Tulajdonságnév(ByVal target As DependencyObject, ByVal value AsvalueType)

A célobjektum lehet egy konkrétabb típusú a megvalósításban, de a DependencyObjectből kell származnia. Az értékobjektum és a értéktípus az implementációban ennél konkrétabb típusok lehetnek. Ne feledje, hogy ennek a metódusnak az értéke az a bemenet, amelyet a XAML-processzor biztosít, amikor a jelölésben találkozik az Ön csatolt tulajdonságával. A használt típus típuskonvertálásának vagy meglévő korrektúrakiterjesztési támogatásának kell lennie, hogy a megfelelő típust attribútumértékből lehessen létrehozni (ami végső soron csak egy sztring). Az alapszintű objektumtípus elfogadható, de gyakran további típusbiztonságra van szüksége. Ehhez írja be a típusérvényesítést a hozzáférőkbe.

Megjegyzés:

Olyan csatolt tulajdonságot is megadhat, amelyben a kívánt használat a tulajdonságelem szintaxisán keresztül történik. Ebben az esetben nincs szükség típuskonvertálásra az értékekhez, de biztosítania kell, hogy a kívánt értékek XAML-ben is létrehozhatók legyenek. A VisualStateManager.VisualStateGroups egy olyan meglévő csatolt tulajdonság példája, amely csak a tulajdonságelemek használatát támogatja.

Kódrészlet

Ez a példa a függőségi tulajdonság regisztrációját (a RegisterAttached metódus használatával), valamint az egyéni csatolt tulajdonság beolvasását és beállítását mutatja be. A példában a csatolt tulajdonság neve .IsMovable Ezért a hozzáférőket el kell nevezni GetIsMovable és SetIsMovable. A csatolt tulajdonság tulajdonosa egy olyan szolgáltatásosztály, amelynek a neve GameService nem rendelkezik saját felhasználói felülettel; célja csak a csatolt tulajdonságszolgáltatások biztosítása a GameService.IsMovable csatolt tulajdonság használatakor.

A csatolt tulajdonság definiálása a C++/CX-ben egy kicsit összetettebb. El kell döntenie, hogyan kell a fejléc és a kódfájl közötti tényezőt figyelembevenni. Emellett az azonosítót csak egyéni függőségi tulajdonságokban tárgyalt okok miatt egy get hozzáférővel rendelkező tulajdonságként kell elérhetővé tenni. A C++/CX-ben explicit módon kell definiálnia ezt a tulajdonságmező-kapcsolatot ahelyett, hogy egyszerű tulajdonságok NET readonly kulcsszó használatára és implicit háttérrendszerre támaszkodna. A csatolt tulajdonság regisztrációját is végre kell hajtania egy segédfüggvényen belül, amely csak egyszer fut, amikor az alkalmazás először elindul, de a csatolt tulajdonságot igénylő XAML-lapok betöltése előtt. A függőségi vagy kapcsolt tulajdonságok tulajdonságregisztrációs segédfüggvényeinek meghívására általában az app.xaml fájl kódjában található App / osztályának konstruktorában kerül sor.

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));
}

Egyéni csatolt tulajdonság beállítása XAML jelölésből

Miután definiálta a csatolt tulajdonságot, és egy egyéni típus részeként belefoglalta annak támogatási tagjait, elérhetővé kell tennie a definíciókat az XAML-használathoz. Ehhez le kell képeznie egy XAML-névteret, amely a megfelelő osztályt tartalmazó kódnévtérre hivatkozik. Azokban az esetekben, amikor a csatolt tulajdonságot egy könyvtár részeként definiálta, a könyvtárat az alkalmazáscsomag részeként kell tartalmaznia.

Az XAML-hez tartozó XML-névtérleképezés általában egy XAML-lap gyökérelemébe kerül. Például a névtérben GameService elnevezett UserAndCustomControls osztály esetében, amely az előző kódrészletekben látható csatolt tulajdonságdefiníciókat tartalmazza, a leképezés így nézhet ki.

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

A leképezés használatával a csatolt tulajdonságot GameService.IsMovable bármely olyan elemre beállíthatja, amely megfelel a céldefiníciónak, beleértve a Windows Runtime által definiált meglévő típust is.

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

Ha a tulajdonságot egy olyan elemre állítja be, amely szintén ugyanabban a megfeleltetett XML-névtérben található, akkor is tartalmaznia kell az előtagot a csatolt tulajdonságnéven. Ennek az az oka, hogy az előtag megfelel a tulajdonos típusának. A csatolt tulajdonság attribútuma nem feltételezhető, hogy ugyanabban az XML-névtérben van, mint az az elem, amelyben az attribútum szerepel, annak ellenére, hogy a normál XML-szabályok szerint az attribútumok örökölhetik a névteret az elemektől. Ha például egyéni típust állít be GameService.IsMovable-ra ImageWithLabelControl-ben (a definíció nem jelenik meg), és még akkor is, ha mindkettő ugyanabban a kódnévtérben van meghatározva, amely ugyanahhoz az előtaghoz van rendelve, az XAML struktúrája továbbra is ez lesz.

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

Megjegyzés:

Ha XAML felhasználói felületet ír C++/CX használatával, akkor a csatolt tulajdonságot meghatározó egyéni típus fejlécét minden alkalommal tartalmaznia kell, amikor egy XAML-lap ezt a típust használja. Minden XAML-oldalhoz tartozik egy kód mögötti fejléc (.xaml.h). Itt kell a csatolt tulajdonság tulajdonostípusának definíciójának fejlécét ( #include használatával) tartalmaznia.

Az egyéni csatolt tulajdonság kényszerítő beállítása

Az imperatív kódból is hozzáférhet egy egyéni csatolt tulajdonsághoz. Az alábbi kód bemutatja, hogyan.

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

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

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

Egyéni csatolt tulajdonság értéktípusa

Az egyéni csatolt tulajdonság értéktípusaként használt típus befolyásolja a használatot, a definíciót vagy a használatot és a definíciót is. A csatolt tulajdonság értéktípusa több helyen deklarálva van: a Get és a Set kiegészítő metódus aláírásaiban, valamint a RegisterAttached hívás propertyType paramétereként is.

A csatolt tulajdonságok (egyéni vagy egyéb) leggyakoribb értéktípusa egy egyszerű sztring. Ennek az az oka, hogy a csatolt tulajdonságok általában az XAML-attribútumok használatára szolgálnak, és az értéktípusként használt karakterláncok könnyűvé teszik a tulajdonságokat. Más, sztringmetódusokra natívan konvertált primitívek, például egész szám, dupla vagy enumerálási érték is gyakoriak a csatolt tulajdonságok értéktípusaként. A csatolt tulajdonságértékként más értéktípusokat is használhat – azokat, amelyek nem támogatják a natív sztringek konvertálását. Ez azonban azt jelenti, hogy választhat a használatról vagy a megvalósításról:

  • A csatolt tulajdonságot elhagyhatja, de a csatolt tulajdonság csak akkor támogatja a használatot, ha a csatolt tulajdonság tulajdonságelem, és az érték objektumelemként van deklarálva. Ebben az esetben a tulajdonságtípusnak támogatnia kell az XAML használatát objektumelemként. Meglévő Windows-futtatókörnyezeti referenciaosztályok esetén ellenőrizze az XAML szintaxist, hogy a típus támogatja-e az XAML objektumelemek használatát.
  • A csatolt tulajdonságot változatlanul hagyhatja, de csak attribútumhasználatban használhatja egy XAML referenciatechnikával, például kötéssel vagy StaticResource-nal , amely sztringként fejezhető ki.

További információ a Canvas.Left-példáról

A csatolt tulajdonsághasználatok korábbi példáiban különböző módokon állítottuk be a Canvas.Left csatolt tulajdonságot. De miben változik ez abban, hogy a vászon hogyan kommunikál az objektummal, és mikor történik ez? Ezt a konkrét példát részletesebben is megvizsgáljuk, mert ha egy csatolt tulajdonságot implementál, érdekes látni, hogy egy tipikus csatolt tulajdonságtulajdonosi osztály mit kíván még tenni a csatolt tulajdonságértékeivel, ha más objektumokon találja őket.

A vászon fő funkciója az, hogy abszolút elhelyezésű elrendezéstároló legyen a felhasználói felületen. A vászon gyermekeit egy alaposztályban definiált Gyermek tulajdonság tárolja. Az összes panel közül a Vászon az egyetlen, amely abszolút pozicionálást használ. Az általános UIElement-típus objektummodelljét elárasztotta volna, ha olyan tulajdonságokat adnánk hozzá, amelyek csak a Canvas-hoz és azokhoz a konkrét UIElement esetekhez kapcsolódnak, amikor ezek egy UIElement gyermekelemei. A Canvas elrendezésvezérlő tulajdonságainak meghatározása csatolt tulajdonságokként, amelyeket bármely UIElement használhat, tisztábban tartja az objektummodellt.

Gyakorlati panelként a Canvas olyan viselkedéssel rendelkezik, amely felülbírálja a keretrendszerszintű mérték - és rendezési módszereket. Itt ellenőrzi a Canvas a gyermekekhez csatolt tulajdonságértékeket. Mind a Mérték , mind az Elrendezés minták része egy hurok, amely minden tartalom felett iterál, és a panelen a Children tulajdonság látható, amely explicitvé teszi, hogy mit kellene egy panel gyermekének tekinteni. A Vászon elrendezés viselkedése tehát végigfut ezeken a gyermekeken, és statikus Canvas.GetLeft és Canvas.GetTop hívásokat indít minden gyermeken, hogy lássa, a csatolt tulajdonságok tartalmaznak-e nem alapértelmezett értéket (alapértelmezés szerint 0). Ezeket az értékeket ezután a rendszer a gyermek által megadott értékeknek megfelelően a vászon rendelkezésre álló elrendezési területén lévő összes gyermek abszolút elhelyezésére használja, és az Elrendezés funkcióval véglegesít.

A kód ehhez a pszeudokódhoz hasonló.

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
}

Megjegyzés:

A panelek működéséről további információt az XAML egyéni panelek áttekintésében talál.