2013-05-07 49 views
2

我有一个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。我有一个想法是使用2个字段; isUserLoadingisOtherDataLoading,并确保在将Busy设置为false之前两者均为false。

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

+0

我一直在使用一个数字计数器(其中您的异步调用将递增/递减)与像布尔忙属性{获得{ return _count!= 0; }}。我很好奇看到别人推荐。 – mztan 2013-05-07 00:34:52

回答

2

如果你有两个布尔值,_isUserLoading_isOtherDataLoading,您在load方法更新,那么你可以改变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

+0

我必须担心Busy属性上的锁吗? – 2013-05-07 00:53:11

+0

我如何处理notifproroperty?我编辑了我的问题 – 2013-05-07 00:55:00

+0

查看我的编辑,上面有一种方法可以包含RaisePropertyChanged调用 – joshuahealy 2013-05-07 02:05:44

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()); 
+0

如果可以修改API,还可以显示版本吗? – 2013-05-07 04:21:13

+0

您可以使用类似的技术,但更多地嵌入在API中 – Polity 2013-05-07 11:59:25