Aracılığıyla paylaş


MVVM Araç Seti ile MVVM uygulama

Artık proje yapısını oluşturduğunuza göre, MVVM Araç Seti'ni kullanarak MVVM desenini uygulamaya başlayabilirsiniz. Bu adım, MVVM Araç Seti'nin özellik değişikliği bildirimi ve ObservableObject komut uygulaması gibi RelayCommand özelliklerinden yararlanan ViewModel'ler oluşturmayı içerir.

MVVM Toolkit NuGet paketini yükleme

MVVM Araç Seti'ni hem WinUINotes hem de WinUINotes.Bus projelerine yüklemeniz gerekir.

Visual Studio'yu kullanma

  1. Çözüm Gezgini'nde WinUINotes.Bus projesine sağ tıklayın.
  2. NuGet Paketlerini Yönet'i seçin.
  3. CommunityToolkit.Mvvm için arama yapın ve en son kararlı sürümü yükleyin.
  4. WinUINotes projesi için bu adımları yineleyin.

.NET CLI kullanma

Alternatif olarak paketi yüklemek için .NET CLI kullanabilirsiniz:

dotnet add WinUINotes.Bus package CommunityToolkit.Mvvm
dotnet add WinUINotes package CommunityToolkit.Mvvm

Model katmanı için tasarım kararları

MVVM'yi uyguladığınızda model sınıflarınızı ViewModel'lere göre nasıl yapılandırabileceğinize karar vermeniz önemlidir. Bu öğreticide, model sınıfları (Note ve AllNotes) veri gösteriminden, iş mantığından ve veri depolamanın güncelleştirilmesinden sorumludur. ViewModel'ler, kullanıcı arabirimi etkileşimi için gözlemlenebilir özellikleri, değişiklik bildirimini ve komutları işler.

