Использование Rx в Silverlight для вызовов WCF не работает с TakeUntil - PullRequest
3 голосов
/ 20 января 2011

У меня есть следующий бит кода для настройки моих подключений Rx:

Определения, связанные с событием:

    public class QueryEventArgs : EventArgs
    {
        public SomeParametersType SomeParameters
        {
            get;
            set;
        }

        public object QueryContext
        {
                     get;
            set;
        }
    };

    public delegate void QueryDelegate(object sender, QueryEventArgs e);

    public event QueryDelegate QueryEvent;

Инициализация:

            queryObservable = Observable.FromEvent<QueryEventArgs>(this, "QueryEvent");
            queryObservable.Subscribe((e) =>
            {
                tbQueryProgress.Text = "Querying... ";
                client.QueryAsync(e.EventArgs.SomeParameters, e.EventArgs.QueryContext);
            });

            queryCompletedObservable = from e in Observable.FromEvent<QueryCompletedEventArgs>(client, "QueryCompleted").TakeUntil(queryObservable) select e;

            queryCompletedObservable.Subscribe((e) =>
                {
                    tbQueryProgress.Text = "Ready";
                    SilverlightClientService_QueryCompleted(e.Sender, e.EventArgs);
                },
                (Exception ex) =>
                {
                    SetError("Query error: " + ex);
                }
            );

«клиент» - это клиент WCF, а все остальное довольно очевидно.

«TakeUntil» предназначен для того, чтобы пользователь не давил себе, когда выполняет новый запрос, находясь в середине текущего запроса. Однако, хотя код работает, если я удаляю предложение TakeUntil, если я его вставляю, запрос никогда не завершается.

Это правильный шаблон? Если так, я делаю что-то не так?

Ура, -Tim

1 Ответ

3 голосов
/ 20 января 2011

TakeUntil прекращает подписку при получении значения из его аргумента, поэтому ваш первый queryObservable запускает запрос, но также прекращает подписку на завершенные события.

Более простое решение - настроитьIObservable вокруг вашего фактического запроса, а затем используйте Switch, чтобы убедиться, что одновременно выполняется только один запрос.

public static class ClientExtensions
{
    public static IObservable<QueryCompletedEventArgs> QueryObservable(
        this QueryClient client,
        object[] someParameters, object queryContext)
    {
       return Observable.CreateWithDisposable<QueryCompletedEventArgs>(observer =>
       {
            var subscription = Observable.FromEvent<QueryCompletedEventArgs>(
                    h => client.QueryCompleted += h,
                    h => client.QueryCompleted -= h
                )
                .Subscribe(observer);

            client.QueryAsync(someParameters, queryContext);

            return new CompositeDisposable(
                subscription,
                Disposable.Create(() => client.Abort())
            );
        });
    }
}

Тогда вы можете сделать это:

queryObservable = Observable.FromEvent<QueryEventArgs>(this, "QueryEvent");

queryObservable
    .Select(query => client.QueryObservable(
        query.EventArgs.SomeParameters, 
        query.EventArgs.QueryContext
    ))
    .Switch()
    .Subscribe(queryComplete =>
    {
        tbQueryProgress.Text = "Ready";
        // ... etc
    });

Это устанавливает один непрерывный поток, в результате чего каждое событие «Запрос» запускает запрос, который генерирует полное событие из этого запроса.Новые запросы автоматически отменяют предыдущий запрос (если возможно) и запускают новый.

...