Denetim yazmaya genel bakış

Windows Presentation Foundation (WPF) denetim modelinin genişletilebilirliği, yeni denetim oluşturma gereksinimini büyük ölçüde azaltır. Ancak bazı durumlarda özel bir denetim oluşturmanız gerekebilir. Bu konu başlığında, Özel denetim oluşturma gereksiniminizi en aza indiren özellikler ve Windows Presentation Foundation'da (WPF) farklı denetim yazma modelleri açıklanmaktadır. Bu konu başlığında yeni bir denetimin nasıl oluşturulacağı da gösterilmektedir.

Yeni Denetim Yazmanın Alternatifleri

Geçmişte, mevcut bir denetimden özelleştirilmiş bir deneyim elde etmek istiyorsanız, denetimin arka plan rengi, kenarlık genişliği ve yazı tipi boyutu gibi standart özelliklerini değiştirmekle sınırlıydınız. Denetimin görünümünü veya davranışını bu önceden tanımlanmış parametrelerin ötesine genişletmek istiyorsanız, genellikle mevcut bir denetimden devralarak ve denetimin çizilmesinden sorumlu yöntemi geçersiz kılarak yeni bir denetim oluşturmanız gerekir. Bu hala bir seçenek olsa da WPF, zengin con çadır modu l, stiller, şablonlar ve tetikleyicilerini kullanarak mevcut denetimleri özelleştirmenizi sağlar. Aşağıdaki listede, bu özelliklerin yeni bir denetim oluşturmak zorunda kalmadan özel ve tutarlı deneyimler oluşturmak için nasıl kullanılabileceğini gösteren örnekler verilmiştir.

  • Zengin İçerik. Standart WPF denetimlerinin çoğu zengin içeriği destekler. Örneğin, öğesinin Button içerik özelliği türündedir Object, bu nedenle teorik olarak herhangi bir Buttonşey üzerinde görüntülenebilir. Bir düğmenin görüntü ve metin görüntülemesini sağlamak için, öğesine bir resim ve bir TextBlockStackPanel ekleyebilir ve öğesini özelliğine Content atayabilirsinizStackPanel. Denetimler WPF görsel öğelerini ve rastgele verileri görüntüleyebildiğinden, karmaşık bir görselleştirmeyi desteklemek için yeni bir denetim oluşturmanız veya mevcut bir denetimi değiştirmeniz daha az gerekir. için con çadır modu l ve WPF'deki diğer con çadır modu ls hakkında daha fazla bilgi için Button bkz. WPF İçerik Modeli.

  • Stiller. A Style , bir denetimin özelliklerini temsil eden bir değer koleksiyonudur. Stilleri kullanarak, yeni bir denetim yazmadan istenen denetim görünümünün ve davranışının yeniden kullanılabilir bir gösterimini oluşturabilirsiniz. Örneğin, tüm denetimlerinizin TextBlock yazı tipi boyutu 14 olan kırmızı, Arial yazı tipi olmasını istediğinizi varsayalım. Kaynak olarak bir stil oluşturabilir ve uygun özellikleri buna göre ayarlayabilirsiniz. Ardından uygulamanıza eklediğiniz her TextBlock şey aynı görünüme sahip olur.

  • Veri Şablonları. A DataTemplate , bir denetimde verilerin nasıl görüntüleneceğini özelleştirmenizi sağlar. Örneğin, içinde DataTemplate verilerin nasıl görüntüleneceğini ListBoxbelirtmek için bir kullanılabilir. Bunun bir örneği için bkz . Veri Şablon oluşturmaya genel bakış. Verilerin görünümünü özelleştirmeye ek olarak, DataTemplate kullanıcı arabirimi öğelerini de içerebilir ve bu da size özel URI'lerde çok fazla esneklik sağlar. Örneğin, kullanarak DataTemplateher öğenin bir ComboBox onay kutusu içerdiği bir oluşturabilirsiniz.

  • Denetim Şablonları. WPF'deki birçok denetim, denetimin yapısını ve görünümünü tanımlamak için bir kullanır ControlTemplate ve bu da denetimin görünümünü denetimin işlevselliğinden ayırır. Bir denetimin görünümünü, öğesini yeniden tanımlayarak ControlTemplateönemli ölçüde değiştirebilirsiniz. Örneğin, stoplight gibi görünen bir denetim istediğinizi varsayalım. Bu denetimin basit bir kullanıcı arabirimi ve işlevselliği vardır. Denetim üç dairedir ve bunlardan yalnızca biri aynı anda aydınlatılabilir. Bir yansımadan sonra, bir RadioButton tek seferde yalnızca bir tanesinin seçilmesinin işlevselliğini sunduğunu, ancak varsayılan görünümünün RadioButton bir stoplight üzerindeki ışıklara benzediğini fark edebilirsiniz. RadioButton görünümü tanımlamak için bir denetim şablonu kullandığından, öğesini denetimin gereksinimlerine uyacak şekilde yeniden tanımlamak ControlTemplate ve trafik işığınızı yapmak için radyo düğmelerini kullanmak kolaydır.

    Dekont

    bir kullanabilirDataTemplateDataTemplate, ancak RadioButton bu örnekte yeterli değildir. , DataTemplate bir denetimin içeriğinin görünümünü tanımlar. durumunda RadioButtoniçerik, dairenin sağında görünen ve öğesinin seçili olup olmadığını RadioButton gösteren içeriktir. Trafik işığı örneğinde, radyo düğmesinin yalnızca "ışık açabilen" bir daire olması gerekir. Stoplight için görünüm gereksinimi varsayılan görünümünden RadioButtonçok farklı olduğundan, öğesini yeniden tanımlamak ControlTemplategerekir. Genel olarak bir DataTemplate denetimin içeriğini (veya verilerini) tanımlamak için kullanılır ve ControlTemplate denetimin nasıl yapılandırıldığını tanımlamak için kullanılır.

  • Tetikleyiciler. , Trigger yeni bir denetim oluşturmadan denetimin görünümünü ve davranışını dinamik olarak değiştirmenize olanak tanır. Örneğin, uygulamanızda birden çok ListBox denetim olduğunu ve her ListBox bir öğe seçildiğinde kalın ve kırmızı olmasını istediğinizi varsayalım. İlk içgüdünüz öğesinden ListBox devralan bir sınıf oluşturmak ve seçili öğenin görünümünü değiştirmek için yöntemini geçersiz kılmak OnSelectionChanged olabilir, ancak daha iyi bir yaklaşım, seçilen öğenin görünümünü değiştiren bir ListBoxItem stile tetikleyici eklemektir. Tetikleyici, özellik değerlerini değiştirmenize veya bir özelliğin değerine göre eylemler gerçekleştirmenize olanak tanır. , EventTrigger bir olay gerçekleştiğinde eylem gerçekleştirmenizi sağlar.

