Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to wait for IObservable<T> to complete without blocking UI with Reactive Extensions?
    primarykey
    data
    text
    <p>I'm trying to update a piece of code so that it simulates modal dialogs and Reactive Extensions felt like a proper tool to do so, but I can't make it work.</p> <p>Currently, the code looks something like this:</p> <pre><code>public bool ShowConfirmationDialogs(IEnumerable&lt;ItemType&gt; items) { bool canContinue = true; foreach (var item in items) { Dialog dialog = new Dialog(); dialog.Prepare(item); // Prepares a "dialog" specific to each item IObservable&lt;bool&gt; o = Service.ShowDialog(dialog, result =&gt; { // do stuff with result that may impact next iteration, e.g. canContinue = !result.Condition; }); // tried using the following line to wait for observable to complete // but it blocks the UI thread o.FirstOrDefault(); if (!canContinue) break; } if (!canContinue) { // do something that changes current object's state } return canContinue; } </code></pre> <p>Up until now, the code from the lambda expression was used to do stuff when the "dialog" shown by <code>ShowDialog</code> was closed. The call to <code>ShowDialog</code> is non blocking and used to return <code>void</code>.</p> <p>What happens behind the scenes in <code>ShowDialog</code> is that an object is added to an <code>ObservableCollection</code> so that it is shown on the screen.</p> <p>I modified <code>ShowDialog</code> so that it will return an <code>IObservable&lt;bool&gt;</code> who calls <code>OnCompleted</code> of its subscribers when the dialog is closed. This works. I tested it with the following code:</p> <pre><code>o.Subscribe(b =&gt; Console.WriteLine(b), () =&gt; Console.WriteLine("Completed")); </code></pre> <p>And I can see the string <code>"Completed"</code> when the dialog is closed. My problem is that the line above is non-blocking, so I can potentially display several dialogs, which I don't want to do.</p> <p>I tried the following:</p> <pre><code>o.FirstOrDefault(); </code></pre> <p>assuming that the program would wait there until the observable sent something or completed. The program blocks all right, but it also freezes the UI, which means I never see my dialog, which I can never close, so the observable never completes.</p> <p>I tried several variations using <code>ObserveOn</code> and <code>SubscribeOn</code> to try to leave the UI thread do its work, with no luck. Any ideas would be greatly appreciated, my main goal being to keep the code looking sequential, kind of like when using <code>Window.ShowDialog</code>.</p> <p><strong>To summarize:</strong> (and to answer Chris in the comments)</p> <p>The problem is that <code>ShowDialog</code> is non-blocking and, as stated above, the expected behavior is the same as when using <code>Window.ShowDialog</code>. Right now, I can either not block—but then the loop continues and I get several dialogs—or I can block (with <code>FirstOrDefault</code>), but it also blocks the UI, which prevents me from closing the dialog in order to complete the observable.</p> <p><strong>More explanations:</strong> (for Enigmativity)</p> <p>When I call <code>ShowDialog</code> a control is displayed that is modal—in the sense that it blocks the user from accessing the rest of the application—but the call to the method is non-blocking, so execution continues immediately. In my example, this can potentially display several dialogs because of the loop. The method is non-blocking because all it does is add an object to a collection and I can't change this behaviour.</p> <p>However, hoping to use Rx, I made it so that <code>ShowDialog</code> will return an <code>IObservable</code>. So now the method returns immediately, but I have an object that will call <code>OnCompleted</code> of any observers once the control that was displayed by <code>ShowDialog</code>'s actions is closed. I'm using a <code>Subject</code> for this, in case it matters.</p> <p>What I want now, is to wait for this returned <code>IObservable</code> to complete before moving on, and so simulate a blocking call. <code>FirstOrDefault</code> does the waiting part successfully, but unfortunately, it also blocks the UI thread, preventing the control from actually showing, thus preventing the user from closing it, thus preventing the <code>IObservable</code> from completing.</p> <p>I know my idea can't be far off, because I can get things to kind of work by closing the dialog automatically after <em>x</em> seconds. All I need now is for the "waiting" part not to block the UI so that the user can close the control instead of a timer.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload