Veri bağlamaya genel bakış (WPF .NET)

Windows Presentation Foundation'da (WPF) veri bağlama, uygulamaların verileri sunup bunlarla etkileşim kurması için basit ve tutarlı bir yol sağlar. Öğeler, .NET nesneleri ve XML biçimindeki farklı veri kaynaklarından verilere bağlanabilir. Button gibi herhangi bir ContentControl ile ListBox ve ListView gibi herhangi bir ItemsControl, tek veri öğeleri veya veri öğeleri koleksiyonlarının esnek stillerini etkinleştirmek için yerleşik işlevlere sahiptir. Verilerin üzerinde sıralama, filtreleme ve grup görünümleri oluşturulabilir.

WPF'de veri bağlamanın geleneksel modellere göre çeşitli avantajları vardır. Bunlar arasında çok çeşitli özelliklere göre veri bağlama desteği, verilerin esnek kullanıcı arabirimi gösterimi ve iş mantığının kullanıcı arabiriminden temiz ayrımı yer alır.

Bu makalede önce WPF veri bağlaması için temel kavramlar ele alınmakta, ardından Binding sınıfının kullanımı ve veri bağlamanın diğer özellikleri ele alınmaktadır.

Önemli

.NET 7 ve .NET 6 için Masaüstü Kılavuzu belgeleri yapım aşamasındadır.

Veri bağlama nedir?

Veri bağlama, uygulama kullanıcı arabirimiyle görüntülenen veriler arasında bağlantı kuran işlemdir. Bağlama doğru ayarlara sahipse ve veriler doğru bildirimleri sağlıyorsa, veriler değerini değiştirdiğinde, verilere bağlı öğeler otomatik olarak değişir. Veri bağlama, bir öğedeki verilerin dış gösterimi değişirse, temel alınan verilerin değişikliği yansıtacak şekilde otomatik olarak güncelleştirilebileceği anlamına da gelebilir. Örneğin, kullanıcı bir TextBox öğesindeki değeri düzenlerse, temel alınan veri değeri otomatik olarak bu değişikliği yansıtacak şekilde güncelleştirilir.

Veri bağlamanın tipik bir kullanımı, sunucu veya yerel yapılandırma verilerini formlara veya diğer kullanıcı arabirimi denetimlerine yerleştirmektir. WPF'de bu kavram, çok çeşitli özellikleri farklı veri kaynaklarına bağlamayı içerecek şekilde genişletilir. WPF'de, öğelerin bağımlılık özellikleri .NET nesnelerine (Web Hizmetleri ve Web özellikleriyle ilişkili ADO.NET nesneler veya nesneler dahil) ve XML verilerine bağlanabilir.

Temel veri bağlama kavramları

Hangi öğeyi bağladığınıza ve veri kaynağınızın yapısına bakılmaksızın, her bağlama her zaman aşağıdaki şekilde gösterilen modeli izler.

Diagram that shows the basic data binding model.

Şekilde gösterildiği gibi, veri bağlama temelde bağlama hedefiniz ile bağlama kaynağınız arasındaki köprüdür. Şekilde, aşağıdaki temel WPF veri bağlama kavramları gösterilmektedir:

  • Genellikle her bağlamanın dört bileşeni vardır:

    • Bir bağlama hedef nesnesi.
    • Bir hedef özelliği.
    • Bir bağlama kaynağı.
    • Kullanılacak bağlama kaynağındaki değerin yolu.

    Örneğin, bir TextBox öğesinin içeriğini Employee.Name özelliğine bağlarsanız bağlamanızı aşağıdaki tablo gibi ayarlayabilirsiniz:

    Ayar Değer
    Hedef TextBox
    Hedef özelliği Text
    Kaynak nesne Employee
    Kaynak nesne değeri yolu Name
  • Hedef özellik bir bağımlılık özelliği olmalıdır.

    UIElement özelliklerin çoğu bağımlılık özellikleridir ve salt okunur özellikler dışında çoğu bağımlılık özelliği, varsayılan olarak veri bağlamayı destekler. Yalnızca DependencyObject öğesinden türetilen türler bağımlılık özelliklerini tanımlayabilir. Tüm UIElement türleri DependencyObject öğesinden türetilir.

  • Bağlama kaynakları özel .NET nesneleriyle sınırlı değildir.

    Şekilde gösterilmese de, bağlama kaynak nesnesinin özel bir .NET nesnesi olmakla sınırlı olmadığı belirtilmelidir. WPF veri bağlama .NET nesneleri, XML ve hatta XAML öğesi nesneleri biçimindeki verileri destekler. Bazı örnekleri sağlamak için bağlama kaynağınız bir UIElement, herhangi bir liste nesnesi, bir ADO.NET veya Web Hizmetleri nesnesi ya da XML verilerinizi içeren bir XmlNode olabilir. Daha fazla bilgi için, bkz. Bağlama kaynaklarına genel bakış.

Bir bağlama oluştururken, bağlama hedefini bağlama kaynağına bağladığınızı unutmamanız önemlidir. Örneğin, veri bağlama kullanarak bir ListBox içinde bazı temel XML verilerini görüntülüyorsanız, ListBox öğenizi XML verilerine bağlarsınız.

Bağlama oluşturmak için Binding nesnesini kullanırsınız. Bu makalenin geri kalanında, ilişkili kavramların birçoğu ile Binding nesnesinin bazı özellikleri ve kullanımı ele alınmaktadır.

Veri bağlamı

XAML öğelerinde veri bağlama bildirildiğinde, ilk DataContext özelliklerine bakarak veri bağlamayı çözümlerler. Veri bağlamı genellikle bağlama kaynağı değer yolu değerlendirmesi için bağlama kaynak nesnesidir. Bağlamada bu davranışı geçersiz kılabilir ve belirli bir bağlama kaynak nesnesi değeri ayarlayabilirsiniz. Bağlamayı barındıran nesnenin DataContext özelliği ayarlanmadıysa, üst öğenin DataContext özelliği denetlenir ve XAML nesne ağacının köküne kadar bu şekilde devam eder. Kısacası, bağlamayı çözümlemek için kullanılan veri bağlamı, nesne üzerinde açıkça ayarlanmadığı sürece üst öğeden devralınır.

Bağlamalar, bağlama çözümlemesi için veri bağlamını kullanmak yerine belirli bir nesneyle çözümlenecek şekilde yapılandırılabilir. Bir kaynak nesneyi doğrudan belirtmek, örneğin, bir nesnenin ön plan rengini başka bir nesnenin arka plan rengine bağladığınızda kullanılır. Bağlama bu iki nesne arasında çözümlendiğinden, veri bağlamı gerekli değildir. Buna karşılık, belirli kaynak nesnelere bağlı olmayan bağlamalar veri bağlamı çözümlemesini kullanır.

DataContext özelliği değiştiğinde veri bağlamından etkilenebilen tüm bağlamalar yeniden değerlendirilir.

Veri akışının yönü

Önceki şekilde okla gösterildiği gibi, bir bağlamanın veri akışı, bağlama kaynağı uygun bildirimleri sağlıyorsa bağlama hedefinden bağlama kaynağına (örneğin, bir kullanıcı bir TextBox değerini düzenlediğinde kaynak değeri değişir) ve/veya bağlama kaynağından bağlama hedefine (örneğin, TextBox içeriğiniz bağlama kaynağındaki değişikliklerle güncellenir) gidebilir.

Uygulamanızın, kullanıcıların verileri değiştirmesini ve kaynak nesneye geri yaymasını sağlayabilirsiniz. Veya kullanıcıların kaynak verileri güncelleştirmesini sağlamak istemeyebilirsiniz. Binding.Mode öğesini ayarlayarak veri akışını denetleyebilirsiniz.

Bu şekilde farklı veri akışı türleri gösterilmektedir:

