将可见性绑定到任务状态

时间:2015-11-27 15:26:07

标签: c# wpf mvvm-light

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

查看:

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

视图模型:

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可见?

2 个答案:

答案 0 :(得分:1)

我强烈建议您将您的财产#barra{ float: left; margin-top: 0px; margin-bottom: 4%; width: 100%; } #logosw img{ position: relative; float: left; margin-right: 4%; width: auto; height: same as #textsw; } #textsw{ float: right; width: calc(100% - #logosw); height: 100% of the text; } 重命名为TaskRunning,因为最好将IsBusy个变量命名为前缀bool

你应该在你的属性TaskRunning中设置setter来设置is值:

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;); } ,因为WPF会自动将PropertyChanged event的参数分派给UI线程。

<强>更新

您的代码无效,因为您的媒体资源PropertyChanged event只是可读,而您无法设置TaskRunningtrue值。要为您的属性设置值,您应该添加setter并在为属性false设置新值时触发事件PropertyChanged:

TaskRunning

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

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

答案 1 :(得分:0)

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;
}