C# 后台工作者追加文本框

首先,我想说我是 C# 的新手,所以我不太清楚后台工作人员应该如何实现。我有一个 GUI 程序,它基本上可以 ping 域并将响应返回到文本框。我能够让它正常工作,但是,它冻结了代码,因为它运行在同一个线程上,这就是我试图实现后台工作程序的原因。这是基本设置


private void button1_Click(object sender, EventArgs e)

{

    url = textBox1.Text;

    button1.Enabled = false;

    button2.Enabled = true;

    bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);

    bgWorker.RunWorkerAsync();


}

private void bgWorker_DoWork(object sender, DoWorkEventArgs e)

{

    do

    {

        if (bgWorker.CancellationPending)

            break;


        Invoke((MethodInvoker)delegate { monitor(); });


    } while (true);

}

public void monitor()

{

    textBox2.AppendText("Status of: " + url + "\n");

    Status(url);

    System.Threading.Thread.Sleep(30000);

}

private void Status(string url)

{

    // This method does all the ping work and also appends the status to the Text box as it goes through , as OK or down

}

我之前没有和 bgworkers 一起工作过,你可以想象这很令人困惑。我看过很多其他的文章,但似乎无法理解。对不起,如果代码看起来很疯狂,我正在努力学习。


冉冉说
浏览 181回答 3
3回答

鸿蒙传说

使用微软的反应框架(NuGet“System.Reactive.Windows.Forms”并添加using System.Reactive.Linq;),然后你可以这样做:private void button1_Click(object sender, EventArgs e){    var url = textBox1.Text;    Observable        .Interval(TimeSpan.FromMinutes(0.5))        .SelectMany(_ => Observable.Start(() => Status(url)))        .ObserveOn(this)        .Subscribe(status => textBox2.AppendText("Status of: " + status + "\n"));}然后,您只需要更改Status即可获得此签名:string Status(string url).就是这样。没有后台工作人员。没有调用。并且Status很好地在后台线程上运行。

BIG阳

你有几个错误。第一的,Invoke((MethodInvoker)delegate{    monitor();});将调用monitor()您的 UI 线程。在几乎所有情况下,您都不应该在其他线程上调用方法。您尤其不应该调用在 UI 线程上阻塞或执行任何需要超过几毫秒的操作的方法,这就是这样做的:System.Threading.Thread.Sleep(30000);而不是在另一个线程上调用方法;向另一个线程提交不可变数据并让线程决定何时处理它。BackgroundWorker 中已经内置了一个事件来执行此操作。在您致电之前,请bgWorker.RunWorkerAsync()执行以下操作:url = new Uri(something);bgWorker.WorkerReportsProgress = true;bgWorker.WorkerSupportsCancellation = true;bgWorker.ProgressChanged += Bgw_ProgressChanged;private void Bgw_ProgressChanged(object sender, ProgressChangedEventArgs e){    textBox2.AppendText("Status of: " + url + ": " + e.UserState.ToString()        + Environment.NewLine);}你bgWorker_DoWork应该看起来更像这样:void bgWorker_DoWork(object sender, DoWorkEventArgs e){    while (!bgw.CancellationPending)    {        System.Threading.Thread.Sleep(new TimeSpan(0, 0, 30));        var status = ResultOfPing(e.Argument as Uri);        bgw.ReportProgress(0, status);    }    e.Cancel = true;}你应该这样称呼它:bgWorker.RunWorkerAsync(url);你还有第二个问题。BackgroundWorker 创建一个线程,并且您的线程将花费大部分时间在计时器上阻塞或等待网络响应。这是对线程的不良使用。您最好使用完成回调或async/await。

天涯尽头无女友

试试这个代码:public partial class Form1 : Form{    bool cancel;    public Form1()    {        InitializeComponent();    }    public void StartPinging()    {        this.cancel = false;        startButton.Enabled = false;        stopButton.Enabled = true;        responseBox.Clear();        responseBox.AppendText("Starting to ping server.");        responseBox.AppendText(Environment.NewLine);        var bw = new BackgroundWorker        {            WorkerReportsProgress = false,            WorkerSupportsCancellation = true        };        bw.DoWork += (obj, ev) =>        {            while (!cancel)            {                // Ping Server Here                string response = Server.PingServer();                this.Invoke(new UiMethod(() =>                {                    responseBox.AppendText(response);                    responseBox.AppendText(Environment.NewLine);                }));            }        };        bw.RunWorkerCompleted += (obj, ev) =>        {            this.Invoke(new UiMethod(() =>            {                responseBox.AppendText("Stopped pinging the server.");                responseBox.AppendText(Environment.NewLine);                startButton.Enabled = true;                stopButton.Enabled = false;            }));        };        bw.RunWorkerAsync();    }    delegate void UiMethod();    private void startButton_Click(object sender, EventArgs e)    {        StartPinging();    }    private void stopButton_Click(object sender, EventArgs e)    {        responseBox.AppendText("Cancelation Pressed.");        responseBox.AppendText(Environment.NewLine);        cancel = true;    }}public class Server{    static Random rng = new Random();    public static string PingServer()    {        int time = 1200 + rng.Next(2400);        Thread.Sleep(time);        return $"{time} ms";    }}
打开App,查看更多内容
随时随地看视频慕课网APP