停止WPF

时间:2016-01-20 16:42:14

标签: c# wpf mvvm backgroundworker

我有WPF应用程序。

在页面上,我有像“{1}} PanelLoading

时显示的”忙碌指示符“
true

在这个页面上我还有其他控件(textBoxes,comboBoxes等)

对于ItemsSource,我绑定了一些值,如:

<Grid Panel.ZIndex="1000" HorizontalAlignment="Stretch" Grid.RowSpan="3" Visibility="{Binding PanelLoading, Converter={StaticResource BoolToVis}}">
        <controls:LoadingPanel x:Name="loadingPanel" VerticalAlignment="Stretch"
                    IsLoading="{Binding PanelLoading}"
                    Message="Wait"
                    SubMessage="a minute"
                               />
    </Grid>

在上面的示例中,每次在textBox中更改文本时,public string SearchWord { get { return _searchWord; } set { _searchWord = value; OnPropertyChanged("SearchWord"); RunFilterWorker(); } } 都会尝试运行。

RunFilterWorker是一种创建BW并运行它的方法。

RunFilterWorker

对于此BW,我在private void RunFilterWorker() { if (_filterWorker == null) { _filterWorker = CreateBackgroundWorker();//create if null (only on start) } else { if(_filterWorker.IsBusy)return; //do nothing if busy } _filterWorker.RunWorkerAsync(); } private BackgroundWorker CreateBackgroundWorker() { var bw = new BackgroundWorker(); bw.WorkerSupportsCancellation = true; bw.DoWork += filterWorker_DoWork; bw.RunWorkerCompleted += filterWorker_CompleteWork; return bw; } DoWork

上绑定处理程序
RunWorkerCompleted

因此,当BW开始工作时, private async void filterWorker_DoWork(object sender, DoWorkEventArgs e) { PanelLoading = true; var products = await FilterProducts(); e.Result = products; } private void filterWorker_CompleteWork(object sender, RunWorkerCompletedEventArgs e) { if (e.Error == null) { if (e.Cancelled) return; var products = (e.Result) as List<ProductDTO>; Products = products; PanelLoading = false; } else { LogHelper.Log(e.Error); } } 设置为PanelLoading并显示BusyIndi​​cator。但是在true上没有任何事情发生在指标上,它仍在旋转。我确信它不是指标控制的问题,而是BW。

致@Servy:

Complete

没有帮助,不隐藏指标。

2 个答案:

答案 0 :(得分:1)

如果BGW没有错误且未取消,您只能到达PanelLoading = false;行。但那不是你想要的行为。您希望加载面板不管BGW停止的原因,因此您的程序逻辑需要反映出来。

您需要做的就是将该行移动到已完成的处理程序的开头。

您还有另一个无关的问题。您正在将async与BackgroundWorker进行混合和匹配,而您确实不应该这样做。 BGW希望DoWork处理程序是同步方法。一旦完成处理程序的执行,它就会将自己标记为已完成,但您正在做的是让您的处理程序除了启动某些工作之外什么都不做,而且这项工作并非如此实际上直到处理程序结束很久才完成。因此,在BGW完成之后之前,您实际上并未设置结果。

由于您已经有Task返回的异步方法,并且您可以使用async,因此只需完全使用BGW进行裁剪。它在这里没有任何成就。制作RunFilterWorker async,让它处理任何抛出的错误,让它显示并隐藏加载面板等。

答案 1 :(得分:0)

BGW是一种非常过时的技术,正如Servy正确指出的那样,它根本不理解async。给它一个async DoWork只是要求麻烦(特别是,BGW在你预期之前就完成了)。

我有一个博客系列,展示如何Task.Run is superior to BGW,但在这种情况下,我会同意Servy你可能不需要BGW Task.Run。一个简单的Task就足够了:

Task _filterWorker;
private void RunFilterWorker()
{
  if (_filterWorker == null)
  {
    _filterWorker = FilterAsync();
  }
}

private Task FilterAsync()
{
  PanelLoading = true;
  try
  {
    Products = await FilterProducts();
  }
  catch (Exception ex)
  {
    LogHelper.Log(ex);
  }
  PanelLoading = false;

  // Ensure the calling method has set _filterWorker before we clear it.
  await Task.Yield();
  _filterWorker = null;
}