Pertanyaan Menampilkan Konfirmasi di jendela menutup dengan cara reaktif


Saya memiliki pengamatan yang saya gunakan untuk menampilkan dialog konfirmasi, kira-kira tanda tangan:

IObservable<DialogResult> ShowDialog(string title, string message);

Ini menunjukkan dialog kepada pengguna, dengan kombinasi tombol ya / tidak.

Di jendela utama saya, saya mengakses acara penutupan seperti:

this.Events().Closing.[Do something here]

Saya ingin dapat:

  1. Tampilkan dialog konfirmasi saat penutupan kebakaran yang dapat diamati
  2. Mengatur CancelEventArgs.Cancel properti ke true jika pengguna mengklik tombol "tidak".

Saya sudah mencoba berlangganan langsung:

this.Events().Closing.Subscribe(e =>
{
    var res = Dialogs.ShowDialog("Close?", "Really Close?").Wait();
    e.Cancel = res == DialogResult.Ok;
});

Tapi itu tergantung karena Wait() panggilan, saya juga mencoba varian async:

this.Events().Closing.Subscribe(async e =>
{
    var res = await Dialogs.ShowDialog("Close?", "Really Close?");
    e.Cancel = res == DialogResult.Ok;
});

Itu tidak bagus, karena itu langsung kembali.

Yang benar-benar ingin saya lakukan adalah sesuatu seperti:

this.Events().Closing.ThenDo(_ => Dialogs.ShowDialog("Close?", "Really Close?"))
    .Subscribe((cancelEventArgs, dialogResult) =>
    {
        cancelEventArgs.Cancel == dialogResult == DialogResult.Ok;
    });

Tapi itu tidak ada, saya tahu kuncinya di sini adalah bagaimana saya menggabungkan dua hal yang bisa diamati, tetapi saya tidak tahu bagaimana melakukannya, dan dokumentasi sedikit cahaya pada contoh-contoh praktis.


6
2018-05-20 17:56


asal


Jawaban:


Kamu perlu untuk memblokir event handler Penutup, maka async (atau manipulasi Rx) tidak akan banyak membantu Anda di sini.

Tetapi Anda juga perlu memblokirnya sedemikian rupa sehingga acara UI masih diproses, sehingga UI tidak membeku.

Solusi yang paling umum untuk itu adalah menggunakan Window.ShowDialog bukannya Show, dan kode ini berfungsi:

        this.Events().Closing.Subscribe(e =>
        {
            var ret = new Window().ShowDialog();
            e.Cancel = true;
        });

Tetapi menggunakan itu dalam metode ShowDialog Rx Anda akan membuat blok panggilan berlangganan, dan itu tidak mungkin apa yang Anda inginkan (untuk kasus lain, dalam hal ini aku s Apa yang kau butuhkan).

Atau Anda dapat menjalankan loop dispatcher batin, seperti ini:

        this.Events().Closing.Subscribe(e =>
        {
            var dialog = Dialogs.ShowDialog("Close?", "Really Close?");
            var dispatcherFrame = new DispatcherFrame();
            dialog.Take(1).Subscribe(res => {
                e.Cancel = res == DialogResult.Ok;
                dispatcherFrame.Continue = false;
            });
            // this will process UI events till the above fires
            Dispatcher.PushFrame(dispatcherFrame);
        });

Itu hanya akan berfungsi jika Dispatcher yang sama digunakan oleh kedua jendela.

EDIT:

Atau, Anda dapat menghindari pemblokiran dengan selalu membatalkan penutupan, dan menutup formulir sendiri nanti, yang mungkin lebih Rx-cara, yaitu:

        var forceClose = default(bool);

        this.Events().Closing
            .Where(_ => !forceClose)
            .Do(e => e.Cancel = true)
            .SelectMany(_ => Dialogs.ShowDialog("Close?", "Really Close?"))
            .Where(res => res == DialogResult.Ok)
            .Do(_ => forceClose = true)
            .Subscribe(_ => this.Close());

2
2017-07-20 11:18



Cara terbaik untuk menggabungkan ke aliran yang dapat diamati adalah CombineLatest. Ini akan diaktifkan ketika salah satu diperbarui dengan nilai terakhir di setiap aliran.

Kanal 9 video di Kombinasikan Terbaru


-1
2017-07-16 18:11