RelayCommand özniteliği

türü RelayCommand , açıklamalı yöntemler için geçiş komutu özellikleri oluşturulmasına izin veren bir özniteliktir. Amacı, bir ViewModel içinde özel yöntemleri saran komutları tanımlamak için gereken tekrarlayan kodu tamamen ortadan kaldırmaktır.

Note

Çalışmak için, açıklamalı yöntemlerin kısmi bir sınıfta olması gerekir. Tür iç içeyse, bildirim söz dizimi ağacındaki tüm türler de partial olarak işaretlenmelidir. Oluşturucu istenen komutla bu tür için farklı bir kısmi bildirim oluşturamayacağından, bunu yapmamak derleme hatalarına neden olur.

Platform API'leri:RelayCommand, ICommand, IRelayCommand, IRelayCommand<T>, IAsyncRelayCommand, IAsyncRelayCommand<T>, TaskCancellationToken

Nasıl çalışır?

özniteliği, RelayCommand kısmi türde bir yönteme açıklama eklemek için kullanılabilir, örneğin:

[RelayCommand]
private void GreetUser()
{
    Console.WriteLine("Hello!");
}

Ve şuna benzer bir komut oluşturur:

private RelayCommand? greetUserCommand;

public IRelayCommand GreetUserCommand => greetUserCommand ??= new RelayCommand(GreetUser);

Note

Oluşturulan komutun adı, yöntem adına göre oluşturulur. Oluşturucu, yöntem adını kullanır ve sonuna "Command" ekler; varsa baştaki "On" ön ekini kaldırır. Ayrıca, asenkron yöntemlerde "Command" eklenmeden önce "Async" soneki de kaldırılır.

Komut parametreleri

özniteliği, [RelayCommand] bir parametre ile yöntemler için komut oluşturmayı destekler. Bu durumda, aynı türdeki bir parametreyi kabul ederek oluşturulan komutu otomatik olarak bir IRelayCommand<T> olarak değiştirir:

[RelayCommand]
private void GreetUser(User user)
{
    Console.WriteLine($"Hello {user.Name}!");
}

Bu, aşağıdaki kodun oluşturulmasına neden olur:

private RelayCommand<User>? greetUserCommand;

public IRelayCommand<User> GreetUserCommand => greetUserCommand ??= new RelayCommand<User>(GreetUser);

Ortaya çıkan komut, bağımsız değişkenin türünü tür bağımsız değişkeni olarak otomatik olarak kullanır.

Zaman uyumsuz komutlar

[RelayCommand] komutu, IAsyncRelayCommand ve IAsyncRelayCommand<T> arabirimleri aracılığıyla asenkron yöntemlerin sarmalanmasını da destekler. Bu işlem, bir yöntem Task türünde bir değer döndürdüğünde otomatik olarak gerçekleştirilir. Örneğin:

[RelayCommand]
private async Task GreetUserAsync()
{
    User user = await userService.GetCurrentUserAsync();

    Console.WriteLine($"Hello {user.Name}!");
}

Bu, aşağıdaki kodla sonuçlanır:

private AsyncRelayCommand? greetUserCommand;

public IAsyncRelayCommand GreetUserCommand => greetUserCommand ??= new AsyncRelayCommand(GreetUserAsync);

Yöntem bir parametre alırsa, sonuçta elde edilen komut da genel olacaktır.

Yöntemin bir CancellationToken içerdiği özel bir durum vardır; bu, iptali etkinleştirmek için komuta aktarılır. Yani, aşağıdaki gibi bir yöntem:

[RelayCommand]
private async Task GreetUserAsync(CancellationToken token)
{
    try
    {
        User user = await userService.GetCurrentUserAsync(token);

        Console.WriteLine($"Hello {user.Name}!");
    }
    catch (OperationCanceledException)
    {
    }
}

Oluşturulan komutun sarmalanmış yönteme bir belirteç iletmesine neden olur. Bu, kullanıcıların bu belirteci işaretlemek için yalnızca IAsyncRelayCommand.Cancel çağrısı yapmasına ve bekleyen işlemlerin doğru şekilde durdurulabilmesine olanak tanır.

