C# 使用BackgroundWorker时逐个处理datagrid WPF中的项

C# 使用BackgroundWorker时逐个处理datagrid WPF中的项,c#,wpf,C#,Wpf,我想一个接一个地处理项目,处理datagrid元素中的每个项目 我有一个创建后台工作程序的方法: internal void Run(Action doWork, Action completed, Action loadingBeforeAction = null, Action loadingAfterAction = null) { using (BackgroundWorker worker = new BackgroundWorker()) { work

我想一个接一个地处理项目,处理datagrid元素中的每个项目

我有一个创建后台工作程序的方法:

internal void Run(Action doWork, Action completed, Action loadingBeforeAction = null, Action loadingAfterAction = null)
{
    using (BackgroundWorker worker = new BackgroundWorker())
    {
        worker.DoWork += (s, ev) =>
        {
            if (loadingBeforeAction != null)
            {
                _dispatcher.Invoke(loadingBeforeAction);
            }

            doWork();
        };

        worker.RunWorkerCompleted += (s, ev) =>
        {
            if (loadingAfterAction != null)
            {
                _dispatcher.Invoke(loadingAfterAction);
            }

            completed();
        };

        worker.RunWorkerAsync();
    }
}
现在处理datagrid中的选定项:

var folders = btn.Name.Equals("test") 
    ? _model.Folders.ToArray()
    : fileDataGrid.SelectedItems.Cast<FolderStatus>().ToArray();"
似乎所有项目都是同时处理的,并且处理从文本到其他文本的消息flick取决于
\u model.message
text


如何在不阻塞用户界面的情况下逐个处理项目?

BackgroundWorker
是Windows窗体中的一个遗留组件。您不应该在WPF应用程序中使用它。它会起作用,但是有更好的方法来实现你想要的

最简单的方法是使用TAP(基于任务的异步编程)模式,该模式由
async
wait
C#关键字支持

如果您的目标至少是.NETFramework4.5或.NETCore,那么一切都是现成的。对于.NETFramework4.0,有一些NuGet软件包可以启用此功能

实现可以如下所示:

async void MyButtonClick(object sender, RoutedEventArgs e)
{
    var btn = (Button)sender;

    var folders = btn.Name.Equals("test") 
        ? _model.Folders.ToArray()
        : fileDataGrid.SelectedItems.Cast<FolderStatus>().ToArray();"

    foreach (var folder in folders)
    {
        // This will be executed on the UI thread
        _model.Message = $"This is message for {folder.Name}"};
        _model.IsBusy = true;

        // This will be executed on a worker thread due to Task.Run
        await Task.Run(() => YourLongRunningOperation(folder));

        await Task.Run(() => SomeOtherLongRunningOperation());

        // This will be executed again on the UI thread
        _model.IsBusy = false;
    }
}
async void MyButton单击(对象发送方,路由目标)
{
变量btn=(按钮)发送器;
var folders=btn.Name.Equals(“测试”)
?_model.Folders.ToArray()
:fileDataGrid.SelectedItems.Cast().ToArray();“
foreach(文件夹中的var文件夹)
{
//这将在UI线程上执行
_model.Message=$“这是{folder.Name}”的消息;
_model.IsBusy=true;
//由于Task.Run,这将在工作线程上执行
等待任务。运行(()=>YourLongRunningOperation(文件夹));
等待任务。运行(()=>SomeOtherLongRunningOperation());
//这将在UI线程上再次执行
_model.IsBusy=false;
}
}
几点注意:

  • 上面的方法有一个签名
    async void(object,EventArgs)
    。但是,
    async
    方法应返回
    任务
    任务
    异步无效
    用于使事件处理程序
    异步
    。这是您应该使用
    异步无效
    UI事件处理程序的唯一情况。请注意,
    异步无效
    UI事件处理程序中存在未捕获的异常我会使你的应用程序崩溃
  • wait Task.Run()
    返回时,线程上下文将恢复为原始上下文。因此,您的
    \u model.IsBusy=false
    代码将再次在UI线程上执行。如果不需要,请使用
    wait Task.Run().configurewait(false)
请阅读更多有关该网站的信息


这里还有一个问题。

为什么不使用tasks和async await?关于task await,我无法更改
\u模型。IsBusy
(意味着UI端没有任何事情发生)在
任务内部。运行
即使我使用
调度程序。调用
…这就是我使用
BackgroundWorker
@Snakees的原因是,不要使用
调度程序。在
任务内部调用
运行
。我提供的示例应该可以正常工作。如果没有,那么你的其他代码中就有错误。我喜欢:
加载+=DoLoad;
异步void DoLoad(…){wait Task.Run(()=>{u model.IsBusy=false;});
,什么都没有happens@SnakeEyes,不,这是错误的。不要设置
\u模型。我在
任务中忙
。运行
。你仔细阅读了我的答案吗?请复制粘贴我提供的方法,并用你的方法替换
你的长时间运行操作。
async void MyButtonClick(object sender, RoutedEventArgs e)
{
    var btn = (Button)sender;

    var folders = btn.Name.Equals("test") 
        ? _model.Folders.ToArray()
        : fileDataGrid.SelectedItems.Cast<FolderStatus>().ToArray();"

    foreach (var folder in folders)
    {
        // This will be executed on the UI thread
        _model.Message = $"This is message for {folder.Name}"};
        _model.IsBusy = true;

        // This will be executed on a worker thread due to Task.Run
        await Task.Run(() => YourLongRunningOperation(folder));

        await Task.Run(() => SomeOtherLongRunningOperation());

        // This will be executed again on the UI thread
        _model.IsBusy = false;
    }
}