Aracılığıyla paylaş


Özel ekli özellikler

Ekli özellik bir XAML kavramıdır. Ekli özellikler genellikle bağımlılık özelliğinin özelleştirilmiş bir biçimi olarak tanımlanır. Bu konu başlığı altında, ekli bir özelliğin bağımlılık özelliği olarak nasıl uygulanacağı ve ekli özelliğinizin XAML'de kullanılabilir olması için gereken erişimci kuralının nasıl tanımlanacağı açıklanmaktadır.

Önkoşullar

Bağımlılık özelliklerini mevcut bağımlılık özelliklerinin tüketicisi açısından anladığınız ve Bağımlılık özelliklerine genel bakışını okuduğunuz varsayılır. Ekli özelliklere genel bakış da okumanız gerekir. Bu konudaki örnekleri izlemek için XAML'yi de anlamanız ve C++, C# veya Visual Basic kullanarak temel bir Windows Çalışma Zamanı uygulaması yazmayı bilmeniz gerekir.

Ekli özellikler için senaryolar

Tanımlama sınıfı dışındaki sınıflar için özellik ayarı mekanizmasının kullanılabilir olmasının bir nedeni olduğunda ekli bir özellik oluşturabilirsiniz. Bunun için en yaygın senaryolar düzen ve hizmet desteğidir. Varolan düzen özelliklerine örnek olarak Canvas.ZIndex ve Canvas.Top verilebilir. Düzen senaryosunda, düzen denetimi öğelerine alt öğe olarak var olan öğeler, düzen gereksinimlerini üst öğelerine tek tek ifade edebilir ve her biri üst öğe tarafından ekli özellik olarak tanımlanan bir özellik değeri ayarlar. Windows Çalışma Zamanı API'sindeki hizmet destek senaryosuna bir örnek, ScrollViewer gibi ekli özelliklerin kümesi olan ScrollViewer.IsZoomChainingEnabled olabilir.

Uyarı

Windows Çalışma Zamanı XAML uygulamasının mevcut sınırlamalarından biri, özel ekli özelliğinize animasyon ekleyememenizdir.

Özel bir ekli özelliği kaydetme

Ekli özelliği diğer türlerde kullanmak üzere kesin olarak tanımlıyorsanız, özelliğin kaydedildiği sınıfın DependencyObject'ten türetmesi gerekmez. Ancak, ekli özelliğinizin de bağımlılık özelliği olması için tipik bir modeli izlerseniz, donatılar için hedef parametrenin DependencyObject kullanması gerekir, böylece yedekleme özellik deponuzu kullanabilirsiniz.

Ekli özelliğinizi bir bağımlılık özelliği olarak tanımlamak için DependencyProperty türünde genelstatiksalt okunur bir özellik bildirin. RegisterAttached yönteminin dönüş değerini kullanarak bu özelliği tanımlarsınız. Özellik adı, RegisterAttached parametresi olarak belirttiğiniz ekli özellik adıyla eşleşmeli ve sonuna "Property" dizesi eklenmelidir. Bu, bağımlılık özelliklerinin tanımlayıcılarını temsil ettikleri özelliklerle ilgili olarak adlandırmaya yönelik yerleşik kuraldır.

Özel ekli özellik tanımlamanın özel bağımlılık özelliğinden farklı olduğu ana alan, erişimcileri veya sarmalayıcıları tanımlama şeklinizdedir. Özel bağımlılık özelliklerinde açıklanan sarmalayıcı tekniğini kullanmak yerine, statik GetPropertyName ve SetPropertyName yöntemlerini ekli özellik için erişimci olarak da sağlamanız gerekir. Erişimciler çoğunlukla XAML ayrıştırıcısı tarafından kullanılır, ancak diğer arayanlar bunları XAML dışı senaryolarda değer ayarlamak için de kullanabilir.

Önemli

