Aracılığıyla paylaş


Windows veri bağlamaya genel bakış

WinUI uygulamalarında veri bağlama, denetimleri veri kaynaklarına verimli bir şekilde bağlamanızı sağlar. Denetimi tek bir öğeye veya öğe koleksiyonuna bağlamayı, öğe işlemeyi denetlemeyi, ayrıntı görünümlerini uygulamayı ve verileri görüntüleme için biçimlendirmeyi öğrenin. Daha fazla ayrıntı için bkz. Ayrıntılı veri bağlama.

Önkoşullar

Bu konu başlığında, Windows Uygulama SDK'sı ile temel bir WinUI uygulaması oluşturmayı bildiğiniz varsayılır. İlk WinUI uygulamanızı oluşturma yönergeleri için bkz. WinUI uygulaması oluşturma.

Projeyi oluşturma

Yeni bir WinUI Boş Uygulaması, Paketlenmiş C# projesi oluşturun. Buna "Hızlı Başlangıç" adını verin.

Tek bir öğeye bağlama

Her bağlama bir bağlama hedef ve bir bağlama kaynağından oluşur. Genellikle, hedef bir denetimin veya başka bir ui öğesinin özelliğidir ve kaynak bir sınıf örneğinin (veri modeli veya görünüm modeli) özelliğidir. Bu örnekte bir denetimin tek bir öğeye nasıl bağlanacağınız gösterilmektedir. Hedef, Text'in TextBlock özelliğidir. Kaynak, bir ses kaydını temsil eden Recording adlı basit bir sınıfın örneğidir. Önce sınıfa bakalım.

Projenize yeni bir sınıf ekleyin ve sınıfı Recordingolarak adlandırın.

namespace Quickstart
{
    public class Recording
    {
        public string ArtistName { get; set; }
        public string CompositionName { get; set; }
        public DateTime ReleaseDateTime { get; set; }
        public Recording()
        {
            ArtistName = "Wolfgang Amadeus Mozart";
            CompositionName = "Andante in C for Piano";
            ReleaseDateTime = new DateTime(1761, 1, 1);
        }
        public string OneLineSummary
        {
            get
            {
                return $"{CompositionName} by {ArtistName}, released: "
                    + ReleaseDateTime.ToString("d");
            }
        }
    }
    public class RecordingViewModel
    {
        private Recording defaultRecording = new();
        public Recording DefaultRecording { get { return defaultRecording; } }
    }
}

Ardından, işaretleme pencerenizi temsil eden sınıftan bağlama kaynak sınıfını kullanıma sunun. RecordingViewModel türüne sahip bir özellik ekleyin.

namespace Quickstart
{
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
        }
        public RecordingViewModel ViewModel{ get; } = new RecordingViewModel();
    }
}

Son adım, TextBlock özelliğine bir ViewModel.DefaultRecording.OneLineSummary bağlamaktır.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"/>
    </Grid>
</Window>

Sonuç şu şekildedir.

Tek bir öğeye bağlı TextBlock'un gösterildiği WinUI uygulamasının ekran görüntüsü.

Öğe koleksiyonuna bağlama

Yaygın bir senaryo, bir iş nesneleri koleksiyonuna bağlanmaktır. C# dilinde, veri bağlama için genel ObservableCollection<T> sınıfını kullanın. Öğeler eklendiğinde veya kaldırıldığında bağlamalara değişiklik bildirimi sağlayan INotifyCollectionChanged arabirimini uygular. Ancak, .NET 8 ve sonraki sürümlerde bilinen bir WinUI Yayın modu hatası nedeniyle, bazı senaryolarda, özellikle koleksiyonunuz statikse ve başlatma işleminden sonra değişmiyorsa Liste<T> kullanmanız gerekebilir. Koleksiyon çalışma zamanında değiştiğinde kullanıcı arabiriminizin güncelleştirilmesi gerekiyorsa kullanın ObservableCollection<T>. Yalnızca sabit bir öğe kümesi görüntülemeniz gerekiyorsa yeterlidir List<T> . Ayrıca, ilişkili denetimlerinizin koleksiyondaki nesnelerin özelliklerindeki değişikliklerle güncelleştirilmesini istiyorsanız, bu nesnelerin INotifyPropertyChanged uygulaması gerekir. Daha fazla bilgi için bkz. Ayrıntılı Veri Bağlama.

Not

List<T> kullanarak, koleksiyon değişiklikleri için değişiklik bildirimleri alamayabilirsiniz. Değişikliklere yanıt vermeniz gerekiyorsa kullanmayı ObservableCollection<T>göz önünde bulundurun. Bu örnekte koleksiyon değişikliklerine yanıt vermeniz gerekmez, bu nedenle List<T> yeterlidir.

Aşağıdaki örnek bir ListView'ı bir nesne koleksiyonuna Recording bağlar. İlk olarak, koleksiyonu görünüm modelinize ekleyin. Bu yeni üyeleri sınıfına RecordingViewModel ekleyin.

