C# windows phone 7中的锁定异步方法

C# windows phone 7中的锁定异步方法,c#,windows-phone-7,locking,windows-phone,async-await,C#,Windows Phone 7,Locking,Windows Phone,Async Await,我使用自定义方法UploadDataToDropbboxAsync()将数据上传到按钮命令上的dropbox;我是这样用这个方法的 RelayCommand _navigateToDropBoxUploadCommand; public ICommand NavigateToDropBoxUploadCommand { get { return _navigateToDropBoxUploadCommand = _navi

我使用自定义方法UploadDataToDropbboxAsync()将数据上传到按钮命令上的dropbox;我是这样用这个方法的

 RelayCommand _navigateToDropBoxUploadCommand;
    public ICommand NavigateToDropBoxUploadCommand
    {
        get
        {
            return _navigateToDropBoxUploadCommand = _navigateToDropBoxUploadCommand ?? new RelayCommand(
                    async () =>
                    {
                        await UploadDataToDropbox("sandbox");
                    });
        }
    }
因此,当我在等待上传数据之前多次单击按钮时,thr是多个同时上传。 所以我想锁定这个方法,这样在第一次上传完成之前就不会再次调用它。
非常感谢您的帮助。

我不会为此使用锁定。首先,您只处理一个线程——UI线程(至少在锁定方面——因为您真正要求的是将UI线程从运行此命令中锁定)。另一方面,这是一个沉重的负担,相比之下,我们应该采取更好的方式来处理这个问题

我只需在异步之前禁用该按钮,然后再重新启用它。例如:

return _navigateToDropBoxUploadCommand = _navigateToDropBoxUploadCommand ?? new RelayCommand(
    async () =>
    {
        myButton.IsEnabled = false;
        await UploadDataToDropbox("sandbox");
        myButton.IsEnabled = true;
    });

但是,禁用按钮可能更好地在其他地方完成,这取决于您处理命令的方式等。。。(例如,如果您将此命令用于多个UI点击/点击事件)。

使用异步锁,可以创建上载队列,而不是同时上载:

private readonly AsyncLock _dropBoxUploadLock = new AsyncLock(); 

return _navigateToDropBoxUploadCommand = _navigateToDropBoxUploadCommand ?? new RelayCommand(
    async () =>
    {   
        var cachedStateFromUI = GetDataFromTheUI(...);
        using(var releaser = await _dropBoxUploadLock.LockAsync()) 
        {
            await UploadDataToDropbox(cachedStateFromUI);
        }
    });
使用的AsyncLock类来自Stephen Toub的示例

/*
*私有只读异步锁m_lock=新异步锁();
* … 
*使用(var releaser=wait m_lock.LockAsync())
* { 
*…//此处是受保护的代码
* }
*/
/// 
/// http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx
/// 
公共类异步锁
{
私有只读异步信号量m_信号量;
专用只读任务m_释放器;
公共异步锁()
{
m_信号量=新的异步信号量(1);
m_releaser=Task.FromResult(新releaser(this));
}
公共任务LockAsync()
{
var wait=m_信号量.WaitAsync();
返回等待。是否完成?
m_释放器:
wait.ContinueWith((_,state)=>newreleaser((异步锁)状态),
这是CancellationToken。无,
TaskContinuationOptions.ExecuteSynchronously,TaskScheduler.Default);
}
公共结构释放器:IDisposable
{
私有只读异步锁m_toRelease;
内部释放器(AsyncLock-toRelease){m_-toRelease=toRelease;}
公共空间处置()
{
if(m_toRelease!=null)
m_toRelease.m_semaphore.Release();
}
} 
}
异步锁取决于异步信号量

/*
*私有只读异步信号量m_lock=新异步信号量(1);
* … 
*等待m_lock.WaitAsync();
*试一试
* { 
*…//此处是受保护的代码
* }  
*最后{m_lock.Release();}
*/
/// 
/// http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266983.aspx
/// 
公共类异步信号量
{
private readonly static Task s_completed=Task.FromResult(true);
私有只读队列m_waiters=新队列();
私有整数m_currentCount;
公共异步信号量(int initialCount)
{
如果(initialCount<0)抛出新ArgumentOutOfRangeException(“initialCount”);
m_currentCount=初始计数;
}
公共任务WaitAsync()
{
锁(男服务员)
{
如果(m_currentCount>0)
{
--m_电流计数;
返回s_已完成;
}
其他的
{
var water=new TaskCompletionSource();
服务员排队(服务员);
返回服务员。任务;
}
}
}
公开无效释放()
{
TaskCompletionSource toRelease=null;
锁(男服务员)
{
如果(m_waiters.Count>0)
toRelease=m_waiters.Dequeue();
其他的
++m_电流计数;
}
if(toRelease!=null)
toRelease.SetResult(true);
}
}

peter我知道这种方法。但我只想找到一种合适的方法,可能不是锁定而是其他方法。由于它是手动处理的,我认为在asynv/Wait使用库中会有一些方法。感谢您的回复这是一种方法——简单地禁用UI的一部分,使其无法同时执行相同的操作。任何其他的“锁定”都会导致您的UI出现挂起状态,并造成糟糕的用户体验。绕过“挂起”外观的唯一方法是禁用按钮并绕过锁定…嗨@Peter,我读过关于AsyncLock的文章,发现它会锁定async方法,但它会将对该方法的调用放入队列,这肯定会是个问题。所以你的解决方案是正确的。恐怕这对wp7不起作用。我不记得具体是什么,但Bcl.Async中不存在某些内容。我想,等等。继续使用()-我不久前试过,但没有成功。
  /*
   * private readonly AsyncLock m_lock = new AsyncLock(); 
   * … 
   * using(var releaser = await m_lock.LockAsync()) 
   * { 
   *     … // protected code here 
   * }
   */

  /// <summary>
  /// http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx
  /// </summary>
  public class AsyncLock
  {
    private readonly AsyncSemaphore m_semaphore;
    private readonly Task<Releaser> m_releaser;

    public AsyncLock()
    {
      m_semaphore = new AsyncSemaphore(1);
      m_releaser = Task.FromResult(new Releaser(this));
    }

    public Task<Releaser> LockAsync()
    {
      var wait = m_semaphore.WaitAsync();
      return wait.IsCompleted ?
          m_releaser :
          wait.ContinueWith((_, state) => new Releaser((AsyncLock)state),
              this, CancellationToken.None,
              TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
    }

    public struct Releaser : IDisposable
    {
      private readonly AsyncLock m_toRelease;

      internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; }

      public void Dispose()
      {
        if (m_toRelease != null)
          m_toRelease.m_semaphore.Release();
      }
    } 
  }
  /*
   * private readonly AsyncSemaphore m_lock = new AsyncSemaphore(1); 
   * … 
   * await m_lock.WaitAsync(); 
   * try 
   * { 
   *     … // protected code here 
   * }  
   * finally { m_lock.Release(); }
   */

  /// <summary>
  /// http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266983.aspx
  /// </summary>
  public class AsyncSemaphore
  {
    private readonly static Task s_completed = Task.FromResult(true);
    private readonly Queue<TaskCompletionSource<bool>> m_waiters = new Queue<TaskCompletionSource<bool>>();
    private int m_currentCount;

    public AsyncSemaphore(int initialCount)
    {
      if (initialCount < 0) throw new ArgumentOutOfRangeException("initialCount");
      m_currentCount = initialCount;
    }

    public Task WaitAsync()
    {
      lock (m_waiters)
      {
        if (m_currentCount > 0)
        {
          --m_currentCount;
          return s_completed;
        }
        else
        {
          var waiter = new TaskCompletionSource<bool>();
          m_waiters.Enqueue(waiter);
          return waiter.Task;
        }
      }
    }

    public void Release()
    {
      TaskCompletionSource<bool> toRelease = null;
      lock (m_waiters)
      {
        if (m_waiters.Count > 0)
          toRelease = m_waiters.Dequeue();
        else
          ++m_currentCount;
      }
      if (toRelease != null)
        toRelease.SetResult(true);
    }
  }