Data binding data flow

  • OneWay bağlama, kaynak özellikte yapılan değişikliklerin hedef özelliği otomatik olarak güncelleştirmesine neden olur, ancak hedef özellikteki değişiklikler kaynak özelliğe geri yayılmaz. Bağlı olan denetim örtük olarak salt okunursa bu bağlama türü uygundur. Örneğin, bir hisse senedi değerleyicisi gibi bir kaynağa bağlanabilir veya belki de hedef mülkünüz, bir tablonun veriye bağlı arka plan rengi gibi değişiklik yapmak için sağlanan bir denetim arayüzüne sahip değildir. Hedef özelliğin değişikliklerini izlemeye gerek yoksa OneWay bağlama modunun kullanılması TwoWay bağlama modunun ek yükünü önler.

  • TwoWay bağlama, kaynak özellikte veya hedef özellikte yapılan değişikliklerin diğerini otomatik olarak güncelleştirmesine neden olur. Bu bağlama türü düzenlenebilir formlar veya diğer tam etkileşimli kullanıcı arabirimi senaryoları için uygundur. Çoğu özellik OneWay bağlama için varsayılandır, ancak bazı bağımlılık özellikleri (genellikle TextBox.Text ve CheckBox.IsChecked gibi kullanıcı tarafından düzenlenebilir denetimlerin özellikleri) TwoWay bağlama için varsayılandır.

    Bir bağımlılık özelliğinin varsayılan olarak tek yönlü mü yoksa iki yönlü mü bağlandığını belirlemenin programlı bir yolu, ile DependencyProperty.GetMetadataözellik meta verilerini almaktır. Bu yöntemin dönüş türü, bağlamayla ilgili meta veriler içermeyen şeklindedir PropertyMetadata. Bununla birlikte, bu tür tür türetilmiş FrameworkPropertyMetadataöğesine dönüştürülebiliyorsa, özelliğin FrameworkPropertyMetadata.BindsTwoWayByDefault Boole değeri denetlenebilir. Aşağıdaki kod örneği özelliği için TextBox.Text meta verileri almayı gösterir:

    public static void PrintMetadata()
    {
        // Get the metadata for the property
        PropertyMetadata metadata = TextBox.TextProperty.GetMetadata(typeof(TextBox));
    
        // Check if metadata type is FrameworkPropertyMetadata
        if (metadata is FrameworkPropertyMetadata frameworkMetadata)
        {
            System.Diagnostics.Debug.WriteLine($"TextBox.Text property metadata:");
            System.Diagnostics.Debug.WriteLine($"  BindsTwoWayByDefault: {frameworkMetadata.BindsTwoWayByDefault}");
            System.Diagnostics.Debug.WriteLine($"  IsDataBindingAllowed: {frameworkMetadata.IsDataBindingAllowed}");
            System.Diagnostics.Debug.WriteLine($"        AffectsArrange: {frameworkMetadata.AffectsArrange}");
            System.Diagnostics.Debug.WriteLine($"        AffectsMeasure: {frameworkMetadata.AffectsMeasure}");
            System.Diagnostics.Debug.WriteLine($"         AffectsRender: {frameworkMetadata.AffectsRender}");
            System.Diagnostics.Debug.WriteLine($"              Inherits: {frameworkMetadata.Inherits}");
        }
    
        /*  Displays:
         *  
         *  TextBox.Text property metadata:
         *    BindsTwoWayByDefault: True
         *    IsDataBindingAllowed: True
         *          AffectsArrange: False
         *          AffectsMeasure: False
         *           AffectsRender: False
         *                Inherits: False
        */
    }
    
    Public Shared Sub PrintMetadata()
    
        Dim metadata As PropertyMetadata = TextBox.TextProperty.GetMetadata(GetType(TextBox))
        Dim frameworkMetadata As FrameworkPropertyMetadata = TryCast(metadata, FrameworkPropertyMetadata)
    
        If frameworkMetadata IsNot Nothing Then
    
            System.Diagnostics.Debug.WriteLine($"TextBox.Text property metadata:")
            System.Diagnostics.Debug.WriteLine($"  BindsTwoWayByDefault: {frameworkMetadata.BindsTwoWayByDefault}")
            System.Diagnostics.Debug.WriteLine($"  IsDataBindingAllowed: {frameworkMetadata.IsDataBindingAllowed}")
            System.Diagnostics.Debug.WriteLine($"        AffectsArrange: {frameworkMetadata.AffectsArrange}")
            System.Diagnostics.Debug.WriteLine($"        AffectsMeasure: {frameworkMetadata.AffectsMeasure}")
            System.Diagnostics.Debug.WriteLine($"         AffectsRender: {frameworkMetadata.AffectsRender}")
            System.Diagnostics.Debug.WriteLine($"              Inherits: {frameworkMetadata.Inherits}")
    
            '  Displays:
            '
            '  TextBox.Text property metadata:
            '    BindsTwoWayByDefault: True
            '    IsDataBindingAllowed: True
            '          AffectsArrange: False
            '          AffectsMeasure: False
            '           AffectsRender: False
            '                Inherits: False
        End If
    
    
    End Sub
    
  • OneWayToSource, OneWay bağlamanın tersidir; hedef özellik değiştiğinde kaynak özelliği güncelleştirir. Örnek senaryolardan biri, yalnızca kullanıcı arabiriminden kaynak değeri yeniden değerlendirmeniz gerektiğidir.

  • Şekilde gösterilmeyen OneTime bağlamadır, bu da kaynak özelliğin hedef özelliği başlatmasına neden olur, ancak sonraki değişiklikleri yaymaz. Veri bağlamı değişirse veya veri bağlamındaki nesne değişirse, değişiklik hedef özelliğine yansıtılmaz. Geçerli durumun anlık görüntüsü uygunsa veya veriler gerçekten statikse bu bağlama türü uygundur. Bu bağlama türü, hedef özelliğinizi bir kaynak özellikten bir değerle başlatmak istiyorsanız ve veri bağlamı önceden bilinmiyorsa da yararlıdır. Bu mod temelde kaynak değerin değişmediği durumlarda daha iyi performans sağlayan daha basit bir OneWay bağlama biçimidir.

Kaynak değişikliklerini algılamak için (OneWay ve TwoWay bağlamaları için geçerlidir), kaynağın INotifyPropertyChanged gibi uygun bir özellik değişikliği bildirim mekanizması uygulaması gerekir. INotifyPropertyChanged uygulama örneği için, bkz. Nasıl yapılır: Özellik değişikliği bildirimini (.NET Framework) uygulama.

Binding.Mode özelliğini bağlama modları hakkında daha fazla bilgi ve bağlama yönünün nasıl belirtileceğini gösteren bir örnek sağlar.

Kaynak güncelleştirmeleri tetikleyenler

TwoWay veya OneWayToSource olan bağlamalar, hedef özellikteki değişiklikleri dinler ve bunları kaynağı güncelleme olarak bilinen kaynağa geri yayar. Örneğin, temel alınan kaynak değerini değiştirmek için TextBox metnini düzenleyebilirsiniz.

Ancak, metni düzenlerken veya metni düzenlemeyi bitirdikten ve denetim odağı kaybettikten sonra kaynak değeriniz güncelleştiriliyor mu? Binding.UpdateSourceTrigger özelliği, kaynağın güncelleştirmesini neyin tetiklediğini belirler. Aşağıdaki şekildeki sağ okların noktaları Binding.UpdateSourceTrigger özelliğin rolünü gösterir.

Diagram that shows the role of the UpdateSourceTrigger property.

UpdateSourceTrigger için değer UpdateSourceTrigger.PropertyChanged ise TwoWay öğesinin sağ okunun veya OneWayToSource bağlamalarının işaret ettiği değer, hedef özellik değiştiğinde güncelleştirilir. Ancak UpdateSourceTrigger için değer LostFocus ise hedef özellik odağı kaybettiğinde bu değer yalnızca yeni değerle güncelleştirilir.

Mode özelliğine benzer şekilde, farklı bağımlılık özellikleri farklı varsayılan UpdateSourceTrigger değerlerine sahiptir. Çoğu bağımlılık özelliği için varsayılan değer PropertyChanged, hedef özellik değeri değiştirildiğinde kaynak özelliğin değerinin anında değişmesine neden olur. Anlık değişiklikler, CheckBox ve diğer basit denetimler için uygundur. Bununla birlikte, metin alanları için, her tuş vuruşundan sonra güncelleştirme, performansı azaltabilir ve kullanıcıya, yeni değeri işlemeden önce geri alma ve yazım hatalarını düzeltme fırsatını reddedebilir. Örneğin, TextBox.Text özelliği varsayılan olarak LostFocus öğesinin UpdateSourceTrigger değerini alır; bu, kaynak değerinin TextBox.Text özelliği değiştirildiğinde değil, yalnızca kontrol öğesi odağı kaybettiğinde değişmesine neden olur. Bağımlılık özelliğinin varsayılan değerini bulma hakkında bilgi için UpdateSourceTrigger özelliği sayfasına bakın.

Aşağıdaki tabloda, TextBox örneği kullanılarak, her UpdateSourceTrigger değeri için örnek bir senaryo sağlanmaktadır.

