繁忙指示器,用于多个异步调用

时间:2013-05-07 00:29:16

标签: c# silverlight windows-phone

我有一个Busy属性,在进行异步调用之前设置为true,然后在完成时设置为false。现在我有2个异步调用,我该如何处理这个逻辑?我是否需要锁定变量或其他一些我需要注意的并行问题?

private bool _busy;

public bool Busy
{
    get { return _busy; }
    set
    {
        bool changed = value != _busy;
        _busy = value;
        if (changed) RaisePropertyChanged("Busy");
    }
}

private void loadUser(int userId)
{
        Busy = true;
        api.GetUser(userId, CancellationToken.None).ContinueWith(t =>
                                      Deployment.Current.Dispatcher.BeginInvoke(() =>
                                      {
                                          Busy = false;
                                      }));

}

private void loadOtherData(int dataId)
{
        Busy = true;
        api.GetData(dataId, CancellationToken.None).ContinueWith(t =>
                                      Deployment.Current.Dispatcher.BeginInvoke(() =>
                                      {
                                          Busy = false;
                                      }));

}

我知道这个逻辑存在缺陷,因为Busy属性在第一个完成执行的方法上设置为false。我的想法是使用另外两个字段;在将isUserLoading设置为false之前,isOtherDataLoadingBusy并确保两者均为假。

我想知道是否有更好的方法来实现这一目标。

2 个答案:

答案 0 :(得分:2)

如果你有两个布尔值_isUserLoading_isOtherDataLoading,你在加载方法中更新,那么你可以将Busy更改为:

public bool busy
{
    get
    {
         return _isUserLoading || _isOtherDataLoading;
    }
}

包括对RaisePropertyChanged的调用的另一个版本可以这样工作:

public bool busy
{
    get
    {
         return _isUserLoading || _isOtherDataLoading;
    }
}

public bool IsUserLoading
{
    get
    {
         return _isUserLoading;
    }
    set
    {
       bool busy = Busy;
       _isUserLoading = value;
       if (busy != Busy) RaisePropertyChanged("Busy");
    }
}

当然是IsOtherDataLoading的类似属性。

答案 1 :(得分:0)

理想情况下,您希望从API中公开一个可观察的属性/事件,说明它何时繁忙。假设您无法进行任何修改,我建议您采用更通用的方法。像

这样的东西
class CountedContext {
    int workersCount  = 0;
    Action<bool> notifier;  

    public CountedContext(Action<bool> notifier) { this.notifier = notifier; }

    public Task<TResult> Execte<TResult>(Func<Task<TResult>> func)
    {   
        lock(worksersCount) 
        { 
            workersCount++; 

            if (workdersCount == 1)
                notifier(true);
        }

        var result = func();

        result.ContinueWith(_ => 
        {
            lock (worksersCount)
            {
                workersCount--;

                if (worksersCount == 0){
                    notifier(false);
                }
            }
        });

        return result;
    }
}

在您的主要课程中,您可以使用:

// constructor:
countedContext = new CountedContext(state => 
{
    ...BeginInvoke(() =>
    {
        Busy = state;
    });
});

...

// loadData
countedContext.Execute(() => api.GetData());