Stiller, şablonlar ve tetikleyiciler hakkında daha fazla bilgi için bkz . Stil Oluşturma ve Şablon Oluşturma.

Genel olarak, denetiminiz mevcut bir denetimin işlevselliğini yansıtıyorsa ancak denetimin farklı görünmesini istiyorsanız, önce mevcut denetimin görünümünü değiştirmek için bu bölümde açıklanan yöntemlerden herhangi birini kullanıp kullanamayacağınızı göz önünde bulundurmalısınız.

Denetim Yazma Modelleri

Zengin con çadır modu l, stiller, şablonlar ve tetikleyiciler, yeni denetim oluşturma gereksinimini en aza indirir. Ancak, yeni bir denetim oluşturmanız gerekiyorsa, WPF'de farklı denetim yazma modellerini anlamak önemlidir. WPF, denetim oluşturmak için her biri farklı bir özellik kümesi ve esneklik düzeyi sağlayan üç genel model sağlar. Üç model için temel sınıflar , Controlve FrameworkElementşeklindedirUserControl.

UserControl'den türetme

WPF'de denetim oluşturmanın en basit yolu, 'den UserControltüretmektir. öğesinden UserControldevralan bir denetim oluşturduğunuzda, var olan bileşenleri UserControlöğesine eklersiniz, bileşenleri adlandırır ve XAML'deki olay işleyicilerine başvurursunuz. Ardından adlandırılmış öğelere başvurabilir ve kodda olay işleyicilerini tanımlayabilirsiniz. Bu geliştirme modeli WPF'de uygulama geliştirme için kullanılan modele çok benzer.

Doğru şekilde derlenirse, UserControl zengin içerik, stil ve tetikleyicilerin avantajlarından yararlanabilir. Ancak, denetiminiz öğesinden UserControldevralıyorsa, denetiminizi kullanan kişiler görünümünü özelleştirmek için veya DataTemplateControlTemplate kullanamaz. Şablonları destekleyen özel bir denetim oluşturmak için sınıfından Control veya türetilmiş sınıflarından birinden (dışında UserControl) türetilmesi gerekir.

UserControl'den Türetmenin Avantajları

Aşağıdakilerin tümü geçerliyse şu kaynaktan UserControl türetebilirsiniz:

  • Denetiminizi, bir uygulamayı nasıl derlediğinize benzer şekilde oluşturmak istiyorsunuz.

  • Denetiminiz yalnızca mevcut bileşenlerden oluşur.

  • Karmaşık özelleştirmeyi desteklemeniz gerekmez.

Denetimden Türetme

