将可见性绑定到任务状态

本文关键字:任务 状态 绑定 可见性 | 更新日期: 2023-09-27 18:24:41

我将ProgressBar的可见性绑定到一个属性,该属性在运行特定任务时返回true:

视图:

<ProgressBar IsIndeterminate="True" 
             Visibility="{Binding TaskRunning, Converter={StaticResource boolToVisibilityConverter}}"/>

ViewModel:

private Task someTask;
private CancellationTokenSource cancellationTokenSource;
public bool TaskRunning
{
    get
    {
        return someTask!= null && someTask.Status == TaskStatus.Running;
    }
}
private void StartTaskHandler()
{
    someTask = Task.Run(new Action(() =>
    {
         // Simulate some work
         cancellationTokenSource.Token.WaitHandle.WaitOne(10000);
    }), cancellationTokenSource.Token);
    someTask.ContinueWith((task) => RaisePropertyChanged("TaskRunning"));
    RaisePropertyChanged("TaskRunning");
}

执行StartTaskHandler时,ProgressBar有时只会变为可见。为什么?如何确保ProgressBar在任务运行时可见?

将可见性绑定到任务状态

我强烈建议您将属性TaskRunning重命名为IsBusy,因为最好使用前缀is命名bool变量。

您应该在属性TaskRunning中设置setter来设置true值:

private bool _isBusy;
public bool IsBusy
{
  get { return _isBusy; }
  set
    {
       _isBusy = value;
       RaisePropertyChanged("IsBusy");
    }
}

和你的代码:

private void StartTaskHandler()
{
   IsBusy=true;
   someTask = Task.Run(new Action(() =>
   {
       // Simulate some work
       cancellationTokenSource.Token.WaitHandle.WaitOne(10000);
   }), cancellationTokenSource.Token);
   someTask.ContinueWith((task) => IsBusy=false;);       
}

您可以从任何线程引发PropertyChanged event,因为WPF会自动将PropertyChanged event的参数分派到UI线程。

更新:

您的代码不起作用,因为属性TaskRunning只是可读的,并且不能设置truefalse值。要为属性设置值,您应该添加setter,并在为属性TaskRunning:设置新值时激发事件PropertyChanged

private bool _taskRunning;
public bool TaskRunning
{
  get
    {
        if(someTask!= null && someTask.Status == TaskStatus.Running)
           _taskRunning=true;
       return _taskRunning;
    }
  set
    {
       _taskRunning=value;
       RaisePropertyChanged("TaskRunning");
    }
}

这行代码只是用当前值(而不是新值)触发事件:

someTask.ContinueWith((task) => RaisePropertyChanged("TaskRunning"));

但是这一行代码将设置属性TaskRunning的新值,并触发事件PropertyChanged来更新您的UI:

someTask.ContinueWith((task) => TaskRunning=true;);

someTask.Status有时可能仍然是TaskStatus.WaitingToRun。添加此项将解决问题。但最好使用async/await:

private bool isBusy = false;
public bool IsBusy
{
    get
    {
        return isBusy;
    }
    set
    {
        isBusy = value;
        RaisePropertyChanged("IsBusy");
    }
}
private async void StartTaskHandler()
{
    cancellationTokenSource = new CancellationTokenSource();
    IsBusy = true;
    someTask = Task.Run(new Action(() =>
    {
        // Simulate some work
        cancellationTokenSource.Token.WaitHandle.WaitOne(10000);
    }), cancellationTokenSource.Token);
    await someTask;
    IsBusy = false;
}