Komutları etkinleştirme ve devre dışı bırakma

Komutları devre dışı bırakmak ve daha sonra durumlarını geçersiz kılıp yürütülemeyeceklerini yeniden denetlemelerini sağlamak genellikle yararlıdır. Bunu desteklemek için, RelayCommand özniteliği, bir komutun yürütülüp yürütülemeyeceğini değerlendirmek amacıyla kullanılacak hedef özellik veya yöntemi belirtmek için kullanılabilen CanExecute özelliğini kullanıma sunar:

[RelayCommand(CanExecute = nameof(CanGreetUser))]
private void GreetUser(User? user)
{
    Console.WriteLine($"Hello {user!.Name}!");
}

private bool CanGreetUser(User? user)
{
    return user is not null;
}

Bu şekilde, CanGreetUser düğme kullanıcı arabirimine ilk bağlandığında (örn. bir düğmeye) çağrılır ve ardından komutta her IRelayCommand.NotifyCanExecuteChanged çağrıldığında yeniden çağrılır.

Örneğin, bir komut durumunu denetlemek için bir özelliğe bu şekilde bağlanabilir:

[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(GreetUserCommand))]
private User? selectedUser;
<!-- Note: this example uses traditional XAML binding syntax -->
<Button
    Content="Greet user"
    Command="{Binding GreetUserCommand}"
    CommandParameter="{Binding SelectedUser}"/>

Bu örnekte, oluşturulan SelectedUser özellik değeri her değiştiğinde yöntemini çağıracaktır GreetUserCommand.NotifyCanExecuteChanged() . Kullanıcı arabiriminde GreetUserCommand öğesine bağlı bir Button denetimi vardır; bu, CanExecuteChanged olayı her tetiklendiğinde CanExecute yöntemini yeniden çağıracağı anlamına gelir. Bu, sarmalanan CanGreetUser yönteminin değerlendirilmesine neden olur; bu yöntem de, giriş User örneğinin (kullanıcı arayüzünde SelectedUser özelliğine bağlı olan) null olup olmamasına bağlı olarak düğmenin yeni durumunu döndürür. Bu, her SelectedUser değiştirildiğinde bu GreetUserCommand özelliğin bir değere sahip olup olmadığına bağlı olarak etkinleştirileceği veya etkinleştirilmeyeceği anlamına gelir. Bu, bu senaryoda istenen davranıştır.

Note

Yöntemin veya özelliğin dönüş değeri değiştiğinde komut otomatik olarak fark CanExecute. Komutu geçersiz kılmak ve bağlı CanExecute yönteminin yeniden değerlendirilmesini isteyerek komuta bağlı denetimin görsel durumunu güncellemek için IRelayCommand.NotifyCanExecuteChanged çağrısını yapmak geliştiriciye bağlıdır.

Eşzamanlı yürütmeleri işleme

Bir komut zaman uyumsuz olduğunda, eşzamanlı yürütmelere izin verilip verilmeyeceğine karar verecek şekilde yapılandırılabilir. RelayCommand özniteliği kullanıldığında, AllowConcurrentExecutions özelliği aracılığıyla ayarlanabilir. Varsayılan değer false'dır; bu, bir yürütme beklemede olana kadar komutun durumunu devre dışı olarak göstereceği anlamına gelir. Bunun yerine true olarak ayarlanırsa, istenen sayıda eşzamanlı çağrı kuyruğa alınabilir.

Bir komut bir iptal belirtecini kabul ediyorsa, eşzamanlı yürütme talep edildiğinde belirteç de iptal edilir; bunu unutmayın. Temel fark, eşzamanlı yürütmelere izin verilirse komutun etkin kalması ve öncekinin gerçekten tamamlanmasını beklemeden yeni bir istenen yürütme başlatmasıdır.

Eşzamansız özel durumları işleme