sınıfından Control türetme, mevcut WPF denetimlerinin çoğu tarafından kullanılan modeldir. sınıfından Control devralan bir denetim oluşturduğunuzda, şablon kullanarak görünümünü tanımlarsınız. Bunu yaptığınızda, işlem mantığını görsel gösterimden ayırırsınız. Ayrıca, olaylar yerine komutları ve bağlamaları kullanarak ve mümkün olduğunda içindeki öğelere başvurmaktan kaçınarak kullanıcı arabiriminin ve mantığın ControlTemplate ayrıştırılmasını sağlayabilirsiniz. Denetiminizin kullanıcı arabirimi ve mantığı düzgün şekilde ayrılmışsa, denetiminizin kullanıcısı görünümünü özelleştirmek için denetimin ControlTemplate kullanıcılarını yeniden tanımlayabilir. Özel Control bir derleme, oluşturmak kadar UserControlbasit olmasa da, en fazla esnekliği sağlayan bir özel Control özelliktir.

Denetimden Türetmenin Avantajları

Aşağıdakilerden biri geçerliyse sınıfını UserControl kullanmak yerine öğesinden Control türetebilirsiniz:

  • Denetiminizin görünümünün aracılığıyla ControlTemplateözelleştirilebilir olmasını istiyorsunuz.

  • Denetiminizin farklı temaları desteklemesini istiyorsunuz.

FrameworkElement'ten Türetme

Mevcut öğeleri oluşturmaktan UserControl türetilen veya Control bu öğelere dayanan denetimler. Birçok senaryoda, bu kabul edilebilir bir çözümdür çünkü öğesinden FrameworkElement devralan tüm nesneler içinde ControlTemplateolabilir. Ancak, bir denetimin görünümünün basit öğe bileşiminin işlevselliğinden daha fazlasını gerektirdiği zamanlar vardır. Bu senaryolar için bir bileşeni FrameworkElement temel alan doğru seçimdir.

Tabanlı bileşenler oluşturmak FrameworkElementiçin iki standart yöntem vardır: doğrudan işleme ve özel öğe oluşturma. Doğrudan işleme, yöntemini FrameworkElement geçersiz kılmayı OnRender ve bileşen görsellerini açıkça tanımlayan işlemler sağlamayı DrawingContext içerir. Bu, ve Bordertarafından Image kullanılan yöntemdir. Özel öğe bileşimi, bileşeninizin görünümünü oluşturmak için türdeki Visual nesneleri kullanmayı içerir. Örnek için bkz . DrawingVisual Nesneleri Kullanma. Track WPF'de özel öğe oluşturma kullanan bir denetim örneğidir. Doğrudan işleme ve özel öğe bileşimini aynı denetimde karıştırmak da mümkündür.

FrameworkElement'ten Türetmenin Avantajları

Aşağıdakilerden FrameworkElement birinin geçerli olup olmadığını türetebilirsiniz:

  • Denetiminizin görünümü üzerinde, basit öğe bileşimi tarafından sağlananın ötesinde hassas bir denetime sahip olmak istiyorsunuz.

  • Kendi işleme mantığınızı tanımlayarak denetiminizin görünümünü tanımlamak istiyorsunuz.

  • ve Controlile mümkün olandan daha öteye giden yeni yöntemlerle UserControl mevcut öğeleri oluşturmak istiyorsunuz.

Denetim Yazma Temelleri

Daha önce açıklandığı gibi, WPF'nin en güçlü özelliklerinden biri, bir denetimin görünümünü ve davranışını değiştirmek için temel özelliklerini ayarlamanın ötesine geçebilmektir, ancak yine de özel denetim oluşturma ihtiyacı yoktur. Stil, veri bağlama ve tetikleyici özellikleri WPF özellik sistemi ve WPF olay sistemi tarafından mümkün kılınır. Aşağıdaki bölümlerde, özel denetimi oluştururken kullandığınız modelden bağımsız olarak izlemeniz gereken bazı uygulamalar açıklanmıştır; böylece özel denetiminizin kullanıcıları bu özellikleri WPF'de bulunan bir denetimde olduğu gibi kullanabilir.

Bağımlılık Özelliklerini Kullanma

Bir özellik bir bağımlılık özelliği olduğunda, aşağıdakileri yapmak mümkündür:

  • özelliğini bir stilde ayarlayın.

  • özelliğini bir veri kaynağına bağlayın.

  • Özelliğin değeri olarak dinamik bir kaynak kullanın.

  • Özelliğine animasyon ekleme.

Denetiminizin bir özelliğinin bu işlevlerden herhangi birini desteklemesini istiyorsanız, bunu bir bağımlılık özelliği olarak uygulamanız gerekir. Aşağıdaki örnek, aşağıdakileri yaparak adlı Value bir bağımlılık özelliğini tanımlar:

  • Alan olarak adlandırılan ValueProperty birstaticDependencyPropertypublicreadonly tanımlayıcı tanımlayın.

  • Aşağıdakileri belirtmek için çağırarak DependencyProperty.Registerözellik adını özellik sistemine kaydedin:

    • Özelliğin adı.

    • Özelliğin türü.

    • Özelliğin sahibi olan tür.

    • özelliği için meta veriler. Meta veriler özelliğin varsayılan değeri olan a CoerceValueCallback ve değerini PropertyChangedCallbackiçerir.

  • Özelliğinin ve set erişimcilerini uygulayarak bağımlılık özelliğini kaydetmek için kullanılan aynı ad olan adlı Valuebir CLR sarmalayıcı özelliği get tanımlayın. ve set erişimcilerinin sırasıyla yalnızca ve'yi SetValue çağırdığını getGetValue unutmayın. İstemciler ve WPF erişimcileri atlayıp ve doğrudan çağırabileceğinden GetValueSetValue , bağımlılık özelliklerinin erişimcilerinin ek mantık içermemesi önerilir. Örneğin, bir özellik bir veri kaynağına bağlı olduğunda özelliğin set erişimcisi çağrılmaz. Alma ve ayarlama erişimcilerine ek mantık eklemek yerine, değerini yanıtlamak veya değiştiğinde ValidateValueCallbackdenetlemek için , CoerceValueCallbackve PropertyChangedCallback temsilcilerini kullanın. Bu geri çağırmalar hakkında daha fazla bilgi için bkz . Bağımlılık Özelliği Geri Çağırmaları ve Doğrulama.

  • adlı CoerceValueiçin CoerceValueCallback bir yöntem tanımlayın. CoerceValue değerinin Value değerine eşit MinValue veya daha büyük ve küçük veya eşit MaxValueolmasını sağlar.

  • için PropertyChangedCallbackadlı OnValueChangedbir yöntem tanımlayın. OnValueChanged bir RoutedPropertyChangedEventArgs<T> nesnesi oluşturur ve yönlendirilen olayı tetiklemeye ValueChanged hazırlanır. Yönlendirilen olaylar sonraki bölümde ele alınıyor.

/// <summary>
/// Identifies the Value dependency property.
/// </summary>
public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register(
        "Value", typeof(decimal), typeof(NumericUpDown),
        new FrameworkPropertyMetadata(MinValue, new PropertyChangedCallback(OnValueChanged),
                                      new CoerceValueCallback(CoerceValue)));

/// <summary>
/// Gets or sets the value assigned to the control.
/// </summary>
public decimal Value
{
    get { return (decimal)GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }
}

private static object CoerceValue(DependencyObject element, object value)
{
    decimal newValue = (decimal)value;
    NumericUpDown control = (NumericUpDown)element;

    newValue = Math.Max(MinValue, Math.Min(MaxValue, newValue));

    return newValue;
}

private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
    NumericUpDown control = (NumericUpDown)obj;			

    RoutedPropertyChangedEventArgs<decimal> e = new RoutedPropertyChangedEventArgs<decimal>(
        (decimal)args.OldValue, (decimal)args.NewValue, ValueChangedEvent);
    control.OnValueChanged(e);
}
''' <summary>
''' Identifies the Value dependency property.
''' </summary>
Public Shared ReadOnly ValueProperty As DependencyProperty = DependencyProperty.Register("Value", GetType(Decimal), GetType(NumericUpDown), New FrameworkPropertyMetadata(MinValue, New PropertyChangedCallback(AddressOf OnValueChanged), New CoerceValueCallback(AddressOf CoerceValue)))

''' <summary>
''' Gets or sets the value assigned to the control.
''' </summary>
Public Property Value() As Decimal
    Get
        Return CDec(GetValue(ValueProperty))
    End Get
    Set(ByVal value As Decimal)
        SetValue(ValueProperty, value)
    End Set
End Property

Private Shared Overloads Function CoerceValue(ByVal element As DependencyObject, ByVal value As Object) As Object
    Dim newValue As Decimal = CDec(value)
    Dim control As NumericUpDown = CType(element, NumericUpDown)

    newValue = Math.Max(MinValue, Math.Min(MaxValue, newValue))

    Return newValue
End Function

Private Shared Sub OnValueChanged(ByVal obj As DependencyObject, ByVal args As DependencyPropertyChangedEventArgs)
    Dim control As NumericUpDown = CType(obj, NumericUpDown)

    Dim e As New RoutedPropertyChangedEventArgs(Of Decimal)(CDec(args.OldValue), CDec(args.NewValue), ValueChangedEvent)
    control.OnValueChanged(e)
End Sub

Daha fazla bilgi için bkz . Özel Bağımlılık Özellikleri.

Yönlendirilmiş Olayları Kullanma