Erişimcileri doğru tanımlamazsanız, XAML işlemcisi ekli özelliğinize erişemez ve bunu kullanmaya çalışan herkes büyük olasılıkla bir XAML ayrıştırıcı hatası alır. Ayrıca, tasarım ve kodlama araçları genellikle başvuruda bulunılan bir derlemede özel bağımlılık özelliğiyle karşılaştıklarında tanımlayıcıları adlandırmak için "*Property" kurallarını kullanır.

Accessors

GetPropertyName erişimcisinin imzası şu olmalıdır.

public static değerTipiAlÖzellikAdı(DependencyObject target)

Microsoft Visual Basic için bu özelliktir.

Public Shared Function Get PropertyName(ByVal target As DependencyObject) As valueType)

Hedef nesne, uygulamanızda daha belirli bir türde olabilir, ancak DependencyObject'ten türetilmesi gerekir. ValueType dönüş değeri, uygulamanızda daha belirli bir türde de olabilir. Temel Nesne türü kabul edilebilir, ancak genellikle ekli özelliğinizin tür güvenliğini zorunlu kılmasını istersiniz. Alıcı ve ayarlayıcı imzalarında tip belirtmenin kullanılması, önerilen bir tip güvenliği tekniğidir.

Set PropertyNameerişimcisinin imzası şu olmalıdır.

public static void Set PropertyName(DependencyObject target ,valueType value)

Visual Basic için bu durumdur.

Public Shared Sub Set PropertyName(ByVal target As DependencyObject, ByVal value AsvalueType)

Hedef nesne, uygulamanızda daha belirli bir türde olabilir, ancak DependencyObject'ten türetilmesi gerekir. value nesnesi ve valueType, uygulamanızda daha belirli bir türde olabilir. Bu yöntemin değerinin, işaretlemede ekli özelliğinizle karşılaştığında XAML işlemcisinden gelen giriş olduğunu unutmayın. Uygun türün bir öznitelik değerinden (sonuçta yalnızca bir dize) oluşturulabilmesi için, kullandığınız tür için tür dönüştürme veya mevcut işaretleme uzantısı desteği olmalıdır. Temel Nesne türü kabul edilebilir, ancak genellikle daha fazla tür güvenliği istersiniz. Bunu gerçekleştirmek için erişim işlevlerine tür zorlaması koyun.

Uyarı

Ayrıca, hedeflenen kullanımın özellik öğesi söz dizimi aracılığıyla olduğu ekli bir özellik tanımlamak da mümkündür. Bu durumda, değerler için tür dönüştürmesine ihtiyacınız yoktur, ancak amaçladığınız değerlerin XAML'de oluşturulabileceğinden emin olmanız gerekir. VisualStateManager.VisualStateGroups , yalnızca özellik öğesi kullanımını destekleyen mevcut bir ekli özelliğe örnektir.

Kod örneği

Bu örnek, özel bir ekli özellik için bağımlılık özelliği kaydını ( RegisterAttached yöntemini kullanarak) ve Get ve Set erişimcilerini gösterir. Örnekte, ekli özellik adı şeklindedir IsMovable. Bu nedenle, erişimciler GetIsMovable ve SetIsMovable olarak adlandırılmalıdır. Ekli özelliğin sahibi, kendi kullanıcı arabirimi olmayan adlı GameService bir hizmet sınıfıdır; amacı yalnızca GameService.IsMovable ekli özelliği kullanıldığında ekli özellik hizmetlerini sağlamaktır.