public class RecordingViewModel
{
    ...
    private List<Recording> recordings = new();
    public List<Recording> Recordings{ get{ return recordings; } }
    public RecordingViewModel()
    {
        recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
            CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
        recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
            CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
        recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
            CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
    }
}

Ardından özelliğineViewModel.Recordings bir ListView bağlayın.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <ListView ItemsSource="{x:Bind ViewModel.Recordings}"
                  HorizontalAlignment="Center"
                  VerticalAlignment="Center"/>
    </Grid>
</Window>

Henüz Recording sınıfı için bir veri şablonu sağlamadınız, bu nedenle UI çerçevesinin yapabileceği en iyi şey, ListView'daki her öğe için ToString çağırmaktır. varsayılan uygulaması ToString , tür adını döndürür.

Liste görünümü bağlama 1

Bu sorunu düzeltmek için ToString'i geçersiz kılarak değerini OneLineSummarydöndürebilir veya bir veri şablonu sağlayabilirsiniz. Veri şablonu seçeneği daha yaygın ve esnek bir çözümdür. İçerik denetiminin ContentTemplate özelliğini veya öğe denetiminin ItemTemplate özelliğini kullanarak bir veri şablonu belirtirsiniz. Sonuç çizimiyle birlikte için Recording bir veri şablonu tasarlamanın iki yolu aşağıdadır.

<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Recording">
            <TextBlock Text="{x:Bind OneLineSummary}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Liste görünümü bağlama 2

<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Recording">
            <StackPanel Orientation="Horizontal" Margin="6">
                <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                <StackPanel>
                    <TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
                    <TextBlock Text="{x:Bind CompositionName}"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Liste görünümü bağlama 3

XAML söz dizimi hakkında daha fazla bilgi için bkz. XAMLile kullanıcı arabirimi oluşturma . Denetim düzeni hakkında daha fazla bilgi için bkz. XAMLile düzenleri tanımlama .

Ayrıntılar görünümü ekleme

Recording öğelerinde nesnelerin tüm ayrıntılarını görüntülemeyi seçebilirsiniz. Ama bu yaklaşım çok fazla yer kaplar. Bunun yerine, öğeyi tanımlamak için yeterli miktarda veri gösterebilirsiniz. Kullanıcı bir seçim yaptığında, seçilen öğenin tüm ayrıntılarını ayrıntılar görünümü olarak bilinen ayrı bir kullanıcı arabiriminde görüntüleyebilirsiniz. Bu düzenleme ana görünüm/ayrıntılar görünümü veya liste/ayrıntılar görünümü olarak da bilinir.

Bu düzenlemeyi iki şekilde uygulayabilirsiniz. Ayrıntılar görünümünü, ListViewSelectedItem özelliğine bağlayabilirsiniz. İsterseniz CollectionViewSource da kullanabilirsiniz. Bu durumda, hem ListView'yi hem de ayrıntılar görünümünü CollectionViewSource öğesine bağlarsınız. Bu yaklaşım, seçili durumdaki öğeyi sizin için halleder. Her iki teknik de aşağıdaki bölümlerde gösterilmiştir ve ikisi de aynı sonuçları verir (çizimde gösterilmiştir).

Not

Bu konu başlığında şu ana kadar yalnızca {x:Bind} işaretleme uzantısını kullandınız. Ancak aşağıdaki bölümlerde gösterilen tekniklerin her ikisi de daha esnek (ancak daha az performanslı) {Binding} işaretleme uzantısını gerektirir.

İlk olarak, SeçilenÖğe tekniği. C# uygulaması için gereken tek değişiklik işaretlemedir.

<Window x:Class="Quickstart.MainWindow" ... >
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <ListView x:Name="recordingsListView" ItemsSource="{x:Bind ViewModel.Recordings}">
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="local:Recording">
                        <StackPanel Orientation="Horizontal" Margin="6">
                            <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                            <StackPanel>
                                <TextBlock Text="{x:Bind CompositionName}"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <StackPanel DataContext="{Binding SelectedItem, ElementName=recordingsListView}"
            Margin="0,24,0,0">
                <TextBlock Text="{Binding ArtistName}"/>
                <TextBlock Text="{Binding CompositionName}"/>
                <TextBlock Text="{Binding ReleaseDateTime}"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

CollectionViewSource tekniği için, önce üst düzey CollectionViewSourcekaynağı olarak bir Grid ekleyin.

<Grid.Resources>
    <CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Grid.Resources>

Not

WinUI'deki Window sınıfının Resources özelliği yoktur. Bunun yerine CollectionViewSource'ı en üst düzey Grid (veya StackPanelgibi diğer üst seviye kullanıcı arabirimi öğesi) elemanına ekleyebilirsiniz. Eğer bir Pageiçinde çalışıyorsanız, CollectionViewSource'i Page.Resources'ye ekleyebilirsiniz.

