Apakah ada pola formal yang baik untuk mengelola negara dalam MVVM?

21

Saya sudah mulai belajar tentang Redux dan Bereaksi di dunia web, dan semakin saya mempelajarinya semakin saya menyadari betapa manajemen negara yang menyakitkan di dunia desktop dengan arsitektur gaya MVVM WPF (menggunakan Caliburn khusus untuk mengikat Tampilan untuk ViewModels).

Redux memiliki beberapa prinsip sederhana yang menentukan cara pengelolaan negara, membuat pembaruan UI, penanganan acara, dan perubahan keadaan jauh lebih mudah diprediksi. Prinsipnya adalah:

  • Sumber kebenaran tunggal (semua status yang dapat diubah disimpan dalam satu objek bersama).
  • Status hanya baca. Itu tidak dapat dimodifikasi oleh komponen melalui kode, yang biasanya terjadi di WPF.
  • Status hanya dapat dimodifikasi oleh fungsi murni.

Arsitektur MVVM dari WPF memungkinkan Anda untuk membangun tampilan interaktif dengan sangat cepat, tetapi men-debug masalah ketika berbagai model dan acara semua perubahan kondisi adalah mimpi buruk. Misalnya: peristiwa yang dipicu yang mengubah tampilan dan mencoba mengatur tab default, tetapi data belum selesai memuat secara tidak sinkron dari layanan web sehingga tab tidak ada (belum) sehingga tidak ada yang terjadi

Saya menghabiskan waktu berjam-jam menggambar diagram untuk mencoba dan memahami interaksi yang kompleks antara komponen viewModels yang saling terkait yang saling memperbarui.

Saya mengerti bahwa Redux bertujuan untuk menyelesaikan beberapa keadaan yang tidak dapat diprediksi ini. Apakah ada yang serupa, atau pola arsitektur yang cocok dengan WPF untuk membantu mengelola negara lebih baik? Saya tidak yakin seberapa baik prinsip-prinsip Redux akan bekerja di. NET karena saya belum mencobanya. Mungkin seseorang memiliki pengalaman yang dapat memberikan saran?

Willem
sumber
Kami memiliki masalah serupa di browser. Javascript sederhana akan berjalan sangat awal dan DOM belum dibangun, jadi orang tidak dapat menemukan elemen UI. Untungnya ada sejumlah Acara, yang dapat kita gunakan untuk memicu penundaan eksekusi beberapa skrip hingga hal-hal lain berjalan lebih jauh. (Seperti DOMContentLoaded.)
Erik Eidt
1
Status redux sebenarnya diperbarui, tidak pernah dimodifikasi.
Andy
1
Saya tahu saya terlambat ke pesta tetapi ada proyek bernama React.NET yang membawa arsitektur Redux ke .NET.
SiberianGuy
Bagi mereka yang menyukai pendekatan ngrx / store di proyek Angular, ada NetRx.Store - manajemen negara untuk proyek Net, terinspirasi oleh ngrx / store. Anda bisa menemukannya di Nuget juga. Juga ada contoh penggunaan NetRx yang baik. Simpan dengan pola MVVM dalam proyek WPF
Vitalii Ilchenko

Jawaban:

8

Saya rasa saya tahu apa yang Anda maksud. Pada dasarnya Anda memecahkan masalah dengan menambahkan viewmodel 'controller' atau 'master' (excuse psudocode)

yaitu

public class MasterVM
{
    public ChildVM View1 {get;set;}
    public ChildVM View2 {get;set;}

    private Data data;
    public MasterVM()
    {
        View1.OnEvent += updateData;
    }

    private Action<int> updateData(int value)
    {
         View2.Value = value;
    }
}

ketika Anda melakukan ini dengan Pola Mediator, saya menganggap kelas sebagai Pengendali. yaitu.

public class Controller
{
    public Controller(MediatorService m)
    {
        m.Subscribe("valueupdated", updateData);
    }

    private Action<int> updateData(int value)
    {
         m.Publish("showvalue", value);
    }
}

public class View2
{
    public View2(MediatorService m)
    {
        m.Subscribe("showvalue", (int v)=> {Value = v;});
    }
}

Hal semacam ini memungkinkan Anda untuk menempatkan 'flow logic' atau Event Orkestrasi Anda di kelas-kelas bertahan tingkat tinggi ini dan menjaga kode VM ringan. Jika Anda ingin mengubah 'ketika pengguna mengklik BELI, pesanan diproses' hal-hal yang Anda ketahui terlihat di 'OrderFlowController' atau 'OrderProcessVM' atau namun Anda ingin menamai mereka. Daripada kombinasi dari BasketVM, PaymentVM, 3dSecureVM dll

Jadi, dalam contoh spesifik Anda tentang 'tab belum siap' mungkin Anda miliki

public class Controller
{
    bool dataLoadCompleted;
    public Controller(MediatorService m)
    {
        m.Subscribe("setTabRequest", setTab); //message from view model with set tab button
        m.Subscribe("dataLoadComplete", dataLoadComplete); //message from data loading view model or some other controller?
    }

    private Action<int> setTab(int value)
    {
         if(!dataLoadCompleted)
         {
             m.Publish("error", "Please wait for data to load"); //message for error alert view model
         }
         else
         {
             m.Publish("setDefaultTab", value); //message for tab viewmodel
         }
    }

    private Action dataLoadComplete()
    {
         //persist state;
         dataLoadCompleted = true;
    }
}
Ewan
sumber