2015-05-20 13 views
6

Tôi có một quan sát mà tôi sử dụng để hiển thị một hộp thoại xác nhận, khoảng ký:Hiển thị một Chứng nhận trên cửa sổ gần một cách phản ứng

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

Điều này cho thấy người sử dụng hộp thoại, với một yes/no nút kết hợp.

Trong cửa sổ chính của tôi, tôi truy cập vào lễ bế mạc như vậy:

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

Tôi muốn để có thể:

  1. Hiển thị hộp thoại xác nhận khi đóng hoả hoạn quan sát
  2. Đặt thuộc tính CancelEventArgs.Cancel thành true nếu người dùng nhấp vào nút "không".

tôi đã cố gắng thẳng lên đăng ký:

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

Nhưng đó bị treo vì Wait() cuộc gọi, tôi cũng đã thử một biến thể async:

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

Đó là không có tốt, bởi vì nó chỉ trở lại ngay lập tức.

Những gì tôi thực sự muốn làm là một cái gì đó như:

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

Nhưng điều đó không tồn tại, tôi biết chìa khóa ở đây là làm thế nào tôi kết hợp hai quan sát, nhưng tôi không có ý tưởng làm thế nào để làm như vậy, và các tài liệu hướng dẫn là một chút ánh sáng trên các ví dụ thực tế.

Trả lời

2

Bạn cần để ngăn chặn việc xử lý sự kiện bế mạc, do đó async (hoặc Rx thao tác) sẽ không giúp bạn nhiều ở đây.

Nhưng bạn cũng cần chặn nó theo cách mà các sự kiện giao diện người dùng vẫn được xử lý, do đó giao diện người dùng không bị đóng băng.

Các giải pháp phổ biến nhất để đó là sử dụng Window.ShowDialog thay vì Show, và mã này hoạt động:

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

Nhưng sử dụng trong phương pháp ShowDialog Rx của bạn sẽ làm cho khối gọi đăng ký của mình, và đó là khó xảy ra những gì bạn muốn (đối với các trường hợp khác, trong trường hợp này là những gì bạn cần).

Hoặc bạn có thể chạy một vòng lặp điều phối bên trong, như thế này:

 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); 
     }); 

Điều đó sẽ chỉ làm việc nếu Dispatcher tương tự được sử dụng bởi cả hai cửa sổ.

EDIT:

Ngoài ra, bạn có thể tránh được ngăn chặn bằng cách luôn luôn hủy gần, và đóng cửa dưới hình thức bản thân sau, đó là có thể nhiều hơn Rx chiều, tức là .:

 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()); 
-1

Cách tốt nhất để kết hợp với các luồng có thể quan sát là CombineLatest. Điều này sẽ kích hoạt khi một trong hai được cập nhật với giá trị cuối cùng trong mỗi luồng.

Channel 9 video on Combine Latest

Các vấn đề liên quan