C++/CX'te ekli özelliği tanımlamak biraz daha karmaşıktır. Üst bilgi dosyası ve kod dosyası arasındaki görev dağılımına nasıl karar vereceğinizi belirlemeniz gerekir. Ayrıca, Özel bağımlılık özellikleri bölümünde açıklanan nedenlerle tanımlayıcıyı yalnızca get erişimcisine sahip bir özellik olarak kullanıma sunmanız gerekir. C++/CX'te, .NET'te basit özellikler için kullanılan salt okunur anahtar sözcüğüne ve bunların örtük desteklenmesine güvenmek yerine, bu özellik-alan ilişkisini açıkça tanımlamanız gerekir. Ekli özelliğin kaydını, uygulama ilk kez başlatıldığında ancak ekli özelliğe ihtiyaç duyan XAML sayfaları yüklenmeden önce yalnızca bir kez çalıştırılan bir yardımcı işlevin içinde gerçekleştirmeniz gerekir. Tüm bağımlı veya ekli özellikler için özellik kayıt yardımcı fonksiyonlarınızı çağırmanız için tipik yer, app.xaml dosyanızın kodundaki Uygulama / Uygulaması oluşturucusunun içindedir.

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

XAML işaretlemesinden özel ekli özelliğinizi ayarlama

Ekli özelliğinizi tanımladıktan ve destek üyelerini özel bir türün parçası olarak ekledikten sonra tanımları XAML kullanımı için kullanılabilir hale getirmeniz gerekir. Bunu yapmak için, ilgili sınıfı içeren kod ad alanına başvuracak bir XAML ad alanını eşlemeniz gerekir. Ekli özelliği bir kitaplığın parçası olarak tanımladığınız durumlarda, bu kitaplığı uygulamanın uygulama paketinin bir parçası olarak eklemeniz gerekir.

XAML için XML ad alanı eşlemesi genellikle bir XAML sayfasının kök öğesine yerleştirilir. Örneğin, önceki kod parçacıklarında gösterilen ekli özellik tanımlarını içeren ad alanında GameService adlı UserAndCustomControls sınıf için eşleme şöyle görünebilir.

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

Eşlemeyi kullanarak, ekli özelliğinizi GameService.IsMovable, hedef tanımınızla eşleşen herhangi bir öğeye, Windows Çalışma Zamanı'nın tanımladığı mevcut bir tür de dahil olmak üzere, ayarlayabilirsiniz.

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

Aynı eşlenen XML ad alanı içinde bulunan bir öğede özelliğini ayarlıyorsanız, ekli özellik adına yine de ön ekini eklemeniz gerekir. Bunun nedeni, ön ekin sahip türünü nitelediğindendir. Ekli özelliğin özniteliğinin, özniteliğin dahil edildiği öğeyle aynı XML ad alanı içinde olduğu varsayılamaz, ancak normal XML kuralları tarafından öznitelikler öğelerden ad alanını devralabilir. Örneğin, ImageWithLabelControl üzerinde bir özel türü ayarlıyorsanız (tanım gösterilmiyor), ve her ikisi de aynı önekle eşlenmiş aynı kod ad alanında tanımlanmışsa bile, XAML yine de böyle olacaktır.

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

Uyarı

C++/CX ile bir XAML kullanıcı arabirimi yazıyorsanız, XAML sayfasının bu türü kullandığı her zaman ekli özelliği tanımlayan özel türün üst bilgisini eklemeniz gerekir. Her XAML sayfasının ilişkili kod arkası başlık dosyası (.xaml.h) vardır. Burası, eklenmiş özelliğin sahip türünün tanımına yönelik üst bilgiyi #include kullanarak eklemeniz gereken yerdir.

Özel ekli özelliğinizi zorunlu olarak ayarlama

Ayrıca kesinlik temelli koddan özel bir ekli özelliğe de erişebilirsiniz. Aşağıdaki kod nasıl yapılacağını gösterir.

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

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

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

Özel bir ekli özelliğin değer türü

Özel bir ekli özelliğin değer türü olarak kullanılan tür, kullanımını, tanımını veya her ikisini birden etkiler. Ekli özelliğin değer türü birkaç yerde bildirilir: Get ve Set erişimci yöntemlerinin imzalarında hem de RegisterAttached çağrısının propertyType parametresi olarak.

Ekli özellikler (özel veya başka bir şekilde) için en yaygın değer türü basit bir dizedir. Bunun nedeni, ekli özelliklerin genel olarak XAML öznitelik kullanımına yönelik olması ve değer türü olarak bir dize kullanılması özellikleri basit tutar. Tamsayı, çift veya numaralandırma değeri gibi dize yöntemlerine yerel dönüştürmesi olan diğer temel öğeler, ekli özellikler için değer türleri olarak da yaygındır. Ekli özellik değeri olarak diğer değer türlerini (yerel dize dönüştürmeyi desteklemeyenler) kullanabilirsiniz. Ancak bu, kullanım veya uygulama hakkında bir seçim yapmayı gerektirir:

  • Ekli özelliği olduğu gibi bırakabilirsiniz, ancak ekli özellik yalnızca ekli özelliğin bir özellik öğesi olduğu ve değerin nesne öğesi olarak bildirildiği kullanımı destekleyebilir. Bu durumda, özellik türünün nesne öğesi olarak XAML kullanımını desteklemesi gerekir. Mevcut Windows Çalışma Zamanı başvuru sınıfları için, türün XAML nesne öğesi kullanımını desteklediğinden emin olmak için XAML söz dizimini denetleyin.
  • Ekli özelliği olduğu gibi bırakabilirsiniz, ancak bunu yalnızca dize olarak ifade edilebilen Binding veya StaticResource gibi bir XAML başvuru tekniği aracılığıyla öznitelik kullanımında kullanabilirsiniz.

Canvas.Left örneği hakkında daha fazla bilgi

Ekli özellik kullanımlarının önceki örneklerinde Canvas.Left ekli özelliğini ayarlamanın farklı yollarını göstermiştik. Peki bu, Canvas'ın nesnenizle nasıl etkileşime geçtiğini ve bunun ne zaman gerçekleştiğini konusunda neleri değiştirir? Bu özel örneği daha ayrıntılı inceleyeceğiz, çünkü ekli bir özellik uygularsanız, tipik bir ekli özellik sahip sınıfının ekli özellik değerlerini diğer nesnelerde bulması durumunda başka ne yapmak istediğini görmek ilginçtir.

Tuvalin ana işlevi, kullanıcı arabiriminde mutlak konumlandırılmış bir düzen kapsayıcısı olmaktır. Canvas alt öğeleri, temel sınıf tarafından tanımlanan Children özelliğinde depolanır. Tüm paneller arasında Tuval , mutlak konumlandırma kullanan tek paneldir. Ortak UIElement türünün nesne modelini şişirerek yalnızca Canvas'a ve uiElement'in alt öğeleri oldukları belirli UIElement durumlarına ilgi gösterebilecek özellikler ekleyebilirdi. Bir Tuvalin düzen denetimi özelliklerini herhangi bir UIElement için kullanılabilir ekli özellikler olarak tanımlamak, nesne modelini daha temiz tutar.

Tuval, pratik bir panel olmak için çerçeve düzeyinde Ölçü ve Düzenleme yöntemlerini geçersiz kılan davranışlara sahiptir. Burası Canvas'ın alt öğelerinde ekli özellik değerlerini kontrol ettiği alandır. Hem Ölçü hem de Yerleştirme desenlerinin bir parçası, herhangi bir içeriği yineleyen bir döngüdür ve bir panelde, panelin alt öğesi olarak kabul edilenleri açıkça belirten Children özelliği bulunur. Dolayısıyla Tuval düzeni davranışı bu alt öğeler arasında yinelenir ve eklenen özelliklerin varsayılan olmayan bir değer içerip içermediğini görmek için her alt öğede statik Canvas.GetLeft ve Canvas.GetTop çağrıları yapar (varsayılan değer 0'dır). Bu değerler, her alt öğe tarafından sağlanan belirli değerlere göre, Canvas'ın kullanılabilir düzen alanındaki her alt öğeyi kesin bir şekilde konumlandırmak için kullanılır ve Yerleştir ile uygulanır.

Kod, bu sahte koda benzer.

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
}

Uyarı

Panellerin nasıl çalıştığı hakkında daha fazla bilgi için bkz. XAML özel panellerine genel bakış.