中继命令可以执行和任务

FPG*_*PGA 11 c# .net-4.0 task mvvm icommand

我想在调用relay命令时启动任务,但是只要该任务正在运行,我想禁用该按钮

举个例子

private ICommand update;
public ICommand Update
        {
            get
            {
                if (update == null)
                {
                    update = new RelayCommand(
                        param => Task.Factory.StartNew(()=> StartUpdate()),
                        param => true); //true means the button will always be enabled
                }
                return update;
            }
        }
Run Code Online (Sandbox Code Playgroud)

检查该任务是否正在运行的最佳方法是什么?

这是我的解决方案,但不确定它是否是最佳方式

class Vm : ObservableObject 
    {

        Task T;
        public Vm()
        {
            T = new Task(() => doStuff());
        }

        private ICommand myCommand;
        public ICommand MyCommand
        {
            get { return myCommand ?? (myCommand = new RelayCommand( p => { T = new Task(() => doStuff()); T.Start(); }, p => T.Status != TaskStatus.Running)); }
        }


        private void doStuff()
        {
            System.Threading.Thread.Sleep(5000);
        }

    }
Run Code Online (Sandbox Code Playgroud)

更新:这里的每个答案都运行正常,但他们仍然不同意,我刚刚达到100声誉,每当我达到100时我都会开始赏金,所以我要找的是一个优化非内存泄漏异步的实现在.net 4.0中的任务中执行的RelayCommand

Ste*_*ary 22

我强烈建议您避免new TaskTask.Factory.StartNew.在后台线程上启动异步任务的正确方法是Task.Run.

您可以RelayCommand使用此模式轻松创建异步:

private bool updateInProgress;
private ICommand update;
public ICommand Update
{
  get
  {
    if (update == null)
    {
      update = new RelayCommand(
          async () =>
          {
            updateInProgress = true;
            Update.RaiseCanExecuteChanged();

            await Task.Run(() => StartUpdate());

            updateInProgress = false;
            Update.RaiseCanExecuteChanged();
          },
          () => !updateInProgress);
    }
    return update;
  }
}
Run Code Online (Sandbox Code Playgroud)


Vla*_*aev 8

我想,你可以使用AsyncCommand的这个实现.

public class AsyncCommand : ICommand, IDisposable
{
    private readonly BackgroundWorker _backgroundWorker = new BackgroundWorker {WorkerSupportsCancellation = true};
    private readonly Func<bool> _canExecute;

    public AsyncCommand(Action action, Func<bool> canExecute = null, Action<object> completed = null,
                        Action<Exception> error = null)
    {
        _backgroundWorker.DoWork += (s, e) =>
            {
                CommandManager.InvalidateRequerySuggested();
                action();
            };

        _backgroundWorker.RunWorkerCompleted += (s, e) =>
            {
                if (completed != null && e.Error == null)
                    completed(e.Result);

                if (error != null && e.Error != null)
                    error(e.Error);

                CommandManager.InvalidateRequerySuggested();
            };

        _canExecute = canExecute;
    }

    public void Cancel()
    {
        if (_backgroundWorker.IsBusy)
            _backgroundWorker.CancelAsync();
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null
                   ? !_backgroundWorker.IsBusy
                   : !_backgroundWorker.IsBusy && _canExecute();
    }

    public void Execute(object parameter)
    {
        _backgroundWorker.RunWorkerAsync();
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_backgroundWorker != null)
                _backgroundWorker.Dispose();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)