忙碌指示不起作用

时间:2016-06-21 16:04:42

标签: c# wpf xaml mvvm

我在Visual Studio 2015中构建MVVM Light WPF应用程序。它有一个用户控件,其中包含WindowsFormsHost,其中ReportViewer用于SQL Server Reporting Services本地报告。 ReportView.xaml中的按钮调用命令,该命令又将消息发送到MasterListView.xaml的代码隐藏以生成报告。

这是ReportViewModel.cs中按钮调用的命令:

public ICommand RunReportRelayCommand =>
    new RelayCommand(async ()=> { await RunReport(); });

private async Task RunReport()
{
    try
    {
        IsBusy = true;
        await Task.Run(() =>
        {
            Messenger.Default.Send(true, "RunMasterListReport");
        });
    }
    finally
    {
        IsBusy = false;
    }
}

以下是IsBusyReportViewModel.cs属性的定义:

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

包含调用上述命令的按钮的同一视图ReportView.xaml还包含以下Extended WPF Toolkit Busy Indicator:

<UserControl>
    <UserControl.Resources>
       <DataTemplate x:Key="MasterListViewTemplate">
          <view:MasterListView />
       </DataTemplate>
    </UserControl.Resources>
    <xctk:BusyIndicator IsBusy="{Binding IsBusy}">
        <StackPanel>
            <!-- Other XAML here -->
            <ContentControl ContentTemplate="{StaticResource MasterListViewTemplate}" />
        </StackPanel>
    </xctk:BusyIndicator>
</UserControl>

然后在MasterListView.cs代码隐藏中,我们有了这个:

public partial class MasterListView : UserControl
{
    public MasterListView()
    {
        InitializeComponent();
        Messenger.Default.Register<bool>(this, "RunMasterListReport", RunMasterListReport);
    }

    public async void RunMasterListReport(bool val)
    {         
        await Task.Run(() =>
        {
            var dataSet = new DrugComplianceDataSet();
            dataSet.BeginInit();
            ReportViewer.ProcessingMode = ProcessingMode.Local;
            ReportViewer.LocalReport.ShowDetailedSubreportMessages = true;
            ReportViewer.LocalReport.DataSources.Clear();
            var dataSource = new ReportDataSource
            {
                Name = "MasterListRandomDataSet",
                Value = dataSet.MasterListRandom
            };
            ReportViewer.LocalReport.DataSources.Add(dataSource);
            ReportViewer.LocalReport.ReportEmbeddedResource = "MasterListRandom.rdlc";
            dataSet.EndInit();
            var adapter = new MasterListRandomTableAdapter { ClearBeforeFill = true }
                .Fill(dataSet.MasterListRandom);
            Dispatcher.Invoke((MethodInvoker)(() => { ReportViewer.RefreshReport(); }));
        });
    }
}

但是,忙碌指示器不会触发,但报告确实会在5秒左右后显示。我究竟做错了什么?感谢。

1 个答案:

答案 0 :(得分:2)

那里有一整汤的汤。像

这样的事情
await Task.Run(() =>

建议您不要真正了解async / await是如何工作的。我下台找一些很好的文档来阅读。此外,您似乎正在UI线程上完成所有工作。

Dispatcher.Invoke((MethodInvoker)(() => { ReportViewer.RefreshReport(); }));

除非您正在更新UI,否则不应触及后台工作程序中的调度程序。您似乎正在卸载UI线程上后台线程(刷新报表)中您打算执行的实际工作。

也许您的报表查看器可以在UI线程中运行。如果是这样的话(可能它是在前一段时间设计的并且没有利用多任务处理),那么对于这种情况你无能为力。您的UI将在处理时被锁定。

如果所有长时间运行的工作必须在UI线程上运行,那么就去除所有废话。在开始工作之前,更新IsBusy,然后将ReportViewer.RefreshReport()的执行卸载到Dispatcher上,但使用低优先级DispatcherPriority,以便在UI更新后运行并显示它正忙。您的UI将在处理过程中被冻结,但至少您会向用户说明正在进行的操作。