Zaman uyumsuz geçiş komutlarının özel durumları işlemesinin iki farklı yolu vardır:

  • Bekle ve yeniden fırlat (varsayılan): komut, bir çağrının tamamlanmasını beklediğinde, herhangi bir özel durum doğal olarak aynı senkronizasyon bağlamında fırlatılır. Bu genellikle, oluşan özel durumların yalnızca uygulamayı kilitleyeceği anlamına gelir; bu, zaman uyumlu komutlarla tutarlı bir davranıştır (oluşan özel durumlar da uygulamayı kilitler).
  • Özel durumları görev zamanlayıcısına iletme: Bir komut, özel durumları görev zamanlayıcısına iletecek şekilde yapılandırılmışsa, fırlatılan özel durumlar uygulamanın çökmesine neden olmaz; bunun yerine hem kullanıma sunulan IAsyncRelayCommand.ExecutionTask üzerinden erişilebilir olur hem de TaskScheduler.UnobservedTaskException öğesine kadar yukarı yayılır. Bu, daha gelişmiş senaryolara olanak tanır (kullanıcı arabirimi bileşenlerinin göreve bağlanması ve işlemin sonucuna göre farklı sonuçlar görüntülemesi gibi), ancak doğru şekilde kullanılması daha karmaşıktır.

Varsayılan davranış, komutların beklemesi ve özel durumları yeniden fırlatmasıdır. Bu, FlowExceptionsToTaskScheduler özelliği aracılığıyla yapılandırılabilir:

[RelayCommand(FlowExceptionsToTaskScheduler = true)]
private async Task GreetUserAsync(CancellationToken token)
{
    User user = await userService.GetCurrentUserAsync(token);

    Console.WriteLine($"Hello {user.Name}!");
}

Bu durumda, özel durumlar artık uygulamanın çökmesine neden olmayacağı için try/catch gerekli değildir. Bunun, diğer ilgisiz istisnaların da otomatik olarak yeniden fırlatılmamasına neden olacağını unutmayın. Bu nedenle, her bir senaryoya nasıl yaklaşacağınıza dikkatle karar vermeli ve kodun geri kalanını buna göre uygun şekilde yapılandırmalısınız.

Zaman uyumsuz işlemler için komutları iptal etme

Zaman uyumsuz komutların son seçeneklerinden biri, bir iptal komutunun oluşturulmasını isteme özelliğidir. Bu, bir işlemin iptal edilmesini istemek için kullanılabilen eşzamansız bir relay komutunu saran bir ICommand'dir. Bu komut, belirli bir zamanda kullanılıp kullanılamayacağını yansıtmak için durumunu otomatik olarak sinyalleyecektir. Örneğin, bağlı komut yürütülmezse, durumunu yürütülebilir değil olarak bildirir. Bu, aşağıdaki gibi kullanılabilir:

[RelayCommand(IncludeCancelCommand = true)]
private async Task DoWorkAsync(CancellationToken token)
{
    // Do some long running work...
}

Bu, bir DoWorkCancelCommand özelliğin de oluşturulmasına neden olur. Bu, kullanıcıların bekleyen zaman uyumsuz işlemleri kolayca iptal etmesine olanak sağlamak için başka bir kullanıcı arabirimi bileşenine bağlanabilir.

Özel öznitelikler ekleme

Gözlemlenebilir özelliklerde olduğu gibi oluşturucu da RelayCommand oluşturulan özellikler için özel öznitelikler için destek içerir. Bundan yararlanmak için öznitelik listelerindeki hedefi açıklamalı yöntemler üzerinden kullanabilirsiniz [property: ] ve MVVM Araç Seti bu öznitelikleri oluşturulan komut özelliklerine iletir.

Örneğin, aşağıdaki gibi bir yöntemi göz önünde bulundurun:

[RelayCommand]
[property: JsonIgnore]
private void GreetUser(User user)
{
    Console.WriteLine($"Hello {user.Name}!");
}

Bu, üzerinde [JsonIgnore] özniteliği bulunan bir GreetUserCommand özelliği oluşturur. Yöntemi hedef alan öznitelik listelerini istediğiniz kadar kullanabilirsiniz ve bunların tümü oluşturulan özelliklere iletilir.

Examples