UpdateSourceTrigger değeri Kaynak değer güncelleştirildiğinde TextBox için örnek senaryo
LostFocus (TextBox.Text için varsayılan) TextBox denetimi odağı kaybettiğinde. Doğrulama mantığıyla ilişkili bir TextBox (aşağıdaki Veri Doğrulama bölümüne bakın).
PropertyChanged TextBox içine yazarken. Sohbet odası penceresindeki TextBox denetimleri.
Explicit Uygulama UpdateSource çağırdığında. Düzenlenebilir bir formdaki TextBox denetimleri (kaynak değerleri yalnızca kullanıcı gönder düğmesine bastığında güncelleştirir).

Örnek için, bkz. Nasıl yapılır: TextBox metninin kaynağı ne zaman güncelleştirdiğini denetleme (.NET Framework).

Veri bağlama örneği

Veri bağlama örneği için, açık artırma öğelerinin listesini görüntüleyen Veri Bağlama Tanıtımı'ndan aşağıdaki uygulama kullanıcı arabirimine göz atın.

Data binding sample screenshot

Uygulama, veri bağlamanın aşağıdaki özelliklerini gösterir:

  • ListBox'ın içeriği bir AuctionItem nesneleri koleksiyonuna bağlıdır. AuctionItem nesnesi Description, StartPrice, StartDate, Category ve SpecialFeatures gibi özelliklere sahiptir.

  • ListBox içinde görüntülenen veriler (AuctionItem nesneleri) şablonlu hale gelir, böylece açıklama ve geçerli fiyat her öğe için gösterilir. Şablon, bir DataTemplate kullanılarak oluşturulur. Ayrıca, her öğenin görünümü, görüntülenen AuctionItem öğesinin SpecialFeatures değerine bağlıdır. AuctionItem öğesinin SpecialFeatures değeri Color ise, öğenin mavi bir kenarlığı vardır. Değer Vurgula ise, öğenin turuncu kenarlığı ve yıldızı vardır. Veri Şablonu Oluşturma bölümü, veri şablon oluşturma hakkında bilgi sağlar.

  • Kullanıcı sağlanan CheckBoxes öğesini kullanarak verileri gruplandırabilir, filtreleyebilir veya sıralayabilir. Yukarıdaki resimde Kategoriye göre gruplandır ve Kategoriye ve tarihe göre sıralaCheckBoxes seçilidir. Verilerin ürünün kategorisine göre gruplandırıldığını ve kategori adının alfabetik sırada olduğunu fark etmiş olabilirsiniz. Görüntüden fark etmek zor olsa da, öğeler de her kategorideki başlangıç tarihine göre sıralanır. Sıralama, koleksiyon görünümü kullanılarak yapılır. Koleksiyonlara bağlama bölümünde koleksiyon görünümleri ele alınmaktadır.

  • Kullanıcı bir öğeyi seçtiğinde ContentControl, seçili öğenin ayrıntılarını görüntüler. Bu deneyim, Ana ayrıntı senaryosu olarak adlandırılır. Ana ayrıntı senaryosu bölümünde bu bağlama türü hakkında bilgi sağlanır.

  • StartDate özelliğinin türü DateTime, milisaniye düzeyine kadar olan saati içeren bir tarih döndüren değerdir. Bu uygulamada, daha kısa bir tarih dizesinin görüntülenmesi için özel bir dönüştürücü kullanılmıştır. Veri dönüştürme bölümünde dönüştürücüler hakkında bilgi sağlanır.

Kullanıcı Ürün Ekle düğmesini seçtiğinde aşağıdaki form görüntülenir.

Add Product Listing page

Kullanıcı formdaki alanları düzenleyebilir, kısa veya ayrıntılı önizleme bölmelerini kullanarak ürün listesini önizleyebilir ve yeni ürün listesini eklemek için Submit öğesini seçebilir. Tüm mevcut gruplandırma, filtreleme ve sıralama ayarları yeni girişe uygulanır. Bu özel durumda, yukarıdaki görüntüde girilen öğe Bilgisayar kategorisindeki ikinci öğe olarak görüntülenir.

Bu görüntüde, Başlangıç TarihiTextBox ile sağlanan doğrulama mantığı gösterilmez. Kullanıcı geçersiz bir tarih girerse (geçersiz biçimlendirme veya geçmiş bir tarih), kullanıcıya bir ToolTip işareti ve TextBox öğesinin yanında kırmızı bir ünlem işareti ile bilgi verilir. Veri Doğrulama bölümünde doğrulama mantığının nasıl oluşturulacağı açıklanır.

Yukarıda özetlenen farklı veri bağlama özelliklerine geçmeden önce, WPF veri bağlamasını anlamak için kritik öneme sahip temel kavramları tartışacağız.

Bağlantı oluşturma

Önceki bölümlerde tartışılan bazı kavramları yeniden ifade etmek için, Binding nesnesini kullanarak bir bağlama oluşturursunuz ve her bağlamanın genellikle dört bileşeni vardır: bağlama hedefi, hedef özelliği, bağlama kaynağı ve kullanılacak kaynak değerine giden yol. Bu bölümde bağlamanın nasıl ayarlanacağı açıklanır.

Bağlama kaynakları, öğe için aktif DataContext öğesine bağlıdır. Öğeler açıkça tanımlanmadıysa, bunların DataContext öğelerini otomatik olarak devralır.

Bağlama kaynak nesnesinin SDKSample ad alanında tanımlanan MyData adlı bir sınıf olduğu aşağıdaki örneği göz önünde bulundurun. Gösterim amacıyla MyData değeri "Kırmızı" olarak ayarlanmış ColorName adlı bir dize özelliğine sahiptir. Bu nedenle, bu örnek kırmızı arka planlı bir düğme oluşturur.

<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:c="clr-namespace:SDKSample">
    <DockPanel.Resources>
        <c:MyData x:Key="myDataSource"/>
    </DockPanel.Resources>
    <DockPanel.DataContext>
        <Binding Source="{StaticResource myDataSource}"/>
    </DockPanel.DataContext>
    <Button Background="{Binding Path=ColorName}"
            Width="150" Height="30">
        I am bound to be RED!
    </Button>
</DockPanel>

Bağlama bildirimi söz dizimi hakkında daha fazla bilgi ve kodda bağlama ayarlama örnekleri için, bkz. Bağlama bildirimlerine genel bakış.

Bu örneği temel diyagramımıza uygularsak, sonuçta elde edilen şekil aşağıdaki gibi görünür. Arka plan özelliği varsayılan olarak OneWay bağlamayı desteklediğinden bu şekilde OneWay bağlama açıklanmaktadır.

Diagram that shows the data binding Background property.

ColorName özelliği dize türünde olduğunda Background özelliği Brush türünde olsa bile bu bağlamanın neden çalıştığını merak edebilirsiniz. Bu bağlama, Veri dönüştürme bölümünde açıklanan varsayılan tür dönüştürmesini kullanır.

Bağlama kaynağını belirtme

Önceki örnekte bağlama kaynağının DockPanel.DataContext özelliği ayarlanarak belirtildiğine dikkat edin. Button daha sonra DataContext değerini üst öğesi olan DockPanel öğesinden devralır. Yinelemek gerekirse, bağlama kaynak nesnesi bağlamanın dört gerekli bileşeninden biridir. Bu nedenle, bağlama kaynak nesnesi belirtilmeden bağlama hiçbir şey yapmaz.

Bağlama kaynak nesnesini belirtmenin çeşitli yolları vardır. Bir üst öğede DataContext özelliğini kullanmak, birden çok özelliği aynı kaynağa bağlarken yararlıdır. Ancak, bazen bağlama kaynağını tek tek bağlama bildirimlerinde belirtmek daha uygun olabilir. Önceki örnekte, DataContext özelliğini kullanmak yerine, aşağıdaki örnekte olduğu gibi Binding.Source özelliğini doğrudan düğmenin bağlama bildiriminde ayarlayarak bağlama kaynağını belirtebilirsiniz.

<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:c="clr-namespace:SDKSample">
    <DockPanel.Resources>
        <c:MyData x:Key="myDataSource"/>
    </DockPanel.Resources>
    <Button Background="{Binding Source={StaticResource myDataSource}, Path=ColorName}"
            Width="150" Height="30">
        I am bound to be RED!
    </Button>
</DockPanel>

DataContext özelliğini doğrudan bir öğe üzerinde ayarlamak, DataContext değerini bir atadan (ilk örnekteki düğme gibi) devralmak ve bağlamada (son örnekteki düğme gibi) Binding.Source özelliğini ayarlayarak bağlama kaynağını açıkça belirtmek dışında, bağlama kaynağını belirtmek için Binding.ElementName özelliğini veya Binding.RelativeSource özelliğini de kullanabilirsiniz. ElementName özelliği, uygulamanızdaki diğer öğelere bağlanırken (örneğin, bir düğmenin genişliğini ayarlamak için kaydırıcı kullanırken) kullanışlıdır. RelativeSource özelliği, bağlama ControlTemplate veya Styleiçinde belirtildiğinde yararlıdır. Daha fazla bilgi için, bkz. Bağlama kaynaklarına genel bakış.