Ardından, CollectionViewSource'u kullanmak için ListView'da (artık adlandırılması gerekmeyen) ve ayrıntılar görünümündeki bağlamaları ayarlayın. Ayrıntılar görünümünü doğrudan CollectionViewSource öğesine bağlayarak, yolun koleksiyonun kendisinde bulunamadığı durumlarda geçerli veri bağlamı öğesine bağlanmak istediğinizi ima edersiniz. Bağlamanın yolu olarak CurrentItem özelliğini belirtmeniz gerekmez, ancak herhangi bir belirsizlik olduğunda bunu yapabilirsiniz.

...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...

Her durumda aynı sonuç aşağıdadır.

Liste görünümü bağlama 4

Veri değerlerini görüntüleme için biçimlendirme veya dönüştürme

Yukarıdaki işlemede bir sorun var. Özelliği ReleaseDateTime yalnızca bir tarih değil, bir DateTime değeridir. Bu nedenle, ihtiyacınız olandan daha hassas bir şekilde görüntülenir. Çözümlerden biri, Recording sınıfına ReleaseDateTime.ToString("d")eşdeğerini döndüren bir dize özelliği eklemektir. Bu özelliği ReleaseDate adlandırmak, tarih ve saat değil, tarih döndürdüğünü gösterir. Adını ReleaseDateAsString olarak koymak, bir dizge döndürdüğünü gösterir.

Daha esnek bir çözüm, değer dönüştürücüsü kullanmaktır. Aşağıda kendi değer dönüştürücünüzü yazma örneği verilmiştır. Recording.cs kaynak kodu dosyanıza aşağıdaki kodu ekleyin.

public class StringFormatter : Microsoft.UI.Xaml.Data.IValueConverter
{
    // This converts the value object to the string to display.
    // This will work with most simple types.
    public object Convert(object value, Type targetType,
        object parameter, string language)
    {
        // Retrieve the format string and use it to format the value.
        string formatString = parameter as string;
        if (!string.IsNullOrEmpty(formatString))
        {
            return string.Format(formatString, value);
        }

        // If the format string is null or empty, simply
        // call ToString() on the value.
        return value.ToString();
    }

    // No need to implement converting back on a one-way binding
    public object ConvertBack(object value, Type targetType,
        object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Artık StringFormatter örneğini bir kaynak olarak ekleyebilir ve ReleaseDateTime özelliğini görüntüleyen TextBlock bağlamasında kullanabilirsiniz.

<Grid.Resources>
    ...
    <local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Grid.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
    Converter={StaticResource StringFormatterValueConverter},
    ConverterParameter=Released: \{0:d\}}"/>
...

Gördüğünüz gibi biçimlendirme esnekliği için, işaretleme dönüştürücü parametresi yoluyla dönüştürücüye bir biçim dizesi geçirir. Bu konuda gösterilen kod örneğinde, C# değer dönüştürücüsü bu parametreyi kullanır.

Sonuç şu şekildedir.

özel biçimlendirme ile tarih görüntüleme

Bağlama ile x:Bind arasındaki farklar

WinUI uygulamalarında veri bağlama ile çalışırken iki birincil bağlama mekanizmasıyla karşılaşabilirsiniz: Binding ve x:Bind. Her ikisi de kullanıcı arabirimi öğelerini veri kaynaklarına bağlama amacına hizmet etse de, aralarında farklı farklar vardır:

  • x:Bind: Derleme zamanı denetimi, daha iyi performans sunar ve kesin olarak yazılır. Derleme zamanında veri yapısını bildiğiniz senaryolar için idealdir.
  • Binding: Çalışma zamanı değerlendirmesi sağlar ve veri yapısının derleme zamanında bilinmemesi gibi dinamik senaryolar için daha esnektir.

x:Bind tarafından desteklenmeyen senaryolar

x:Bind Güçlü olsa da, bunu belirli senaryolarda kullanamazsınız:

  • Dinamik veri yapıları: Veri yapısı derleme zamanında bilinmiyorsa kullanamazsınız x:Bind.
  • Öğeden öğeye bağlama: x:Bind doğrudan iki kullanıcı arabirimi öğesi arasında bağlamayı desteklemez.
  • öğesine bağlanma, üst öğenin özniteliğini otomatik olarak devralmaz.
  • Mode=TwoWay ile iki yönlü bağlamalar: Destekleniyor olsa da, x:Bind tek yönlü veya iki yönlü bağlama kullanarak kaynak değiştiğinde UI'ın güncellenmesini istediğiniz herhangi bir özellik için açıkça uygulamanız INotifyPropertyChanged gerektirir. İki yönlü bağlamalarla arasındaki temel fark, değişikliklerin kullanıcı arabiriminden kaynağa geri akmasıdır.

Pratik örnekler ve bunların ne zaman kullanılacağı hakkında daha ayrıntılı bilgi için aşağıdaki konulara bakın: