Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 执行后台操作时无法访问AbortButton_C#_Multithreading_Backgroundworker - Fatal编程技术网

C# 执行后台操作时无法访问AbortButton

C# 执行后台操作时无法访问AbortButton,c#,multithreading,backgroundworker,C#,Multithreading,Backgroundworker,我的要求是需要在单击alertbox(附图)中的abort按钮时中止backgroundworker操作。因为GetData()将需要更多的时间来执行 如果调用Dowork方法,则无需访问UI元素,这意味着我们需要限制它,直到backgroundworker完成。如果我删除了(Application.current.dispatcher)行,我们可以访问UI元素并执行一些操作,但我们需要在执行dowork事件时限制它 任何解决办法 try { v

我的要求是需要在单击alertbox(附图)中的abort按钮时中止backgroundworker操作。因为GetData()将需要更多的时间来执行

如果调用Dowork方法,则无需访问UI元素,这意味着我们需要限制它,直到backgroundworker完成。如果我删除了(Application.current.dispatcher)行,我们可以访问UI元素并执行一些操作,但我们需要在执行dowork事件时限制它

任何解决办法

     try
        {
            var backGroundWorker = new CancelSupportedBackgroundWorker { WorkerSupportsCancellation = true };
            CancellationTokenSource source = new CancellationTokenSource();
            var alertBox = new AlertBox
            {
                IsBusy = true,
                WaitingText ="Export Data"
                WaitingHeaderText ="Exporting"
            };
            alertBox.AbortButton.Click += (obj, args) =>
            {
                source.Cancel();
                backGroundWorker.CancelAsync();
                backGroundWorker.Abort();
                backGroundWorker.Dispose();
                GC.Collect();
            };
            backGroundWorker.DoWork += (obj, args) =>                 
            {    
            Appliction.Current.Dispatcher.Invoke(DispatcherPriority.ApplicationIdle, new Action(
                delegate
                {
                    table = GetData((CancellationToken)args.Argument);

                    if (source.Token != default(CancellationToken))
                        if (source.Token.IsCancellationRequested)
                            return;
                    }));
             };
            backGroundWorker.RunWorkerCompleted += (obj, args) =>
            {
                alertBox.IsBusy = false;
            };
           backGroundWorker.RunWorkerAsync(source.Token);
        }
提前谢谢

我进行了编辑,将一个令牌参数传递给Dowork事件

明确的要求是:

1) 查询操作需要在后台运行

2) 我们无法访问其他UI元素,如文件菜单项

3) 执行查询时,仅访问alertbox中的中止按钮

如果单击“中止”按钮,它将自动取消后台操作

我使用Task.Run()方法进行了编辑

我对添加GetFullData()方法进行了更改


在更详细地查看了代码之后,您似乎不需要IProgress

如果您想调用另一个线程上的任何代码,您应该查看它,但根据问题,您只需要使用
Task.Run
&
CancellationToken

此代码采用名为
frmDoWork
的表单,带有两个按钮
cmdDoWork
cmdAbort

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsApplication1
{
    public partial class frmDoWork : Form
    {
        CancellationTokenSource cts = null;
        Task backgroundTask = null;

        public frmDoWork()
        {
            InitializeComponent();
        }

        private void WorkToDoInBackgroundThread(IProgress<int> progress, CancellationToken cancellationToken)
        {
            try
            {
                for (int i = 0; i < 10; i++)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    Task.Delay(1000).Wait(cancellationToken);
                    progress.Report(i);
                    System.Diagnostics.Debug.WriteLine($"{i} - {DateTime.Now}");
                }
            }
            catch(OperationCanceledException ex)
            {

            }

        }

        private void cmdDoWork_Click(object sender, EventArgs e)
        {
            cts = new CancellationTokenSource();
            Progress <int> prg= new Progress<int>(x => this.Text = $"Iteration - {x}");

            backgroundTask = Task.Run(()=> WorkToDoInBackgroundThread(prg, cts.Token));
        }

        private void cmdAbort_Click(object sender, EventArgs e)
        {
            cts?.Cancel();
        }
    }
}

是的,最后我在IshittesVisible属性的帮助下找到了解决方案,该属性用于返回某个部分的命中测试结果

感谢@Ashley Pillay的回复

      Window.isHitTestVisible = false;
      alertBox.AbortButton.Click += (obj, args) =>
        {
            Window.IsHitTestVisible = true;
            source.Cancel();
            backGroundWorker.CancelAsync();
            backGroundWorker.Abort();
            backGroundWorker.Dispose();
            GC.Collect();
        };
        backGroundWorker.DoWork += (obj, args) =>                 
        { 
                table = GetData((CancellationToken)args.Argument);

                if (source.Token != default(CancellationToken))
                    if (source.Token.IsCancellationRequested)
                        return;
         };
        backGroundWorker.RunWorkerCompleted += (obj, args) =>
        {
            Window.IsHitTestVisible = true;
            alertBox.IsBusy = false;
        };