Bağımlılık özellikleri, CLR özellikleri gösterimini ek işlevlerle genişletirken, yönlendirilen olaylar da standart CLR olaylarının gösterimini genişletir. Yeni bir WPF denetimi oluşturduğunuzda, yönlendirilmiş bir olay aşağıdaki davranışı desteklediğinden, olayınızı yönlendirilmiş olay olarak uygulamak da iyi bir uygulamadır:

  • Olaylar birden çok denetimin üst öğesinde işlenebilir. Bir olay bir kabarcık olayıysa, öğe ağacındaki tek bir üst öğe olaya abone olabilir. Daha sonra uygulama yazarları birden çok denetimin olayına yanıt vermek için bir işleyici kullanabilir. Örneğin, denetiminiz içindeki ListBox her öğenin bir parçasıysa (bir içinde DataTemplatebulunduğundan), uygulama geliştiricisi denetiminizin üzerindeki olayı için olay işleyicisini ListBoxtanımlayabilir. Denetimlerden herhangi birinde olay gerçekleştiğinde, olay işleyicisi çağrılır.

  • Yönlendirilen olaylar, uygulama geliştiricilerinin bir EventSetterstil içindeki bir olayın işleyicisini belirtmesini sağlayan bir içinde kullanılabilir.

  • Yönlendirilen olaylar, XAML kullanarak özelliklerin animasyonu için yararlı olan bir EventTriggeriçinde kullanılabilir. Daha fazla bilgi için bkz. Animasyona Genel Bakış.

Aşağıdaki örnek, aşağıdakileri yaparak yönlendirilmiş bir olayı tanımlar:

  • Alan olarak adlandırılan ValueChangedEvent birstaticRoutedEventpublicreadonly tanımlayıcı tanımlayın.

  • yöntemini çağırarak EventManager.RegisterRoutedEvent yönlendirilen olayı kaydedin. Örnek, çağırdığında RegisterRoutedEventaşağıdaki bilgileri belirtir:

    • Olayın adı şeklindedir ValueChanged.

    • Yönlendirme stratejisi, Bubblekaynaktaki bir olay işleyicisinin (olayı oluşturan nesne) önce çağrılır ve ardından en yakın üst öğedeki olay işleyicisi ile başlayarak kaynağın üst öğelerindeki olay işleyicileri sırayla çağrılır.

    • Olay işleyicisinin RoutedPropertyChangedEventHandler<T>türü, bir Decimal türle oluşturulur.

    • Olayın sahip olan türü şeklindedir NumericUpDown.

  • adlı ValueChanged bir genel olay bildirin ve olay erişimci bildirimleri içerir. Örnek, WPF olay hizmetlerini kullanmak için erişimci bildiriminde ve RemoveHandler erişimci bildiriminde çağrılar.AddHandleraddremove

  • Olayı tetikleyen ValueChanged adlı OnValueChanged korumalı bir sanal yöntem oluşturun.

/// <summary>
/// Identifies the ValueChanged routed event.
/// </summary>
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent(
    "ValueChanged", RoutingStrategy.Bubble,
    typeof(RoutedPropertyChangedEventHandler<decimal>), typeof(NumericUpDown));

/// <summary>
/// Occurs when the Value property changes.
/// </summary>
public event RoutedPropertyChangedEventHandler<decimal> ValueChanged
{
    add { AddHandler(ValueChangedEvent, value); }
    remove { RemoveHandler(ValueChangedEvent, value); }
}

/// <summary>
/// Raises the ValueChanged event.
/// </summary>
/// <param name="args">Arguments associated with the ValueChanged event.</param>
protected virtual void OnValueChanged(RoutedPropertyChangedEventArgs<decimal> args)
{
    RaiseEvent(args);
}
''' <summary>
''' Identifies the ValueChanged routed event.
''' </summary>
Public Shared ReadOnly ValueChangedEvent As RoutedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, GetType(RoutedPropertyChangedEventHandler(Of Decimal)), GetType(NumericUpDown))

''' <summary>
''' Occurs when the Value property changes.
''' </summary>
Public Custom Event ValueChanged As RoutedPropertyChangedEventHandler(Of Decimal)
    AddHandler(ByVal value As RoutedPropertyChangedEventHandler(Of Decimal))
        MyBase.AddHandler(ValueChangedEvent, value)
    End AddHandler
    RemoveHandler(ByVal value As RoutedPropertyChangedEventHandler(Of Decimal))
        MyBase.RemoveHandler(ValueChangedEvent, value)
    End RemoveHandler
    RaiseEvent(ByVal sender As System.Object, ByVal e As RoutedPropertyChangedEventArgs(Of Decimal))
    End RaiseEvent
End Event

''' <summary>
''' Raises the ValueChanged event.
''' </summary>
''' <param name="args">Arguments associated with the ValueChanged event.</param>
Protected Overridable Sub OnValueChanged(ByVal args As RoutedPropertyChangedEventArgs(Of Decimal))
    MyBase.RaiseEvent(args)
End Sub

Daha fazla bilgi için bkz . Yönlendirilmiş Olaylara Genel Bakış ve Özel Yönlendirilmiş Olay Oluşturma.

Bağlama kullan