Değerin yolunu belirtme

Bağlama kaynağınız bir nesneyse, bağlamanız için kullanılacak değeri belirtmek için Binding.Path özelliğini kullanırsınız. XML verilerine bağlanacaksanız, değeri belirtmek için Binding.XPath özelliğini kullanırsınız. Bazı durumlarda, verileriniz XML olduğunda bile Path özelliğini kullanmak uygulanabilir. Örneğin, döndürülen bir XmlNode'un Name özelliğine erişmek istiyorsanız (XPath sorgusunun bir sonucu olarak), XPath özelliğine ek olarak Path özelliğini kullanmanız gerekir.

Daha fazla bilgi için Path ve XPath özelliklerine bakın.

Kullanılacak değerin Path bağlamanın dört gerekli bileşeninden biri olduğunu vurgulasak da, nesnenin tamamına bağlamak istediğiniz senaryolarda kullanılacak değer bağlama kaynak nesnesiyle aynı olacaktır. Bu gibi durumlarda, Pathbelirtmemek uygulanabilir. Aşağıdaki örneği inceleyin.

<ListBox ItemsSource="{Binding}"
         IsSynchronizedWithCurrentItem="true"/>

Yukarıdaki örnekte boş bağlama söz dizimi kullanılmaktadır: {Binding}. Bu durumda, ListBox bir üst DockPanel öğesinden DataContext'i devralır (bu örnekte gösterilmez). Yol belirtilmediğinde, varsayılan değer nesnenin tamamına bağlanmaktır. Başka bir deyişle, bu örnekte, ItemsSource özelliğini nesnenin tamamına bağladığımız için yol dışarıda bırakılmıştır. (Ayrıntılı bir tartışma için Koleksiyonlara bağlama bölümüne bakın.)

Bu senaryo, bir koleksiyona bağlamanın dışında, bir nesnenin yalnızca tek bir özelliği yerine nesnenin tamamına bağlanmak istediğinizde de yararlıdır. Örneğin, kaynak nesneniz String türündeyse, dizenin kendisine bağlanmak isteyebilirsiniz. Bir diğer yaygın senaryo, bir öğeyi çeşitli özelliklere sahip bir nesneye bağlamak istemenizdir.

Verilerin ilişkili hedef özelliğinize yönelik anlamlı olması için özel mantık uygulamanız gerekebilir. Varsayılan tür dönüştürmesi yoksa, özel mantık özel dönüştürücü biçiminde olabilir. Dönüştürücüler hakkında bilgi için, bkz. Veri dönüştürme.

Binding ve BindingExpression

Veri bağlamanın diğer özelliklerine ve kullanımlarına girmeden önce BindingExpression sınıfını tanıtmak yararlı olur. Önceki bölümlerde gördüğünüz gibi, Binding sınıfı bağlama bildirimi için üst düzey sınıftır; bağlamanın özelliklerini belirtmenize olanak sağlayan birçok özellik sağlar. İlgili sınıf, BindingExpression, kaynak ile hedef arasındaki bağlantıyı koruyan temel nesnedir. Bağlama, çeşitli bağlama ifadeleri arasında paylaşılabilen tüm bilgileri içerir. BindingExpression, paylaşılamayan bir örnek ifadesidir ve Binding için tüm örnek bilgilerini içerir.

myDataObject öğesinin, MyData sınıfının bir örneği, myBinding öğesinin, kaynak Binding nesnesi ve MyData öğesinin, ColorName adlı bir dize özelliğini içeren tanımlı bir sınıf olduğu aşağıdaki örneği düşünün. Bu örnek, TextBlock öğesinin bir örneği olan myText metin içeriğini ColorName öğesine bağlar.

// Make a new source
var myDataObject = new MyData();
var myBinding = new Binding("ColorName")
{
    Source = myDataObject
};

// Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding);
' Make a New source
Dim myDataObject As New MyData
Dim myBinding As New Binding("ColorName")
myBinding.Source = myDataObject

' Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding)

Diğer bağlamaları oluşturmak için aynı myBinding nesnesini kullanabilirsiniz. Örneğin, onay kutusunun metin içeriğini ColorName öğesine bağlamak için myBindingnesnesini kullanabilirsiniz. Bu senaryoda, myBinding nesnesini paylaşan iki BindingExpression örneği olacaktır.

Veriye bağlı bir nesnede GetBindingExpression çağrılarak bir BindingExpression nesnesi döndürülür. Aşağıdaki makalelerde BindingExpression sınıfının bazı kullanımları gösterilmektedir:

Veri dönüştürme

Bağlama oluştur bölümünde, Background özelliği "Kırmızı" değerine sahip bir dize özelliğine bağlı olduğundan düğme kırmızıdır. Dize değerini Brush değerine dönüştürmek için Brush türünde bir tür dönüştürücüsü bulunduğundan, bu dize değeri çalışır.

Bağlama oluşturma bölümündeki şekle bu bilgiler eklendiğinde şöyle görünür.

Diagram that shows the data binding Default property.

Ancak, bağlama kaynak nesnenizin dize türünde bir özelliği yerine Color türünde bir Color özelliği varsa ne olur? Bu durumda, bağlamanın çalışması için önce Color özellik değerini Background özelliğinin kabul ettiği bir değere dönüştürmeniz gerekir. Aşağıdaki örnekte olduğu gibi IValueConverter arabirimini uygulayarak özel bir dönüştürücü oluşturmanız gerekir.

[ValueConversion(typeof(Color), typeof(SolidColorBrush))]
public class ColorBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Color color = (Color)value;
        return new SolidColorBrush(color);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}
<ValueConversion(GetType(Color), GetType(SolidColorBrush))>
Public Class ColorBrushConverter
    Implements IValueConverter
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert
        Dim color As Color = CType(value, Color)
        Return New SolidColorBrush(color)
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
        Return Nothing
    End Function
End Class

Daha fazla bilgi edinmek için bkz. IValueConverter.

Artık varsayılan dönüştürme yerine özel dönüştürücü kullanılır ve diyagramımız şöyle görünür.

Diagram that shows the data binding custom converter.

Yinelemek gerekirse, varsayılan dönüştürmeler, bağlı olduğu türdeki tür dönüştürücüleri nedeniyle kullanılabilir. Bu davranış, hedefte hangi tür dönüştürücülerin kullanılabilir olduğuna bağlıdır. Şüpheniz varsa kendi, dönüştürücünüzü oluşturun.

Aşağıda, veri dönüştürücüsü uygulamanın mantıklı olduğu bazı tipik senaryolar verilmiştir:

  • Verileriniz, kültüre bağlı olarak farklı şekilde görüntülenmelidir. Örneğin, belirli bir kültürde kullanılan kuralları temel alan bir para birimi dönüştürücüsü veya takvim tarih/saat dönüştürücüsü uygulamak isteyebilirsiniz.

  • Kullanılan verilerin bir özelliğin metin değerini değiştirmesi zorunlu değildir, bunun yerine görüntünün kaynağı veya görüntü metninin rengi veya stili gibi başka bir değeri değiştirmeye yöneliktir. Dönüştürücüler, bir metin alanını tablo hücresinin Arka plan özelliğine bağlama gibi uygun görünmeyecek bir özelliğin bağlamasını dönüştürerek bu örnekte kullanılabilir.

  • Birden fazla denetim veya denetimlerin birden çok özelliği aynı verilere bağlıdır. Bu durumda birincil bağlama yalnızca metni görüntüleyebilirken, diğer bağlamalar belirli görüntüleme sorunlarını işler ancak yine de kaynak bilgilerle aynı bağlamayı kullanır.

  • Hedef özelliği, MultiBinding olarak adlandırılan bağlama koleksiyonuna sahiptir. MultiBinding için, bağlamaların değerlerinden son bir değer oluşturmak için özel bir IMultiValueConverter kullanırsınız. Örneğin renk, kırmızı, mavi ve yeşil değerlerden hesaplanabilir ve bunlar aynı veya farklı bağlama kaynak nesnelerinden değerler olabilir. Örnekler ve bilgiler için, bkz. MultiBinding.

Koleksiyonlara bağlama

Bağlama kaynak nesnesi, özellikleri veri içeren tek bir nesne olarak veya genellikle birlikte gruplandırılmış çok biçimli nesnelerin veri koleksiyonu olarak (örneğin, bir veritabanına yapılan sorgunun sonucu) kabul edilebilir. Şu ana kadar yalnızca tek nesnelere bağlamayı ele aldık. Ancak, veri toplamaya bağlama yaygın bir senaryodur. Örneğin, yaygın bir senaryo, Veri bağlama nedir? bölümünde gösterilen uygulamada olduğu gibi bir veri koleksiyonunu görüntülemek için ListBox, ListView veya TreeView gibi bir ItemsControl kullanmaktır.

Neyse ki temel diyagramımız hala geçerlidir. Bir ItemsControl öğesini bir koleksiyona bağlanacaksanız diyagram şöyle görünür.

Diagram that shows the data binding ItemsControl object.

Bu diyagramda gösterildiği gibi, bir ItemsControl öğesini bir koleksiyon nesnesine bağlamak için kullanılacak özellik ItemsControl.ItemsSource özelliğidir. ItemsSource öğesini ItemsControl öğesinin içeriği olarak düşünebilirsiniz. ItemsSource özelliği varsayılan olarak OneWay bağlamayı desteklediğinden bağlama OneWay olur.

Koleksiyonları uygulama

IEnumerable arabirimini uygulayan herhangi bir koleksiyon üzerinde numaralandırabilirsiniz. Ancak, koleksiyondaki eklemelerin veya silmelerin kullanıcı arabirimini otomatik olarak güncelleştirmesi için dinamik bağlamalar ayarlamak üzere koleksiyonun INotifyCollectionChanged arabirimini uygulaması gerekir. Bu arabirim, temel alınan koleksiyon değiştiğinde tetiklenmesi gereken bir olayı kullanıma sunar.

WPF, INotifyCollectionChanged arabirimini kullanıma sunan bir veri koleksiyonunun yerleşik uygulaması olan ObservableCollection<T> sınıfını sağlar. Veri değerlerinin kaynak nesnelerden hedeflere aktarılmasını tam olarak desteklemek için, koleksiyonunuzdaki bağlanabilir özellikleri destekleyen her nesnenin de INotifyPropertyChanged arabirimini uygulaması gerekir. Daha fazla bilgi için, bkz. Bağlama kaynaklarına genel bakış.

Kendi koleksiyonunuzu uygulamadan önce, List<T>, Collection<T> ve BindingList<T> gibi mevcut koleksiyon sınıflarından birini veya ObservableCollection<T> kullanmayı göz önünde bulundurun. Gelişmiş bir senaryonuz varsa ve kendi koleksiyonunuzu uygulamak istiyorsanız, dizin tarafından tek tek erişilebilen ve böylece en iyi performansı sağlayan genel olmayan bir nesne koleksiyonu sağlayan IList öğesini kullanmayı göz önünde bulundurun.

Koleksiyon görünümleri

ItemsControl bir veri koleksiyonuna bağlandıktan sonra verileri sıralamak, filtrelemek veya gruplandırmak isteyebilirsiniz. Bunu yapmak için, ICollectionView arabirimini uygulayan sınıflar olan koleksiyon görünümlerini kullanırsınız.

Koleksiyon görünümleri nelerdir?

Koleksiyon görünümü, temel alınan kaynak koleksiyonun kendisini değiştirmek zorunda kalmadan sıralama, filtre ve grup sorgularına dayalı olarak kaynak koleksiyonda gezinmenize ve görüntülemenize olanak tanıyan bir bağlama kaynak koleksiyonunun üstündeki bir katmandır. Koleksiyon görünümü ayrıca, koleksiyondaki geçerli öğeye yönelik bir işaretçi tutar. Kaynak koleksiyon INotifyCollectionChanged arabirimini uygularsa, CollectionChanged olayı tarafından tetiklenen değişiklikler görünümlere yayılır.

Görünümler temel alınan kaynak koleksiyonları değiştirmediğinden, her kaynak koleksiyonun kendisiyle ilişkilendirilmiş birden çok görünümü olabilir. Örneğin, Görev nesneleri koleksiyonunuz olabilir. Görünümleri kullanarak aynı verileri farklı şekillerde görüntüleyebilirsiniz. Örneğin, sayfanızın sol tarafında görevleri önceliğe göre sıralanmış ve sağ tarafta da alana göre gruplandırılmış olarak göstermek isteyebilirsiniz.

Görünüm oluşturma

Görünüm oluşturmanın ve kullanmanın bir yolu, görünüm nesnesini doğrudan örneklemek ve ardından bağlama kaynağı olarak kullanmaktır. Örneğin, Veri bağlama nedir bölümünde gösterilen Veri bağlama tanıtım uygulamasını göz önünde bulundurun. Uygulama, ListBox öğesinin doğrudan veri toplama yerine veri toplama üzerindeki bir görünüme bağlanacağı şekilde uygulanır. Aşağıdaki örnek, Veri bağlama tanıtım uygulamasından ayıklanır. CollectionViewSource sınıfı, CollectionView öğesinden devralan bir sınıfın XAML ara sunucusudur. Bu özel örnekte, görünümün Source öğesi geçerli uygulama nesnesinin AuctionItems koleksiyonuna (ObservableCollection<T> türünde) bağlıdır.

<Window.Resources>
    <CollectionViewSource 
      Source="{Binding Source={x:Static Application.Current}, Path=AuctionItems}"   
      x:Key="listingDataView" />
</Window.Resources>

Kaynak listingDataView daha sonra ListBox gibi uygulamadaki öğeler için bağlama kaynağı görevi görür.

<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8" 
         ItemsSource="{Binding Source={StaticResource listingDataView}}" />

Aynı koleksiyon için başka bir görünüm oluşturmak üzere başka bir CollectionViewSource örneği oluşturabilir ve farklı bir x:Key adı verebilirsiniz.

Aşağıdaki tabloda, hangi görünüm veri türlerinin varsayılan koleksiyon görünümü olarak veya kaynak koleksiyon türüne göre CollectionViewSource tarafından oluşturulduğu gösterilmektedir.

Kaynak koleksiyon türü Koleksiyon görünüm türü Notlar
IEnumerable CollectionView öğesini temel alan iç tür Öğeler gruplandırılamıyor.
IList ListCollectionView En hızlı.
IBindingList BindingListCollectionView

Varsayılan görünümü kullanma

Koleksiyon görünümünü bağlama kaynağı olarak belirtmek, koleksiyon görünümü oluşturmanın ve kullanmanın bir yoludur. WPF ayrıca, bağlama kaynağı olarak kullanılan her koleksiyon için bir varsayılan koleksiyon görünümü oluşturur. Doğrudan bir koleksiyona bağlarsanız, WPF varsayılan görünümüne bağlanır. Bu varsayılan görünüm, aynı koleksiyondaki tüm bağlamalar tarafından paylaşıldığından, bir bağlı denetim veya kod tarafından varsayılan görünümde yapılan bir değişiklik (sıralama veya daha sonra ele alınan geçerli öğe işaretçisinde değişiklik gibi) aynı koleksiyondaki diğer tüm bağlamalara yansıtılır.

Varsayılan görünümü almak için GetDefaultView yöntemini kullanırsınız. Örnek için, bkz. Veri koleksiyonunun varsayılan görünümünü alma (.NET Framework).

ADO.NET DataTable tabloları olan koleksiyon görünümleri

Performansı artırmak amacıyla, ADO.NET DataTable veya DataView nesneleri için koleksiyon görünümleri sıralamayı ve filtrelemeyi DataView öğesine devreder ve bu da sıralama ile filtrelemenin veri kaynağının tüm koleksiyon görünümlerine paylaşılmasına neden olur. Her koleksiyon görünümünün bağımsız olarak sıralamasını ve filtrelemesini sağlamak için, her koleksiyon görünümünü kendi DataView nesnesiyle başlatın.

Sıralama

Daha önce belirtildiği gibi, görünümler bir koleksiyona sıralama düzeni uygulayabilir. Temel alınan koleksiyonda mevcut olduğundan, verileriniz, ilgili, doğal bir düzene sahip olabilir veya olmayabilir. Koleksiyon üzerindeki görünüm, sağladığınız karşılaştırma ölçütlerine göre bir sipariş uygulamanıza veya varsayılan siparişi değiştirmenize olanak tanır. Verilerin istemci tabanlı bir görünümü olduğundan, kullanıcının sütuna karşılık gelen değere göre tablosal veri sütunlarını sıralamak istemesi yaygın bir senaryodur. Görünümleri kullanarak, bu kullanıcı temelli sıralama, temel koleksiyonda herhangi bir değişiklik yapmadan veya koleksiyon içeriği için yeniden sorgulama yapmak zorunda kalmadan yeniden uygulanabilir. Bir örnek için, bkz. Üst bilgi tıklatıldığında GridView sütununu sıralama (.NET Framework).

