【问题标题】:Busy indicator not showing in async method异步方法中未显示忙碌指示符
【发布时间】:2018-06-18 07:20:59
【问题描述】:

我正在使用 Extended WPF Toolkit 和 MVVM Light 库。

我想实现 WPF 工具包繁忙指示器并定期通知用户一些信息(与视图模型中的 BusyMessage 属性绑定)。

但是,当单击“开始”按钮时,忙碌指示器(IsBusy 绑定到 viewmodel 中的 IsBusy 属性)不显示。我做错了什么? 奇怪的是,当在视图模型的构造函数中将 IsBusy 设置为 true 时,它​​会起作用。

App.xaml

public partial class App : Application
{
    public App()
    {
        DispatcherHelper.Initialize();
    }
}

窗口

<Window xmlns:xctk='http://schemas.xceed.com/wpf/xaml/toolkit'
    DataContext='{Binding Main, Source={StaticResource Locator}}'>
 <StackPanel>
 <xctk:BusyIndicator IsBusy='{Binding IsBusy}'>
  <xctk:BusyIndicator.BusyContentTemplate>
    <DataTemplate>
      <StackPanel Margin='4'>
        <TextBlock Text='{Binding DataContext.BusyMessage, RelativeSource={RelativeSource AncestorType={x:Type Window}}}' />
      </StackPanel>
    </DataTemplate>
  </xctk:BusyIndicator.BusyContentTemplate>      
<Button Content='Start ...'
        Command='{Binding StartCommand}'
        HorizontalAlignment='Center'
        VerticalAlignment='Center' />
</xctk:BusyIndicator>

视图模型

public class MainViewModel : ViewModelBase
{
    private string _busyMessage;

    public string BusyMessage
    {
        get { return _busyMessage; }
        set
        {
            if (_busyMessage != value)
            {
                _busyMessage = value;
                RaisePropertyChanged(nameof(_busyMessage));
            }
        }
    }

    private bool _isBusy;

    public bool IsBusy
    {
        get { return _isBusy; }
        set {
            if (_isBusy != value)
            {
                _isBusy = value;
                RaisePropertyChanged(nameof(_isBusy));
            }
        }
    }

    public RelayCommand StartCommand
    {
        get { return new RelayCommand(() => StartExecute()); }
    }


    private async void StartExecute()
    {
        IsBusy = true;
        await Task.Run(() =>
        {
            //update UI from worker thread
            DispatcherHelper.CheckBeginInvokeOnUI(() => BusyMessage = "Work 1 Done");
            Thread.Sleep(1000);
            //update UI from worker thread
            DispatcherHelper.CheckBeginInvokeOnUI(() => BusyMessage = "Work 2 Done");
        });
        IsBusy = false;
    }

    public MainViewModel()
    {
        //Works when boolean is set to 'true' in constructor
        //IsBusy = true;
    }
}

【问题讨论】:

  • 根据经验,不要在事件处理程序之外使用 async void;返回一个任务,以便可以正确等待该方法。见stackoverflow.com/questions/12144077/…
  • @AlexPaven 更好的代码应该是 public RelayCommand StartCommand { get { return new RelayCommand(async() => await StartExecute()); } }。对吗?
  • async lambdas 有自己的缺陷,应该首先仔细研究(在某些方面它们相当于 async void)。我更喜欢创建一个单独的具有更好异步支持的 RelayCommand。见stackoverflow.com/questions/32591462/… - 我早上没有喝咖啡,所以我可能会混淆。

标签: c# wpf mvvm xceed-plus-edition


【解决方案1】:

这正是我更喜欢ReactiveUI 的原因——它在 ReactiveCommand 中内置了“忙碌指示器”,甚至是异步的。

至于你的问题,我想说你的RaisePropertyChanged(nameof(_isBusy));错了,应该是RaisePropertyChanged(nameof(IsBusy)); // name of the public property

此外,根据您的 RaisePropertyChanged 实现,您可以适当地将参数留空并使用 RaisePropertyChanged();

【讨论】:

    猜你喜欢
    • 2014-10-04
    • 2015-08-04
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多