Daha basit bir uygulamada, iş mantığı veya veri erişim yöntemleri olmadan model sınıfları için düz eski CLR nesneleri (POCO' lar) kullanabilirsiniz. Bu durumda ViewModel'ler tüm veri işlemlerini hizmet katmanı üzerinden işler. Ancak bu öğreticide model sınıfları, endişelerin daha net bir şekilde ayrılmasını sağlamak ve ViewModel'lerin sunu mantığına odaklanmasını sağlamak için notları yükleme, kaydetme ve silme yöntemlerini içerir.

Not modelini taşı

Note Sınıfı WinUINotes.Bus projesine taşıyın. Veri gösterimi ve durum yönetimi için bazı mantık içeren ancak MVVM Araç Seti özellikleri olmayan basit bir model sınıfı olarak kalır. ViewModel'ler gözlemlenebilir özellikleri işler ve modelin kendisini değil bildirimi değiştirir.

  1. WinUINotes.Bus projesinde Models adlı yeni bir klasör oluşturun.

  2. Note.cs Dosyayı WinUINotes projesinden WinUINotes.Bus/Models klasörüne taşıyın.

  3. Ad alanını yeni konumla eşleşecek şekilde güncelleştirin:

    namespace WinUINotes.Models
    {
        public class Note
        {
            // Existing code remains unchanged
            ...
        }
    }
    

Note sınıfı basit bir veri modelidir. ViewModel'ler gözlemlenebilir özellikleri yönettiğinden ve değişiklikleri kullanıcı arabirimine bildirdiğinden değişiklik bildirimi gerekmez.

AllNotes modelini taşıma

AllNotes Sınıfı WinUINotes.Bus projesine taşıyın.

  1. AllNotes.cs Dosyayı WinUINotes projesinden WinUINotes.Bus/Models klasörüne taşıyın.

  2. Ad alanını yeni konumla eşleşecek şekilde güncelleştirin:

    namespace WinUINotes.Models
    {
        public class AllNotes
        {
            // Existing code remains unchanged
            ...
        }
    }
    

Note sınıfı gibi basit AllNotes bir model sınıfıdır. ViewModel gözlemlenebilir davranışı işler ve not koleksiyonunu yönetir.

AllNotesViewModel'i oluşturun

  1. WinUINotes.Bus projesinde ViewModels adlı yeni bir klasör oluşturun.

  2. Aşağıdaki içeriğe sahip adlı AllNotesViewModel.cs yeni bir sınıf dosyası ekleyin:

    using CommunityToolkit.Mvvm.ComponentModel;
    using CommunityToolkit.Mvvm.Input;
    using System.Collections.ObjectModel;
    using System.Threading.Tasks;
    using WinUINotes.Models;
    
    namespace WinUINotes.ViewModels
    {
        public partial class AllNotesViewModel : ObservableObject
        {
            private readonly AllNotes allNotes;
    
            [ObservableProperty]
            private ObservableCollection<Note> notes;
    
            public AllNotesViewModel()
            {
                allNotes = new AllNotes();
                notes = new ObservableCollection<Note>();
            }
    
            [RelayCommand]
            public async Task LoadAsync()
            {
                await allNotes.LoadNotes();
                Notes.Clear();
                foreach (var note in allNotes.Notes)
                {
                    Notes.Add(note);
                }
            }
        }
    }
    

AllNotesViewModel kullanıcı arabiriminde görüntülenen not koleksiyonunu yönetir:

  • [ObservableProperty]: notes alanı, değişiklik bildirimine sahip otomatik olarak bir ortak Notes özelliği oluşturur. Koleksiyon değiştiğinde Notes kullanıcı arabirimi otomatik olarak güncelleştirilir.
  • allNotes model: Bu özel alan, gerçek veri işlemlerini işleyen modelin bir örneğini AllNotes barındırıyor.
  • [RelayCommand]: Bu öznitelik yönteminden LoadCommand bir LoadAsync() özellik oluşturarak kullanıcı arabiriminin veri bağlama aracılığıyla yükleme işlemini tetiklesine olanak tanır.
  • LoadAsync() method: Bu yöntem modelden notları yükler, geçerli gözlemlenebilir koleksiyonu temizler ve yüklenen notlarla doldurur. Bu düzen, kullanıcı arabirimine bağlı koleksiyonun temel alınan verilerle eşitlenmiş kalmasını sağlar.

Model (veri işlemleri) ile allNotes gözlemlenebilir koleksiyon (UI bağlama) arasındaki Notes ayrım, endişeleri ayrı tutan ve ViewModel'in verileriyle eşitlenmiş Görünüm'ü tutan önemli bir MVVM desenidir.

Belgelerde daha fazla bilgi edinin:

NoteViewModel oluşturma

  1. ViewModels klasörüne adlı NoteViewModel.csyeni bir sınıf dosyası ekleyin:

    using CommunityToolkit.Mvvm.ComponentModel;
    using CommunityToolkit.Mvvm.Input;
    using System;
    using System.Threading.Tasks;
    using WinUINotes.Models;
    
    namespace WinUINotes.ViewModels
    {
        public partial class NoteViewModel : ObservableObject
        {
            private Note note;
    
            [ObservableProperty]
            [NotifyCanExecuteChangedFor(nameof(SaveCommand))]
            [NotifyCanExecuteChangedFor(nameof(DeleteCommand))]
            private string filename = string.Empty;
    
            [ObservableProperty]
            [NotifyCanExecuteChangedFor(nameof(SaveCommand))]
            private string text = string.Empty;
    
            [ObservableProperty]
            private DateTime date = DateTime.Now;
    
            public NoteViewModel()
            {
                this.note = new Note();
                this.Filename = note.Filename;
            }
    
            public void InitializeForExistingNote(Note note)
            {
                this.note = note;
                this.Filename = note.Filename;
                this.Text = note.Text;
                this.Date = note.Date;
            }
    
            [RelayCommand(CanExecute = nameof(CanSave))]
            private async Task Save()
            {
                note.Filename = this.Filename;
                note.Text = this.Text;
                note.Date = this.Date;
                await note.SaveAsync();
    
                // Check if the DeleteCommand can now execute
                // (it can if the file now exists)
                DeleteCommand.NotifyCanExecuteChanged();
            }
    
            private bool CanSave()
            {
                return note is not null
                    && !string.IsNullOrWhiteSpace(this.Text)
                    && !string.IsNullOrWhiteSpace(this.Filename);
            }
    
            [RelayCommand(CanExecute = nameof(CanDelete))]
            private async Task Delete()
            {
                await note.DeleteAsync();
                note = new Note();
            }
    
            private bool CanDelete()
            {
                // Note: This is to illustrate how commands can be
                // enabled or disabled.
                // In a real application, you shouldn't perform
                // file operations in your CanExecute logic.
                return note is not null
                    && !string.IsNullOrWhiteSpace(this.Filename)
                    && this.note.NoteFileExists();
            }
        }
    }
    

NoteViewModel birkaç önemli MVVM Araç Seti özelliğini gösterir:

  • [ObservableProperty] filename: , textve date alanları, değişiklik bildirimi desteğine sahip genel özellikleri (Filename, Text, Date) otomatik olarak oluşturur.
  • [NotifyCanExecuteChangedFor]: Bu öznitelik, ne zaman Filename veya Text değiştiğinde ilişkili komutların yürütülip yürütülemeyeceğini yeniden değerlendirmesini sağlar. Örneğin, metin yazdığınızda Kaydet düğmesi doğrulama mantığına göre otomatik olarak etkinleştirir veya devre dışı bırakır.
  • [RelayCommand(CanExecute = nameof(CanSave))]: Bu öznitelik doğrulama yöntemine SaveCommandbağlı bir CanSave() özellik oluşturur. Komut yalnızca her ikisi Text ve Filename değerleri olduğunda etkinleştirilir.
  • InitializeForExistingNote(): Bu yöntem, var olan bir not verilerini ViewModel özelliklerine yükler ve ardından kullanıcı arabirimini veri bağlama aracılığıyla güncelleştirir.
  • Kaydetme mantığı: Save() yöntemi, Note temel alınan modeli geçerli özellik değerleriyle günceller ve modelde SaveAsync() yöntemini çağırır. Kaydettikten sonra, DeleteCommand yeniden değerlendirmesi gerektiğini bildirir (artık bir dosya var olduğundan ve silinebildiğinden).
  • Silme mantığı: Delete() yöntemi not modelinde çağrılar DeleteAsync() ve yeni bir boş not oluşturur.

Bu öğreticinin ilerleyen bölümlerinde, gerçek dosya işlemleri için dosya servislerini entegre edecek ve bir not silindiğinde uygulamanın diğer bölümlerini gevşek bir bağ ile bilgilendirmek için MVVM Toolkit'in WeakReferenceMessenger sınıfını kullanacaksınız.

Belgelerde daha fazla bilgi edinin:

Görünüm Modellerini kullanmak için görünümleri güncelleştirme

Şimdi yeni ViewModel'lere bağlanmak için XAML sayfalarınızı güncelleştirmeniz gerekir.

AllNotesPage görünümünü güncelleştirme

  1. AllNotesPage.xaml içinde, ItemsSource öğesinin bağlamasını, ViewModel'in Notes özelliğini kullanacak şekilde ItemsView güncelleyin.

    <ItemsView ItemsSource="{x:Bind viewModel.Notes}"
    ...
    
  2. AllNotesPage.xaml.cs Dosyayı aşağıdaki gibi görünecek şekilde güncelleştirin:

    using Microsoft.UI.Xaml;
    using Microsoft.UI.Xaml.Controls;
    using Microsoft.UI.Xaml.Navigation;
    using WinUINotes.ViewModels;
    
    namespace WinUINotes.Views
    {
        public sealed partial class AllNotesPage : Page
        {
            private AllNotesViewModel? viewModel;
    
            public AllNotesPage()
            {
                this.InitializeComponent();
                viewModel = new AllNotesViewModel();
            }
    
            private void NewNoteButton_Click(object sender, RoutedEventArgs e)
            {
                Frame.Navigate(typeof(NotePage));
            }
    
            private void ItemsView_ItemInvoked(ItemsView sender, ItemsViewItemInvokedEventArgs args)
            {
                Frame.Navigate(typeof(NotePage), args.InvokedItem);
            }
    
            protected override async void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                if (viewModel is not null)
                {
                    await viewModel.LoadAsync();
                }
            }
        }
    }
    