Aşağıdaki örnek, Veri bağlama nedir? bölümünde uygulama kullanıcı arabiriminin "Kategoriye ve tarihe göre sırala" CheckBox sıralama mantığını gösterir.

private void AddSortCheckBox_Checked(object sender, RoutedEventArgs e)
{
    // Sort the items first by Category and then by StartDate
    listingDataView.SortDescriptions.Add(new SortDescription("Category", ListSortDirection.Ascending));
    listingDataView.SortDescriptions.Add(new SortDescription("StartDate", ListSortDirection.Ascending));
}
Private Sub AddSortCheckBox_Checked(sender As Object, e As RoutedEventArgs)
    ' Sort the items first by Category And then by StartDate
    listingDataView.SortDescriptions.Add(New SortDescription("Category", ListSortDirection.Ascending))
    listingDataView.SortDescriptions.Add(New SortDescription("StartDate", ListSortDirection.Ascending))
End Sub

Filtreleme

Görünümler bir koleksiyona filtre uygulayarak görünümün tam koleksiyonun yalnızca belirli bir alt kümesini göstermesine de neden olabilir. Verilerdeki bir koşula göre filtreleyebilirsiniz. Örneğin, Veri bağlama nedir? bölümünde uygulama tarafından yapıldığı gibi, "Yalnızca pazarlıkları göster" CheckBox 25 ABD doları veya daha fazla maliyete sahip öğeleri filtreleme mantığı içerir. Bu CheckBox seçildiğinde ShowOnlyBargainsFilter öğesini Filter olay işleyicisi olarak ayarlamak için aşağıdaki kod yürütülür.

private void AddFilteringCheckBox_Checked(object sender, RoutedEventArgs e)
{
    if (((CheckBox)sender).IsChecked == true)
        listingDataView.Filter += ListingDataView_Filter;
    else
        listingDataView.Filter -= ListingDataView_Filter;
}
Private Sub AddFilteringCheckBox_Checked(sender As Object, e As RoutedEventArgs)
    Dim checkBox = DirectCast(sender, CheckBox)

    If checkBox.IsChecked = True Then
        AddHandler listingDataView.Filter, AddressOf ListingDataView_Filter
    Else
        RemoveHandler listingDataView.Filter, AddressOf ListingDataView_Filter
    End If
End Sub

ShowOnlyBargainsFilter olay işleyicisi aşağıdaki uygulamaya sahiptir.

private void ListingDataView_Filter(object sender, FilterEventArgs e)
{
    // Start with everything excluded
    e.Accepted = false;

    // Only inlcude items with a price less than 25
    if (e.Item is AuctionItem product && product.CurrentPrice < 25)
        e.Accepted = true;
}
Private Sub ListingDataView_Filter(sender As Object, e As FilterEventArgs)

    ' Start with everything excluded
    e.Accepted = False

    Dim product As AuctionItem = TryCast(e.Item, AuctionItem)

    If product IsNot Nothing Then

        ' Only include products with prices lower than 25
        If product.CurrentPrice < 25 Then e.Accepted = True

    End If

End Sub

CollectionViewSource yerine doğrudan CollectionView sınıflarından birini kullanıyorsanız, geri çağırma belirtmek için Filter özelliğini kullanırsınız. Örnek için, bkz. Görünümdeki Verileri Filtreleme (.NET Framework).

Gruplama

Bir IEnumerable koleksiyonunu görüntüleyen iç sınıf dışında, tüm koleksiyon görünümleri gruplandırma desteği sağlar ve bu da kullanıcının koleksiyon görünümündeki koleksiyonu mantıksal gruplar halinde bölümlemesini sağlar. Gruplar, kullanıcının gruplar listesini sağladığı açık veya örtük olabilir; burada gruplar verilere bağlı olarak dinamik olarak oluşturulur.

Aşağıdaki örnekte, "Kategoriye göre gruplandır" CheckBox mantığı gösterilmektedir.

// This groups the items in the view by the property "Category"
var groupDescription = new PropertyGroupDescription();
groupDescription.PropertyName = "Category";
listingDataView.GroupDescriptions.Add(groupDescription);
' This groups the items in the view by the property "Category"
Dim groupDescription = New PropertyGroupDescription()
groupDescription.PropertyName = "Category"
listingDataView.GroupDescriptions.Add(groupDescription)

Başka bir gruplandırma örneği için, bkz. GridView Uygulayan ListView'da Öğeleri Gruplandırma (.NET Framework).

Geçerli öğe işaretçileri

Görünümler, geçerli bir öğeyi de destekler. Koleksiyon görünümünde nesneler arasında gezinebilirsiniz. Gezinirken, koleksiyondaki belirli bir konumda bulunan nesneyi almanıza olanak tanıyan bir öğe işaretçisini taşırsınız. Örnek için, bkz. CollectionView (.NET Framework) verilerindeki nesneler arasında gezinme.

WPF, bir koleksiyona yalnızca bir görünüm (belirttiğiniz bir görünüm veya koleksiyonun varsayılan görünümü) kullanarak bağlandığından, koleksiyonlara yapılan tüm bağlamaların geçerli bir öğe işaretçisi vardır. Görünüme bağlanırken, bir Path değerindeki eğik çizgi ("/") karakteri görünümün geçerli öğesini belirler. Aşağıdaki örnekte veri bağlamı bir koleksiyon görünümüdür. İlk satır koleksiyona bağlanır. İkinci satır koleksiyondaki geçerli öğeye bağlanır. Üçüncü satır, koleksiyondaki geçerli öğenin Description özelliğine bağlanır.

<Button Content="{Binding }" />
<Button Content="{Binding Path=/}" />
<Button Content="{Binding Path=/Description}" />

Eğik çizgi ve özellik söz dizimi de bir koleksiyon hiyerarşisi arasında geçiş yapmak için yığılabilir. Aşağıdaki örnek, kaynak koleksiyonun geçerli öğesinin bir özelliği olan Offices adlı koleksiyonun geçerli öğesine bağlanır.

<Button Content="{Binding /Offices/}" />

Geçerli öğe işaretçisi, koleksiyona uygulanan herhangi bir sıralama veya filtrelemeden etkilenebilir. Sıralama, seçilen son öğedeki geçerli öğe işaretçisini korur, ancak koleksiyon görünümü artık bunun çevresinde yeniden yapılandırılır. (Seçili öğe daha önce listenin başında olabilir, ancak şimdi seçili öğe ortada bir yerde olabilir.) Filtreleme, seçim filtrelemeden sonra görünümde kalırsa seçili öğeyi korur. Aksi takdirde, geçerli öğe işaretçisi filtrelenmiş koleksiyon görünümünün ilk öğesine ayarlanır.

Ana ayrıntı bağlama senaryosu

Geçerli öğeye ilişkin ifade yalnızca koleksiyondaki öğelerin gezintisi için değil, aynı zamanda ana ayrıntı bağlama senaryosu için de yararlıdır. Veri bağlama nedir? bölümündeki uygulama kullanıcı arabirimini yeniden göz önünde bulundurun. Bu uygulamada, ListBox içindeki seçim ContentControl içinde gösterilen içeriği belirler. Başka bir deyişle, bir ListBox öğesi seçildiğinde, ContentControl, seçilen öğenin ayrıntılarını gösterir.

Aynı görünüme bağlı iki veya daha fazla denetime sahip olarak ana ayrıntı senaryosunu uygulayabilirsiniz. Veri bağlama tanıtımından alınan aşağıdaki örnek, ve öğesinin işaretlemesini ListBox gösterir ve ContentControl veri bağlama nedir bölümünde uygulama kullanıcı arabiriminde görürsünüz.

<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8" 
         ItemsSource="{Binding Source={StaticResource listingDataView}}" />
<ContentControl Name="Detail" Grid.Row="3" Grid.ColumnSpan="3"
                Content="{Binding Source={StaticResource listingDataView}}"
                ContentTemplate="{StaticResource detailsProductListingTemplate}" 
                Margin="9,0,0,0"/>

Her iki denetimin de aynı kaynak olan listingDataView statik kaynağına bağlı olduğuna dikkat edin (görünüm oluşturma bölümündeki bu kaynağın tanımına bakın). Tekil bir nesne (bu örnekteki ContentControl) bir koleksiyon görünümüne bağlı olduğunda görünümün CurrentItem öğesi otomatik olarak bağlandığı için bu bağlama çalışır. CollectionViewSource nesneleri para birimini ve seçimi otomatik olarak eşitler. Liste denetiminiz bu örnekte olduğu gibi bir CollectionViewSource nesnesine bağlı değilse, bunun çalışması için IsSynchronizedWithCurrentItem özelliğini true olarak ayarlamanız gerekir.

Diğer örnekler için, bkz. Koleksiyona bağlama ve seçime göre bilgi görüntüleme (.NET Framework) ve Hiyerarşik verilerle ana ayrıntı desenini kullanma (.NET Framework).

Yukarıdaki örnekte bir şablon kullanıldığı fark etmiş olabilirsiniz. Aslında, şablonlar (ContentControl tarafından açıkça kullanılan ve ListBox tarafından örtük olarak kullanılan) kullanılmadan veriler istediğimiz gibi görüntülenmez. Bir sonraki bölümde veri şablonu oluşturmaya geçeceğiz.

Veri şablonu oluşturma

Veri şablonları kullanılmadan, Veri bağlama örneği bölümündeki uygulama kullanıcı arabirimimiz aşağıdaki gibi görünür:

Data Binding Demo without Data Templates

Önceki bölümdeki örnekte gösterildiği gibi, hem ListBox denetimi hem de ContentControl, AuctionItem nesnesinin koleksiyon nesnesinin tamamına (veya daha açıkçası koleksiyon nesnesi üzerindeki görünüme) bağlıdır. Veri koleksiyonunun nasıl görüntüleneceğine ilişkin belirli yönergeler olmadan, ListBox, temel koleksiyondaki her nesnenin dize gösterimini görüntüler ve ContentControl, bağlı olduğu nesnenin dize gösterimini görüntüler.

Bu sorunu çözmek için uygulama DataTemplates öğesini tanımlar. Önceki bölümdeki örnekte gösterildiği gibi, ContentControl, açık şekilde detailsProductListingTemplate veri şablonunu kullanır. ListBox denetimi, koleksiyonda AuctionItem nesnelerini görüntülerken örtük olarak aşağıdaki veri şablonunu kullanır.

<DataTemplate DataType="{x:Type src:AuctionItem}">
    <Border BorderThickness="1" BorderBrush="Gray"
            Padding="7" Name="border" Margin="3" Width="500">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20"/>
                <ColumnDefinition Width="86"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <Polygon Grid.Row="0" Grid.Column="0" Grid.RowSpan="4"
                     Fill="Yellow" Stroke="Black" StrokeThickness="1"
                     StrokeLineJoin="Round" Width="20" Height="20"
                     Stretch="Fill"
                     Points="9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7"
                     Visibility="Hidden" Name="star"/>

            <TextBlock Grid.Row="0" Grid.Column="1" Margin="0,0,8,0"
                       Name="descriptionTitle"
                       Style="{StaticResource smallTitleStyle}">Description:</TextBlock>
            
            <TextBlock Name="DescriptionDTDataType" Grid.Row="0" Grid.Column="2"
                       Text="{Binding Path=Description}"
                       Style="{StaticResource textStyleTextBlock}"/>

            <TextBlock Grid.Row="1" Grid.Column="1" Margin="0,0,8,0"
                       Name="currentPriceTitle"
                       Style="{StaticResource smallTitleStyle}">Current Price:</TextBlock>
            
            <StackPanel Grid.Row="1" Grid.Column="2" Orientation="Horizontal">
                <TextBlock Text="$" Style="{StaticResource textStyleTextBlock}"/>
                <TextBlock Name="CurrentPriceDTDataType"
                           Text="{Binding Path=CurrentPrice}" 
                           Style="{StaticResource textStyleTextBlock}"/>
            </StackPanel>
        </Grid>
    </Border>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=SpecialFeatures}">
            <DataTrigger.Value>
                <src:SpecialFeatures>Color</src:SpecialFeatures>
            </DataTrigger.Value>
            <DataTrigger.Setters>
                <Setter Property="BorderBrush" Value="DodgerBlue" TargetName="border" />
                <Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
                <Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
                <Setter Property="BorderThickness" Value="3" TargetName="border" />
                <Setter Property="Padding" Value="5" TargetName="border" />
            </DataTrigger.Setters>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=SpecialFeatures}">
            <DataTrigger.Value>
                <src:SpecialFeatures>Highlight</src:SpecialFeatures>
            </DataTrigger.Value>
            <Setter Property="BorderBrush" Value="Orange" TargetName="border" />
            <Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
            <Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
            <Setter Property="Visibility" Value="Visible" TargetName="star" />
            <Setter Property="BorderThickness" Value="3" TargetName="border" />
            <Setter Property="Padding" Value="5" TargetName="border" />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

Bu iki DataTemplates öğesinin kullanılmasıyla elde edilen kullanıcı arabirimi, Veri bağlama nedir? bölümünde gösterilen kullanıcı arabirimidir. Bu ekran görüntüsünden görebileceğiniz gibi DataTemplates, denetimlerinize veri yerleştirmenize izin vermenin yanı sıra verileriniz için cazip görseller tanımlamanızı sağlar. Örneğin, yukarıdaki DataTemplate için DataTrigger öğeleri kullanılır, böylece HighLight öğesinin SpecialFeatures değerine sahip AuctionItem nesneleri, turuncu bir kenarlık ve bir yıldızla görüntülenecektir.

Veri şablonları hakkında daha fazla bilgi için, bkz. Veri şablonu oluşturmaya genel bakış (.NET Framework).

Veri doğrulaması

Kullanıcı girişini alan çoğu uygulamanın, kullanıcının beklenen bilgileri girdiğinden emin olmak için doğrulama mantığına sahip olması gerekir. Doğrulama denetimleri tür, aralık, biçim veya uygulamaya özgü diğer gereksinimleri temel alabilir. Bu bölümde, veri doğrulamanın WPF'de nasıl çalıştığı açıklanmıştır.

Doğrulama kurallarını bağlamayla ilişkilendirme

WPF veri bağlama modeli, ValidationRules öğesini Binding nesnenizle ilişkilendirmenize olanak tanır. Örneğin, aşağıdaki örnek StartPrice adlı bir özelliğe bir TextBox bağlar ve Binding.ValidationRules özelliğine bir ExceptionValidationRule nesnesi ekler.

<TextBox Name="StartPriceEntryForm" Grid.Row="2"
         Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5" Grid.ColumnSpan="2">
    <TextBox.Text>
        <Binding Path="StartPrice" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <ExceptionValidationRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

ValidationRule nesnesi, bir özelliğin değerinin geçerli olup olmadığını denetler. WPF'nin iki tür yerleşik ValidationRule nesnesi vardır:

Ayrıca ValidationRule sınıfından türeterek ve Validate yöntemini uygulayarak kendi doğrulama kuralınızı oluşturabilirsiniz. Aşağıdaki örnekte, Veri bağlama nedir? bölümündeki Ürün Listesi Ekle "Başlangıç Tarihi" TextBox tarafından kullanılan kural gösterilmektedir.

public class FutureDateRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        // Test if date is valid
        if (DateTime.TryParse(value.ToString(), out DateTime date))
        {
            // Date is not in the future, fail
            if (DateTime.Now > date)
                return new ValidationResult(false, "Please enter a date in the future.");
        }
        else
        {
            // Date is not a valid date, fail
            return new ValidationResult(false, "Value is not a valid date.");
        }

        // Date is valid and in the future, pass
        return ValidationResult.ValidResult;
    }
}
Public Class FutureDateRule
    Inherits ValidationRule

    Public Overrides Function Validate(value As Object, cultureInfo As CultureInfo) As ValidationResult

        Dim inputDate As Date

        ' Test if date is valid
        If Date.TryParse(value.ToString, inputDate) Then

            ' Date is not in the future, fail
            If Date.Now > inputDate Then
                Return New ValidationResult(False, "Please enter a date in the future.")
            End If

        Else
            ' // Date Is Not a valid date, fail
            Return New ValidationResult(False, "Value is not a valid date.")
        End If

        ' Date is valid and in the future, pass
        Return ValidationResult.ValidResult

    End Function

End Class

StartDateEntryFormTextBox, aşağıdaki örnekte gösterildiği gibi bu FutureDateRule kuralını kullanır.

<TextBox Name="StartDateEntryForm" Grid.Row="3"
         Validation.ErrorTemplate="{StaticResource validationTemplate}" 
         Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5" Grid.ColumnSpan="2">
    <TextBox.Text>
        <Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged" 
                 Converter="{StaticResource dateConverter}" >
            <Binding.ValidationRules>
                <src:FutureDateRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

UpdateSourceTrigger değeri PropertyChanged olduğundan, bağlama altyapısı her tuş vuruşunda kaynak değeri güncelleştirir. Bu, her tuş vuruşunda ValidationRules koleksiyonundaki tüm kuralları da denetlediği anlamına gelir. Bunu Doğrulama İşlemi bölümünde daha ayrıntılı olarak ele alıyoruz.

Görsel geri bildirim sağlama

Kullanıcı geçersiz bir değer girerse, uygulama kullanıcı arabiriminde hata hakkında geri bildirimde bulunmak isteyebilirsiniz. Bu tür bir geri bildirim sağlamanın bir yolu, Validation.ErrorTemplate ekli özelliği özel ControlTemplate olarak ayarlamaktır. Önceki alt bölümde gösterildiği gibi StartDateEntryFormTextBox, validationTemplate adlı bir ErrorTemplate kullanır. Aşağıdaki örnek, validationTemplate tanımını gösterir.

<ControlTemplate x:Key="validationTemplate">
    <DockPanel>
        <TextBlock Foreground="Red" FontSize="20">!</TextBlock>
        <AdornedElementPlaceholder/>
    </DockPanel>
</ControlTemplate>

AdornedElementPlaceholder öğesi, donatılan denetimin nereye yerleştirilmesi gerektiğini belirtir.

Ayrıca, hata iletisini görüntülemek için bir ToolTip de kullanabilirsiniz. Hem StartDateEntryForm hem de StartPriceEntryFormTextBoxes, hata iletisini görüntüleyen bir ToolTip oluşturan textStyleTextBox stilini kullanır. Aşağıdaki örnekte textStyleTextBox stilinin tanımı gösterilmektedir. Bağlı öğenin özellikleri üzerindeki bağlamalardan biri veya daha fazlası hatalı olduğunda, eklenen Validation.HasError özelliği true olur.

<Style x:Key="textStyleTextBox" TargetType="TextBox">
    <Setter Property="Foreground" Value="#333333" />
    <Setter Property="MaxLength" Value="40" />
    <Setter Property="Width" Value="392" />
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="true">
            <Setter Property="ToolTip" 
                    Value="{Binding (Validation.Errors).CurrentItem.ErrorContent, RelativeSource={RelativeSource Self}}" />
        </Trigger>
    </Style.Triggers>
</Style>

Özel ErrorTemplate ve ToolTip varken, bir doğrulama hatası olduğunda StartDateEntryFormTextBox aşağıdaki gibi görünür.

Data binding validation error for date

Binding öğenizin ilişkili doğrulama kuralları varsa ancak ilişkili denetimde bir ErrorTemplate belirtmezseniz, bir doğrulama hatası olduğunda kullanıcıları bilgilendirmek için varsayılan bir ErrorTemplate kullanılacaktır. Varsayılan ErrorTemplate, donatıcı katmanında kırmızı bir kenarlık tanımlayan bir denetim şablonudur. Varsayılan ErrorTemplate ve ToolTip varken, bir doğrulama hatası olduğunda StartPriceEntryFormTextBox kullanıcı arabirimi aşağıdaki gibi görünür.

Data binding validation error for price

İletişim kutusundaki tüm denetimleri doğrulamak üzere mantık sağlama örneği için İletişim kutularına genel bakış bölümündeki Özel İletişim Kutuları bölümüne bakın.

Doğrulama işlemi

Doğrulama, genellikle bir hedefin değeri bağlama kaynağı özelliğine aktarıldığında gerçekleşir. Bu aktarım TwoWay ve OneWayToSource bağlamalarında gerçekleşir. Yinelemek gerekirse, kaynak güncelleştirmenin nedeni, Kaynak güncellemelerini tetikleyenler bölümünde açıklandığı gibi, UpdateSourceTrigger özelliğinin değerine bağlıdır.

Aşağıdaki öğeler doğrulama işlemini açıklar. Bu işlem sırasında herhangi bir zamanda doğrulama hatası veya başka türde bir hata oluşursa işlem durdurulmuş olur:

  1. Bağlama altyapı, ValidationStep öğesi o Binding için RawProposedValue olarak ayarlanmış herhangi bir özel ValidationRule nesnesi olup olmadığını kontrol eder; bu durumda, bunlardan biri bir hatayla karşılaşana veya tümü geçene kadar her ValidationRule üzerinde Validate yöntemini çağırır.

  2. Bağlama altyapısı, varsa, dönüştürücüyü çağırır.

  3. Dönüştürücü başarılı olursa, ValidationStep öğesi o Binding için ConvertedProposedValue olarak ayarlanmış herhangi bir özel ValidationRule nesnesi olup olmadığını kontrol eder; bu durumda, ValidationStep öğesinin ConvertedProposedValue olarak ayarlı olduğu her ValidationRule üzerinde, biri bir hatayla karşılaşıncaya veya tümü geçene kadar Validate yöntemini çağırır.

  4. Bağlama altyapısı, kaynak özelliğini ayarlar.

  5. Bağlama altyapı, ValidationStep öğesi o Binding için UpdatedValue olarak ayarlanmış herhangi bir özel ValidationRule nesnesi olup olmadığını kontrol eder; bu durumda, bunlardan biri bir hatayla karşılaşana veya tümü geçene kadar, ValidationStep öğesinin UpdatedValue olarak ayarlı olduğu her ValidationRule üzerinde Validate yöntemini çağırır. Bir DataErrorValidationRule bir bağlamayla ilişkilendirilirse ve ValidationStep varsayılan olarak, UpdatedValue, ayarlanmışsa, bu noktada DataErrorValidationRule denetlenir. Bu noktada, ValidatesOnDataErrors öğesinin true olarak ayarlandığı herhangi bir bağlama kontrol edilir.

  6. Bağlama altyapı, ValidationStep öğesi o Binding için CommittedValue olarak ayarlanmış herhangi bir özel ValidationRule nesnesi olup olmadığını kontrol eder; bu durumda, bunlardan biri bir hatayla karşılaşana veya tümü geçene kadar, ValidationStep öğesinin CommittedValue olarak ayarlı olduğu her ValidationRule üzerinde Validate yöntemini çağırır.

Bir ValidationRule, bu işlem boyunca herhangi bir zamanda geçmezse, bağlama altyapısı bir ValidationError nesnesi oluşturur ve bunu ilişkili öğenin Validation.Errors koleksiyonuna ekler. Bağlama altyapısı herhangi bir adımda ValidationRule nesnelerini çalıştırmadan önce, bu adım sırasında ilişkili öğenin Validation.Errors ekli özelliğine eklenen tüm ValidationError öğelerini kaldırır. Örneğin, ValidationStep öğesi UpdatedValue olarak ayarlanmış bir ValidationRule başarısız olursa, doğrulama işlemi bir sonraki gerçekleştiğinde, bağlama altyapısı, ValidationStep öğesi UpdatedValue olarak ayarlanmış herhangi bir ValidationRule çağırmadan hemen önce bu ValidationError öğesini kaldırır.

Validation.Errors boş olmadığında, öğenin ekli Validation.HasError özelliği true olarak ayarlanır. Ayrıca, Binding öğesinin NotifyOnValidationError özelliği true olarak ayarlanırsa, bağlama altyapısı öğesinde ekli Validation.Error olayını tetikler.

Ayrıca her iki yönde de geçerli bir değer aktarımının (hedefe hedef veya hedefe kaynak) ekli Validation.Errors özelliğini temizlediğini unutmayın.

Bağlamanın kendisiyle ilişkilendirilmiş bir ExceptionValidationRule varsa veya ValidatesOnExceptions özelliği true olarak ayarlandıysa ve bağlama altyapısı kaynağı ayarlarken bir özel durum oluşturulduysa, bağlama altyapısı bir UpdateSourceExceptionFilter olup olmadığını denetler. Özel durumları işlemek için özel bir işleyici sağlamak üzere UpdateSourceExceptionFilter geri çağırmayı kullanabilirsiniz. Binding üzerinde bir UpdateSourceExceptionFilter belirtilmezse, bağlama altyapısı özel durum içeren bir ValidationError oluşturur ve bunu ilişkili öğenin Validation.Errors koleksiyonuna ekler.

Hata ayıklama mekanizması

Belirli bir bağlamanın durumu hakkında bilgi almak için bağlamayla ilgili bir nesnede ekli PresentationTraceSources.TraceLevel özelliğini ayarlayabilirsiniz.

Ayrıca bkz.