我在上一个问题中询问过如何"Threading 2 forms to use simultaneously C#" 我现在意识到我不够明确,并且提出了错误的问题。
这是我的情景:
我有一些数据,我从本地服务器收到,我需要写入文件。
这些数据是以我无法控制的恒定时间速率发送的
我想要做的是为tcp流的初始设置创建一个winform,然后单击一个按钮开始读取tcp流并将其写入文件,同时启动另一个具有多个检查的winform-我需要检查已检查状态并将该信息同时添加到同一文件的框
当按下不同的按钮,关闭流,文件和第二个winform时,将停止此处理。 (此按钮位置对于任何winforms都不是特别强制的)。
由于这个取消按钮(在我尝试实现第二个表单之前),我使用后台工作程序能够异步取消用于读取流并写入文件的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#开始,所以请尽量在答案中提供一些简单的例子。
答案 0 :(得分:1)
首先使用一个Winform就够了吗?禁用所有复选框,单击启用复选框的按钮并开始读取tcpstream?如果您出于其他原因需要两份表格,请告诉我,但我认为这不是我在您的问题中所能看到的。
然后我建议你使用.Net的任务库。这是&#34;现代&#34;处理多线程的方法。 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);
}
}
这个片段应该可以解决问题。我没有测试它,所以可能会出现一些语法错误:P,但原理会起作用。
最重要的是你不能访问gui 另一个线程中的组件然后是gui线程。你试图访问 BackgroundWorker DoWork中的复选框是不可能的 并抛出异常。
所以我使用Progress-Object将我们在Tcp-Stream中获得的数据重用到主线程。在那里,我们可以访问复选框,构建我们的字符串并将其写入文件。有关BackgroundWorker与任务以及您可以找到的进度行为的更多信息here。
如果您有任何其他问题,请与我们联系。