【问题标题】:Check multiple checkbox.checked state inside a do while cycle在 do while 循环中检查多个 checkbox.checked 状态
【发布时间】:2016-11-15 16:41:37
【问题描述】:

我在上一个问题中问过如何"Threading 2 forms to use simultaneously C#"
我现在意识到我不够明确并且问错了问题。

这是我的场景:
我有一些从本地服务器接收的数据,需要写入文件。 此数据以我无法控制的恒定时间速率发送。
我想做的是为tcp流的初始设置设置一个winform,然后单击一个按钮开始读取tcp流并将其写入文件,同时启动另一个带有多个检查的winform-我需要检查选中状态并将该信息同时添加到同一文件中的框。
此处理将在按下不同按钮时停止,关闭流、文件和第二个 winform。 (此按钮位置对于任何 winform 都不是特别强制的)。

由于这个取消按钮(在我尝试实现第二种形式之前),我使用后台工作程序能够异步取消用于读取流和写入文件的 do while 循环。

    private void bRecord_Click(object sender, EventArgs e)
    {
        System.IO.StreamWriter file = new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss") + ".xml", true);

        data_feed = client.GetStream();
        data_write = new StreamWriter(data_feed);
        data_write.Write("<SEND_DATA/>\r\n");
        data_write.Flush();

        exit_state = false;
        string behavior = null;

        //code to launch form2 with the checkboxes
        //...

        worker = new BackgroundWorker();
        worker.WorkerSupportsCancellation = true;

        worker.DoWork += new DoWorkEventHandler((state, args) =>
        {
            do
            {
                int var = data_feed.ReadByte();
                if (var != -1)
                {
                    data_in += (char)var;

                    if (data_in.IndexOf("\r\n") != -1)
                    {
                        //code to check the checkboxes state in form2
                        //if (form2.checkBox1.Checked) behavior = form2.checkBox1.Text;
                        //if (form2.checkBoxn.Checked) behavior = form2.checkBoxn.Text;  

                        file.WriteLine(data_in + behavior);
                        data_in = "";
                    }
                }
            }
            while (exit_state == false);
        });

        worker.RunWorkerAsync();
    }
    private void bStop_Click(object sender, EventArgs e)
    {
        exit_state = true;
        worker.CancelAsync();
    }

我希望我现在更清楚了。 我没有事件编程经验,刚开始使用 C#,所以如果可能,请尝试在答案中提供一些简单的示例。

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    一开始用一个Winform就够了吗?禁用所有复选框,单击启用复选框的按钮并开始读取 tcpstream?如果您出于其他原因需要两个表格,请告诉我,但我认为从您的问题中可以看出这不是必需的。

    那么我建议您使用 .Net 中的任务库。这是处理多线程的“现代”方式。 BackgroundWorker 有点老派。如果您只能在 .Net 2.0 上运行,则必须使用 BackgroundWorker,但似乎并非如此(示例如下)。

    此外,如果您想取消 BackgroundWorker 操作,这不仅仅是调用 CancelAsync();。您还需要处理e.Cancelled 标志。

    backgroundWorker.WorkerSupportsCancellation = true;
    
    private void CancelBW()
    {
       backgroundWorker.CancelAsync();
    }
    
    private void backgroundWorker_DoWork += ((sender, args)
    {
        //Handle the cancellation (in your case do this in your loop for sure)
        if (e.Cancelled) //Flag is true if someone call backgroundWorker.CancelAsync();
           return;
    
        //Do your stuff.
    });
    

    直接取消backgroundWorker没有常用方法 手术。你总是需要处理这个。

    现在让我们将您的代码更改为现代 TAP 模式并制作一些您想要的东西。

    private void MyForm : Form
    {
       private CancellationTokenSource ct;
    
       public MyForm()
       {
          InitializeComponent();
    
          checkbox1.Enable = false;
          //Disable all checkboxes here.
    
          ct = new CancellationTokenSource();
       }
    
       //Event if someone click your start button
       private void buttonStart_Click(object sender, EventArgs e)
       {
          //Enable all checkboxes here
    
          //This will be called if we get some progress from tcp
          var progress = new Progress<string>(value =>
          {
              //check the behaviour of the checkboxes and write to file
              file.WriteLine(value + behavior);           
          });
    
          Task.Factory.StartNew(() => ListenToTcp(ct, progress as IProgress<string)); //starts the tcp listening async
       }
    
       //Event if someone click your stop button
       private void buttonStop_Click(object sender, EventArgs e)
       {
          ct.Cancel();
          //Disable all checkboxes (better make a method for this :D)
       }
    
       private void ListenToTcp(CancellationToken ct, IProgess<string> progress)
       {
           do
           {
              if (ct.IsCancellationRequested)
                return;
    
              int temp = data_feed.ReadByte(); //replaced var => temp because var is keyword
              if (temp != -1)
              {
                data_in += (char)temp;
    
                if (data_in.IndexOf("\r\n") != -1)
                {
                   if (progress != null)
                     progress.Report(data_in); //Report the tcp-data to form thread
                   data_in = string.empty;                 
                }
            }
            while (exit_state == false);
       }
    }
    

    这个 sn-p 应该可以解决问题。我没有测试它,所以可能会出现一些语法错误:P,但原理会起作用。

    最重要的部分是你不能访问 gui 另一个线程中的组件然后是 gui 线程。您试图访问 BackgroundWorker DoWork 中的复选框,这是不可能的 并抛出异常。

    所以我使用 Progress-Object 来重用我们在 Tcp-Stream 中获得的数据,返回到主线程。在那里我们可以访问复选框,构建我们的字符串并将其写入文件。有关 BackgroundWorker 与 Task 和 Progress 行为的更多信息,您可以找到 here

    如果您还有其他问题,请告诉我。

    【讨论】:

    • private CancellationToken ct = new CancellationTokenSource(); 你的意思是private CancellationTokenSource ct = new CancellationTokenSource();,对吧? (这是唯一有效的语法)
    • 我尝试了您的代码,但我认为报告 incoming_data 没有传递整个流以写入文件。在文件中,这些行以随机方式不完整(一些,很少,是完整的)。知道为什么会这样吗?
    • @wmw301 1) 是的。 2)Umpf ...听起来像是线程同步的问题。请确保您的 progress.Report 方法在 data_in 变量可以使用时被调用。如果您将正确的字符串传递给 Report();这应该工作。不确定您在 while 循环中的代码是否完全正确,因为我不知道您的数据等。此外,可能会发生 Report();当第一次未打印到您的文件时,第二次执行。也许是因为它非常大,需要一些时间。但我认为情况并非如此。请先调试测试data_in是否正确。
    • 字符串 data_in 在循环中是正确的,但在这里被修剪:var progress = new Progress&lt;string&gt;(value =&gt; { file.WriteLine(data_in); }); 有时它是空白的,其他的字符很少,其他的只有最后一些字符消失了,还有 1或传递完整字符串的 2 次。
    • 没关系,这只是愚蠢的复制代码。我错过了file.WriteLine(value),这就是原因。 (现在好尴尬)
    猜你喜欢
    • 1970-01-01
    • 2021-12-14
    • 2023-03-20
    • 2020-10-13
    • 2022-10-14
    • 1970-01-01
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多