Bu kod arkası dosyasında, oluşturucu AllNotesViewModel'nin doğrudan örneğini oluşturur. OnNavigatedTo() yöntemi, sayfaya gidildiğinde ViewModel üzerindeki LoadAsync() yöntemini çağırır. Bu yöntem, depolamadan notları yükler ve gözlemlenebilir koleksiyonu güncelleştirir. Bu düzen, kullanıcı tüm notlar sayfasına gittiği zaman verilerin her zaman yenilenmesini sağlar.

Bu öğreticinin ilerleyen bölümlerinde, bu kodu bağımlılık ekleme özelliğini kullanacak şekilde yeniden düzenleyebilirsiniz. Bu, ViewModel'in doğrudan oluşturulmak yerine sayfa oluşturucusuna eklenmesini sağlar. Bu yaklaşım test edilebilirliği artırır ve ViewModel yaşam döngülerini yönetmeyi kolaylaştırır.

NotePage görünümünü güncelleştirme

  1. NotePage.xaml içinde, TextBox bağlamalarını Text ve Header için ViewModel'in özelliklerini kullanacak şekilde güncelleyin. Düğmeleri, olayları kullanmak yerine komutlara bağlanacak şekilde güncelleştirin:

    ...
    <TextBox x:Name="NoteEditor"
             Text="{x:Bind noteVm.Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
             AcceptsReturn="True"
             TextWrapping="Wrap"
             PlaceholderText="Enter your note"
             Header="{x:Bind noteVm.Date.ToString()}"
             ScrollViewer.VerticalScrollBarVisibility="Auto"
             MaxWidth="400"
             Grid.Column="1"/>
    
    <StackPanel Orientation="Horizontal"
                HorizontalAlignment="Right"
                Spacing="4"
                Grid.Row="1" Grid.Column="1">
        <Button Content="Save" Command="{x:Bind noteVm.SaveCommand}"/>
        <Button Content="Delete" Command="{x:Bind noteVm.DeleteCommand}"/>
    </StackPanel>
    ...
    

    Bağlamayı UpdateSourceTriggerTextBox.Text kullanıcı yazdıkça değişikliklerin ViewModel'e gönderilmesini sağlamak için de ayarlarsınız. Bu ayar, girişi temel alarak düğmenin Save gerçek zamanlı olarak etkinleştirilmesine veya devre dışı bırakılmasına olanak tanır.

  2. NotePage.xaml.cs içinde, kodu NoteViewModel kullanacak şekilde güncelleyin.

    using Microsoft.UI.Xaml.Controls;
    using Microsoft.UI.Xaml.Navigation;
    using WinUINotes.Models;
    using WinUINotes.ViewModels;
    
    namespace WinUINotes.Views
    {
        public sealed partial class NotePage : Page
        {
            private NoteViewModel? noteVm;
    
            public NotePage()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
                noteVm = new NoteViewModel();
    
                if (e.Parameter is Note note && noteVm is not null)
                {
                    noteVm.InitializeForExistingNote(note);
                }
            }
        }
    }
    

    Click ve Save için olan olaylar kaldırılmıştır çünkü düğmeler artık doğrudan ViewModel'deki komutlara bağlanmaktadır. NoteViewModel örneği, OnNavigatedTo() yönteminde oluşturulur. Bir Note parametre geçirilirse ViewModel'i mevcut not verileriyle başlatır.

Belgelerde daha fazla bilgi edinin: