【问题标题】:Using Rx in Silverlight for WCF calls doesn't work with TakeUntil在 Silverlight 中使用 Rx 进行 WCF 调用不适用于 TakeUntil
【发布时间】:2011-01-19 22:48:57
【问题描述】:

我有以下代码来设置我的 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);
                }
            );

“client”是 WCF 客户端,其他所有内容都非常不言自明。

“TakeUntil”用于阻止用户在当前正在运行的查询中执行新查询时踩踏自己。但是,如果我删除“TakeUntil”子句,代码可以工作,但如果我把它放进去,查询永远不会完成。

这是正确的模式吗?如果是这样,我是不是做错了什么?

干杯, -蒂姆

【问题讨论】:

    标签: silverlight wcf system.reactive


    【解决方案1】:

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

    这会设置一个连续的流程,每个“查询”事件都会启动一个查询,该查询会从该查询中发出完整的事件。新查询会自动终止前一个查询(如果可能)并开始一个新查询。

    【讨论】:

    • 非常感谢您的快速回答,但我不确定我是否理解您的警告...如果新查询使用“切换”终止先前的查询,您将如何获得一个案例是多个查询吗?
    • @Tim - 取消订阅“FromEvent”不会阻止引发事件,因此第一个查询中的“Complete”事件在完成时仍会引发。当您再次订阅完成时(对于第二个查询),您将收到来自第一个查询的完整信息,然后再次收到第二个查询。
    • @Tim - QueryAsync 的方法签名是什么?
    • @Tim - 我已经更新了示例,以便它调用Abort 以在启动新请求时阻止之前的查询请求。此外,我已将“已完成”事件订阅更新为强类型(没有对事件的字符串引用)
    • 非常感谢您的帮助。在我看到的示例中,我没有看到您正在做的事情的类型。QueryAsync 在我的原始消息中只采用“SomeParametersType”类型的单个参数。 Rx 令人困惑!我到了最后期限,所以我现在采用了一种更传统的方法——稍后再回到 Rx 并正确地做。
    猜你喜欢
    • 2019-03-26
    • 1970-01-01
    • 2016-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-01
    相关资源
    最近更新 更多