我还尝试将Application.current.Dispatcher替换为Dispatcher.CurrentDispatcher。在这里,我可以访问其他UI元素。但我们需要限制这一点,因为执行dowork eventBackgroundWorker是一种非常古老的模式。Net中现在的首选模式是使用Task with IProgress来更新UI。我不需要更新UI。只想在后台执行某些操作时调用abort click事件。任何带有IProgress.IProgress的任务链接都不仅仅用于更新UI,它是一种更简单的模式,用于捕获创建进度实例的线程的上下文,并允许您注册在该线程上下文中运行的回调。创建一个Progress实例,传入调用中止单击事件处理程序的操作回调。然后将IProgress对象传递到Task.Run、Parallel.ForEach等中的回调中。当调用IProgress.Report时,您的回调在正确的上下文中运行。您将进行所有设置后台工作程序的工作,但随后立即使用
调度程序
,将其所有工作返回到UI线程上。不知道为什么。嗨@Ashley,我也按照你的代码使用相同的概念。在我的代码中,单击中止按钮,后台操作将被取消。当使用Application.current.Dispatcher行时,它不会被击中。这是我们的问题。无论如何,我会试试这个。我知道代码看起来很相似,但除非你处理的是写得很糟糕的遗留代码,你害怕被破坏,否则任务是现代的方法。如果你真的想继续使用BackgroundWorker,我建议你使用RunWorkerAsync的重载,它需要一个参数。您可以使用该对象传入需要在backGroundWorker.DoWork中调用的任何对象,并通过args参数访问它们。然后,您将不依赖于Application.Current.Dispatcher,因为对象将在后台线程中直接访问。我根据您的建议更改代码,将参数(Source.Token)传递给Dowork方法,但该方法未按预期工作。我尝试了Task.Run(),该方法也未按预期工作。通过未按预期工作,我想你的意思是当你点击按钮时不放弃。请发布您使用Task.Run尝试的代码。请注意,IshitteVisible基本上是告诉窗口忽略其客户端区域中的鼠标事件。窗口仍然可以接收键盘事件以及非客户端区域(边框)中的鼠标事件。用户可以单击“窗口”和“选项卡”来选择各种控件或选择菜单。此外,没有任何视觉指示表明控件不可用。它们看起来是可点击的,但只是忽略点击。设置IsEnabled可防止键盘和鼠标输入,也会使提供视觉反馈的子控件变灰,窗口无法与之连接。感谢@AshleyPillay,如果将IsEnabled设置为false,则可以正常工作。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsApplication1
{
    public partial class frmDoWork : Form
    {
        CancellationTokenSource cts = null;
        Task backgroundTask = null;

        public frmDoWork()
        {
            InitializeComponent();
        }

        private void WorkToDoInBackgroundThread(IProgress<int> progress, CancellationToken cancellationToken)
        {
            try
            {
                for (int i = 0; i < 10; i++)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    Task.Delay(1000).Wait(cancellationToken);
                    progress.Report(i);
                    System.Diagnostics.Debug.WriteLine($"{i} - {DateTime.Now}");
                }
            }
            catch(OperationCanceledException ex)
            {

            }

        }

        private void cmdDoWork_Click(object sender, EventArgs e)
        {
            cts = new CancellationTokenSource();
            Progress <int> prg= new Progress<int>(x => this.Text = $"Iteration - {x}");

            backgroundTask = Task.Run(()=> WorkToDoInBackgroundThread(prg, cts.Token));
        }

        private void cmdAbort_Click(object sender, EventArgs e)
        {
            cts?.Cancel();
        }
    }
}
{
    AlertBox alertBox = new AlertBox();
    alertBox.Owner = this;
    alertBox.Show();
    alertBox.Closed += (sender, e) => this.IsEnabled = true;
    this.IsEnabled = false;
}
      Window.isHitTestVisible = false;
      alertBox.AbortButton.Click += (obj, args) =>
        {
            Window.IsHitTestVisible = true;
            source.Cancel();
            backGroundWorker.CancelAsync();
            backGroundWorker.Abort();
            backGroundWorker.Dispose();
            GC.Collect();
        };
        backGroundWorker.DoWork += (obj, args) =>                 
        { 
                table = GetData((CancellationToken)args.Argument);

                if (source.Token != default(CancellationToken))
                    if (source.Token.IsCancellationRequested)
                        return;
         };
        backGroundWorker.RunWorkerCompleted += (obj, args) =>
        {
            Window.IsHitTestVisible = true;
            alertBox.IsBusy = false;
        };