MVVM Light DispatcherHelper, cara yang benar untuk multithread di MVVM Light

Apa cara yang disarankan untuk melakukan multithreading dengan MVVM Light. Saya memiliki model yang memiliki properti bool Sibuk

 public bool Busy
    {
        get { return busy_; }
        set
        {
           Set(nameof(Busy), ref busy_, value, broadcast: true);
        }
    }

Model tampilan saya mempublikasikan model secara langsung untuk tampilan tersebut (model tersebut mewarisi ViewModelBase MVVM Light), sehingga tampilan tersebut mengikat langsung ke properti sibuk model.

Jika saya memanggil model selalu dari thread UI semuanya baik-baik saja. Tetapi jika saya melakukan hal berikut dalam model tampilan saya sehingga dapat dijalankan di thread yang berbeda

Task.Factory.StartNew(() => 
{            
  model_.SomeFunctionThatWillSetBusyDuringItsExecution();
});

Kemudian tentu saja Sibuk diatur dari thread non UI dan kemudian pengikatan gagal dan aplikasi mogok. Jika saya menggunakan Messenger di penyetel properti, tampaknya Messenger juga tidak secara otomatis mengirimkan kode pengendali Messenger ke thread UI.

Saya menyadari ada DispatcherHelper di MVVM Light, tetapi untuk pengikatannya sepertinya tidak membantu. Jika saya mengubah properti menjadi

    public bool Busy
    {
        get { return busy_; }
        set
        {
           DispatcherHelper.CheckBeginInvokeOnUI(() =>
           {
              Set(nameof(Busy), ref busy_, value, broadcast: true);
           });
        }
    }

Saya masih mendapatkan pengecualian dan aplikasi mogok karena sumber pengikatan tidak ada di thread yang benar. Jadi pertanyaan saya sederhana, apa cara yang disarankan untuk melakukan multithreading seperti ini di MVVM Light?

Saya juga mencoba menggunakan syncronizationContext.

           syncContext_.Post(() =>
           {
              Set(nameof(Busy), ref busy_, value, broadcast: true);
           }, null);

Itu berfungsi jika panggilan selalu dari thread non-UI. Jika panggilan sudah berasal dari thread UI, syncContext.Post mengakibatkan fungsi Set() tidak dipanggil hingga semua kode dalam metode ViewModel selesai. Artinya, status sibuk mungkin tidak diperbarui dengan benar untuk kode yang tersisa. Jadi ini bukanlah solusi yang ideal.

Saya berterima kasih atas bantuan mengenai topik ini.


person Johan    schedule 27.09.2018    source sumber
comment
Saya rasa masalahnya adalah pengakses Set Anda seharusnya tidak melakukan operasi seperti itu. Saya yakin ada masalah desain di sini. IsBusy Anda hanya boleh disetel ke false/true pada beberapa peristiwa/kondisi metode thread Anda (di thread UI). Dengan cara ini Anda bahkan tidak perlu repot dengan DispatcherHelper atau masalah akses thread. Metode thread harus selalu terisolasi dan hanya melaporkan kondisi awal/selesai dan pembaruan kemajuan, yang semuanya harus selalu terjadi di thread utama/UI.   -  person Luishg    schedule 09.04.2019


Jawaban (1)


Daripada menambahkan kode DispatcherHelper di dalam properti, saya menambahkannya di semua tempat di mana properti itu dimodifikasi. Maka tampaknya itu bekerja dengan baik.

Satu-satunya masalah, karena seseorang mengirimkan pekerjaan ke thread UI, kode di ViewModel tidak akan mendapatkan status yang diperbarui jika bagian dari metode model tampilan sudah berjalan di thread UI. Saya menemukan cara untuk memaksa thread UI memproses antrean messenger-nya sambil memastikan status Busy diperbarui. Ini bukan solusi yang terbaik, dan kemungkinan akan memiliki dampak kinerja yang buruk karena semua peralihan konteks, tapi setidaknya ini berhasil dan hanya satu kalimat sederhana.

Kode untuk memaksa thread UI memproses semua pesan dalam antreannya

  DispatcherHelper.UIDispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);

Jika ada cara yang lebih optimal untuk menyelesaikannya, beri tahu saya. Kalau tidak, saya akan menetapkan ini sebagai jawabannya dalam beberapa hari dari sekarang.

person Johan    schedule 27.09.2018