Denetiminizin kullanıcı arabirimini mantığından ayırmak için veri bağlamayı kullanmayı göz önünde bulundurun. Denetiminizin görünümünü kullanarak ControlTemplatetanımlarsanız bu özellikle önemlidir. Veri bağlamayı kullandığınızda, koddan kullanıcı arabiriminin belirli bölümlerine başvurma gereksinimini ortadan kaldırabilirsiniz. kodu ve içindeki ControlTemplate öğelere başvurduğunda başvuruda bulunan öğenin yeni ControlTemplateöğesine eklenmesi gerektiğinden ControlTemplateControlTemplate, içindeki öğelere başvurmaktan kaçınmak iyi bir fikirdir.

Aşağıdaki örnek denetimi güncelleştirir TextBlockNumericUpDown , buna bir ad atar ve metin kutusuna kodda ada göre başvurur.

<Border BorderThickness="1" BorderBrush="Gray" Margin="2" 
        Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Stretch">
  <TextBlock Name="valueText" Width="60" TextAlignment="Right" Padding="5"/>
</Border>
private void UpdateTextBlock()
{
    valueText.Text = Value.ToString();
}
Private Sub UpdateTextBlock()
    valueText.Text = Value.ToString()
End Sub

Aşağıdaki örnek, aynı şeyi gerçekleştirmek için bağlamayı kullanır.

<Border BorderThickness="1" BorderBrush="Gray" Margin="2" 
        Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Stretch">

    <!--Bind the TextBlock to the Value property-->
    <TextBlock 
        Width="60" TextAlignment="Right" Padding="5"
        Text="{Binding RelativeSource={RelativeSource FindAncestor, 
                       AncestorType={x:Type local:NumericUpDown}}, 
                       Path=Value}"/>

</Border>

Veri bağlama hakkında daha fazla bilgi için bkz. Veri Bağlamaya Genel Bakış.

Tasarım Aracı için tasarım

Visual Studio için WPF Tasarım Aracı özel WPF denetimleri için destek almak için (örneğin, Özellikler penceresi ile özellik düzenleme), bu yönergeleri izleyin. WPF Tasarım Aracı geliştirme hakkında daha fazla bilgi için bkz. Visual Studio'da XAML Tasarlama.

Bağımlılık Özellikleri

"Bağımlılık Özelliklerini Kullan" bölümünde daha önce açıklandığı gibi CLR get ve set erişimcileri uyguladığından emin olun. Tasarım Aracı bir bağımlılık özelliğinin varlığını algılamak için sarmalayıcıyı kullanabilir, ancak WPF ve denetimin istemcileri gibi bunlar özelliği alırken veya ayarlarken erişimcileri çağırmak için gerekli değildir.

Ekli Özellikler

Aşağıdaki yönergeleri kullanarak özel denetimlere ekli özellikler uygulamanız gerekir:

  • yöntemini kullanarak oluşturmakta olan PropertyName biçiminde bir publicreadonlyDependencyPropertyRegisterAttachedstaticforma sahip olun.Property geçirilen RegisterAttached özellik adı PropertyName ile eşleşmelidir.

  • PropertyName veGet PropertyName adlıSet bir çift publicstatic CLR yöntemi uygulayın. Her iki yöntem de ilk bağımsız değişkenleri olarak öğesinden DependencyProperty türetilmiş bir sınıfı kabul etmelidir. SetPropertyName yöntemi, türü özelliğin kayıtlı veri türüyle eşleşen bir bağımsız değişken de kabul eder. GetPropertyName yöntemi aynı türde bir değer döndürmelidir. SetPropertyName yöntemi eksikse, özellik salt okunur olarak işaretlenir.

  • SetPropertyName ve GetPropertyName,sırasıyla hedef bağımlılık nesnesinde ve SetValue yöntemlerine doğrudan GetValue yönlendirilmelidir. Tasarım Aracı, yöntem sarmalayıcısı aracılığıyla çağırarak veya hedef bağımlılık nesnesine doğrudan çağrı yaparak ekli özelliğe erişebilir.

Ekli özellikler hakkında daha fazla bilgi için bkz . Ekli Özelliklere Genel Bakış.

Paylaşılan Kaynakları Tanımlama ve Kullanma

Denetiminizi uygulamanızla aynı derlemeye ekleyebilir veya denetiminizi birden çok uygulamada kullanılabilecek ayrı bir derlemede paketleyebilirsiniz. Çoğunlukla, bu konuda açıklanan bilgiler kullandığınız yöntemden bağımsız olarak geçerlidir. Ancak, dikkate değer bir fark vardır. Bir denetimi bir uygulamayla aynı derlemeye yerleştirdiğinizde App.xaml dosyasına genel kaynaklar ekleyebilirsiniz. Ancak yalnızca denetimleri içeren bir derlemenin kendisiyle ilişkilendirilmiş bir Application nesnesi olmadığından App.xaml dosyası kullanılamaz.

Bir uygulama bir kaynağı ararken aşağıdaki sırayla üç düzeye bakar:

  1. Öğe düzeyi.

    Sistem, kaynağa başvuran öğesiyle başlar ve ardından kök öğeye ulaşılana kadar mantıksal üst öğenin kaynaklarını arar ve bu şekilde devam eder.

  2. Uygulama düzeyi.

    Nesnesi tarafından Application tanımlanan kaynaklar.

  3. Tema düzeyi.

    Tema düzeyi sözlükler Temalar adlı bir alt klasörde depolanır. Temalar klasöründeki dosyalar temalara karşılık gelir. Örneğin, Aero.NormalColor.xaml, Luna.NormalColor.xaml, Royale.NormalColor.xaml vb. olabilir. Generic.xaml adlı bir dosyanız da olabilir. Sistem temalar düzeyinde bir kaynak ararken, önce temaya özgü dosyada arar ve ardından generic.xaml dosyasında arar.

Denetiminiz uygulamadan ayrı bir derlemede olduğunda, genel kaynaklarınızı öğe düzeyine veya tema düzeyine yerleştirmeniz gerekir. Her iki yöntemin de avantajları vardır.

Kaynakları Öğe Düzeyinde Tanımlama

Özel bir kaynak sözlüğü oluşturup bunu denetiminizin kaynak sözlüğüyle birleştirerek öğe düzeyinde paylaşılan kaynakları tanımlayabilirsiniz. Bu yöntemi kullandığınızda, kaynak dosyanıza istediğiniz adı verebilir ve denetimlerinizle aynı klasörde yer alabilir. Öğe düzeyindeki kaynaklar anahtar olarak basit dizeleri de kullanabilir. Aşağıdaki örnek, Dictionary1.xaml adlı bir LinearGradientBrush kaynak dosyası oluşturur.

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <LinearGradientBrush 
    x:Key="myBrush"  
    StartPoint="0,0" EndPoint="1,1">
    <GradientStop Color="Red" Offset="0.25" />
    <GradientStop Color="Blue" Offset="0.75" />
  </LinearGradientBrush>
  
</ResourceDictionary>

Sözlüğünüzü tanımladıktan sonra, denetiminizin kaynak sözlüğüyle birleştirmeniz gerekir. Bunu XAML veya kod kullanarak yapabilirsiniz.

Aşağıdaki örnek, XAML kullanarak bir kaynak sözlüğü birleştirir.

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Dictionary1.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>

Bu yaklaşımın dezavantajı, her başvurduğunuz zaman bir ResourceDictionary nesnenin oluşturulmasıdır. Örneğin, kitaplığınızda 10 özel denetim varsa ve XAML kullanarak her denetim için paylaşılan kaynak sözlüklerini birleştirirseniz, 10 özdeş ResourceDictionary nesne oluşturursunuz. Koddaki kaynakları birleştirir ve sonuçta ResourceDictionaryelde edilen değerini döndüren statik bir sınıf oluşturarak bunu önleyebilirsiniz.

Aşağıdaki örnek, paylaşılan ResourceDictionarybir döndüren bir sınıf oluşturur.

internal static class SharedDictionaryManager
{
    internal static ResourceDictionary SharedDictionary
    {
        get
        {
            if (_sharedDictionary == null)
            {
                System.Uri resourceLocater =
                    new System.Uri("/ElementResourcesCustomControlLibrary;component/Dictionary1.xaml",
                                    System.UriKind.Relative);

                _sharedDictionary =
                    (ResourceDictionary)Application.LoadComponent(resourceLocater);
            }

            return _sharedDictionary;
        }
    }

    private static ResourceDictionary _sharedDictionary;
}

Aşağıdaki örnek, paylaşılan kaynağı çağrısından InitializeComponentönce denetimin oluşturucusunda özel bir denetimin kaynaklarıyla birleştirir. SharedDictionaryManager.SharedDictionary statik bir özellik olduğundan, ResourceDictionary yalnızca bir kez oluşturulur. Kaynak sözlüğü çağrılmadan önce InitializeComponent birleştirildiğinden, kaynaklar XAML dosyasındaki denetim tarafından kullanılabilir.

public NumericUpDown()
{
    this.Resources.MergedDictionaries.Add(SharedDictionaryManager.SharedDictionary);
    InitializeComponent();
}

Tema Düzeyinde Kaynakları Tanımlama

WPF, farklı Windows temaları için kaynak oluşturmanıza olanak tanır. Denetim yazarı olarak, hangi temanın kullanıldığına bağlı olarak denetiminizin görünümünü değiştirmek için belirli bir tema için kaynak tanımlayabilirsiniz. Örneğin, Windows Klasik temasındaki (Windows 2000 için varsayılan tema) görünümüButton, Her tema için farklı ControlTemplate bir Button tema kullandığından, Windows Luna temasındaki (Windows XP için varsayılan tema) Button bir görünümden farklıdır.

Bir temaya özgü kaynaklar, belirli bir dosya adına sahip bir kaynak sözlüğünde tutulur. Bu dosyalar, denetimi içeren klasörün alt klasörü olan adlı Themes bir klasörde olmalıdır. Aşağıdaki tabloda kaynak sözlüğü dosyaları ve her dosyayla ilişkili tema listeleniyor:

Kaynak sözlüğü dosya adı Windows teması
Classic.xaml Windows XP'de klasik Windows 9x/2000 görünümü
Luna.NormalColor.xaml Windows XP'de varsayılan mavi tema
Luna.Homestead.xaml Windows XP'de zeytin teması
Luna.Metallic.xaml Windows XP'de gümüş tema
Royale.NormalColor.xaml Windows XP Media Center Edition'da varsayılan tema
Aero.NormalColor.xaml Windows Vista'da varsayılan tema

Her tema için bir kaynak tanımlamanız gerekmez. Belirli bir tema için kaynak tanımlanmamışsa, denetim kaynağı denetler Classic.xaml . Kaynak, geçerli temaya karşılık gelen dosyada veya içinde Classic.xamltanımlanmamışsa, denetim adlı generic.xamlbir kaynak sözlüğü dosyasında bulunan genel kaynağı kullanır. Dosya generic.xaml , temaya özgü kaynak sözlüğü dosyalarıyla aynı klasörde bulunur. Belirli bir Windows temasına karşılık gelemese generic.xaml de, yine de tema düzeyinde bir sözlüktür.

Tema ve UI otomasyonu desteğine sahip C# veya Visual Basic NumericUpDown özel denetimi, denetim için NumericUpDown iki kaynak sözlük içerir: biri generic.xaml, diğeri de Luna.NormalColor.xaml içinde.

Temaya özgü kaynak sözlüğü dosyalarından herhangi birine bir ControlTemplate yerleştirdiğinizde, denetiminiz için statik bir oluşturucu oluşturmanız ve aşağıdaki örnekte gösterildiği gibi üzerinde yöntemini DefaultStyleKeyçağırmanız OverrideMetadata(Type, PropertyMetadata) gerekir.

static NumericUpDown()
{
    DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown),
               new FrameworkPropertyMetadata(typeof(NumericUpDown)));
}
Shared Sub New()
    DefaultStyleKeyProperty.OverrideMetadata(GetType(NumericUpDown), New FrameworkPropertyMetadata(GetType(NumericUpDown)))
End Sub
Tema Kaynakları için Anahtar Tanımlama ve Başvurma

Öğe düzeyinde bir kaynak tanımladığınızda, anahtarı olarak bir dize atayabilir ve dize aracılığıyla kaynağa erişebilirsiniz. Tema düzeyinde bir kaynak tanımlarken, anahtar olarak bir ComponentResourceKey kullanmanız gerekir. Aşağıdaki örnek generic.xaml içinde bir kaynak tanımlar.

<LinearGradientBrush 
     x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:Painter}, 
                                  ResourceId=MyEllipseBrush}"  
                                  StartPoint="0,0" EndPoint="1,0">
    <GradientStop Color="Blue" Offset="0" />
    <GradientStop Color="Red" Offset="0.5" />
    <GradientStop Color="Green" Offset="1"/>
</LinearGradientBrush>

Aşağıdaki örnek, anahtarı olarak belirterek kaynağa başvurur ComponentResourceKey .

<RepeatButton 
    Grid.Column="1" Grid.Row="0"
    Background="{StaticResource {ComponentResourceKey 
                        TypeInTargetAssembly={x:Type local:NumericUpDown}, 
                        ResourceId=ButtonBrush}}">
    Up
</RepeatButton>
<RepeatButton 
    Grid.Column="1" Grid.Row="1"
    Background="{StaticResource {ComponentResourceKey 
                    TypeInTargetAssembly={x:Type local:NumericUpDown}, 
                    ResourceId=ButtonBrush}}">
    Down
 </RepeatButton>
Tema Kaynaklarının Konumunu Belirtme

Bir denetimin kaynaklarını bulmak için barındırma uygulamasının derlemenin denetime özgü kaynaklar içerdiğini bilmesi gerekir. Bunu, denetimini içeren derlemeye ekleyerek ThemeInfoAttribute gerçekleştirebilirsiniz. , ThemeInfoAttribute genel kaynakların konumunu belirten bir GenericDictionaryLocation özelliğe ve temaya özgü kaynakların konumunu belirten bir ThemeDictionaryLocation özelliğe sahiptir.

Aşağıdaki örnek, genel ve temaya özgü kaynakların denetimle aynı derlemede olduğunu belirtmek için ve ThemeDictionaryLocation özelliklerini SourceAssemblyolarak ayarlarGenericDictionaryLocation.

[assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly,
           ResourceDictionaryLocation.SourceAssembly)]
<Assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly)>

Ayrıca bkz.