问题描述
大家好,
背景信息:我有一个应用程序,在其中我不断通过串行端口向微控制器发送命令,并处理来自串行端口的响应.在此过程中,我在主窗体上获取并设置了各种控件属性.
当我启动此主进程时,我无法单击主表单上的任何按钮,也无法选中/取消选中任何复选框等.我猜这是因为所有内容都在单个线程上运行...?
因此,现在我创建了一个单独的线程来运行此过程,但是我仍然需要从主窗体上的控件中更新并获取信息.
我的问题是:我是否需要为我在主窗体上的控件上执行的每个动作创建一个委托"功能,或者是否有其他方法可以做到这一点?我在主窗体上做了很多工作,因此将涉及创建很多委托函数.
任何帮助将不胜感激.
谢谢
新手安德烈:)
这是一些代码来说明:
HI All,
Background info: I have an application where I continually send commands to a microcontroller via a serial port and processing the responses from the Serial port. I get and set various control properties on the main form during this process.
When I start this main process I cannot click any buttons on the main form or check/uncheck any checkboxes etc etc. I guess this is because everything runs on a single thread...?
So now I created a seperate thread to run this process in but I still need to update and get info from controls on the main Form.
My question is: Do I need to create a "Delegate" function for each action I perform on a control on the main Form or is there some other way of doing this. There is quite a lot of stuff I do on the main Form so it will involve creating a LOT of delegate functions.
Any help will be appreciated.
Thanks
Newbie Andre :)
Here is some code to illustrate:
protected void start_tests() //this method runs in its own thread
{
string input = string.Empty;
timer1.Enabled = false; // this would need delegate?
if (ResetFlag == true) //I guess this would need delegate
{
reset_selectedindex(); //delegate allready created
checkedListBox1.SelectedIndex = 0; //this would need delegate
ResetFlag = false; //I think this would need delegate
}
progressBar1.Maximum = checkedListBox1.CheckedItems.Count; //this needs delegate
progressBar1.Value = 0; //this needs delegate
while (checkedListBox1_selectedindex() < checkedListBox1_Items_Count()) //delegates used here
{
if (checkedListBox1.GetItemCheckState(checkedListBox1.SelectedIndex) == CheckState.Checked) //delegates needed here
{
UpdateText(checkedListBox1.SelectedItem.ToString() + "\n", UpdateType.TXdata,Color.Lime); //delegates needed here
progressBar1.Value++; //delegate needed here ....etc etc etc
try
{
show_message_box(checkedListBox1.SelectedIndex,PrePostCommand.precommand);
input = ExecCommand("TESTSEQ" + Convert.ToDecimal(checkedListBox1.SelectedIndex).ToString().PadLeft(2, '0') + "\r", 3000, "No responese from OVPT");
if (input.Contains("REQUEST"))
{
if (DialogResult.Yes == show_message_box(checkedListBox1.SelectedIndex,PrePostCommand.postcommand))
{
UpdateText("TEST:" + Convert.ToDecimal(checkedListBox1.SelectedIndex).ToString().PadLeft(2, '0') + " - " + checkedListBox1.SelectedItem.ToString() + "\r\n", UpdateType.MessageData, Color.Lime);
UpdateText("TEST PASS.", UpdateType.MessageData, Color.Lime);
}
else
{
UpdateText("TEST:" + Convert.ToDecimal(checkedListBox1.SelectedIndex).ToString().PadLeft(2, '0') + " - " + checkedListBox1.SelectedItem.ToString() + "\r\n", UpdateType.MessageData, Color.Red);
UpdateText("TEST FAIL.", UpdateType.MessageData, Color.Lime);
TestPass = false;
}
}
if (input.Contains("FAIL"))
{
UpdateText("TEST:" + Convert.ToDecimal(checkedListBox1.SelectedIndex).ToString().PadLeft(2, '0') + " - " + checkedListBox1.SelectedItem.ToString() + "\r\n", UpdateType.MessageData, Color.Red);
UpdateText(input, UpdateType.MessageData, Color.Red);
TestPass = false;
}
if (input.Contains("PASS"))
{
UpdateText("TEST:" + Convert.ToDecimal(checkedListBox1.SelectedIndex).ToString().PadLeft(2, '0') + " - " + checkedListBox1.SelectedItem.ToString() + "\r\n", UpdateType.MessageData, Color.Lime);
UpdateText(input, UpdateType.MessageData, Color.Lime);
}
}
catch (Exception e)
{
UpdateText(e.Message, UpdateType.MessageData,Color.Red);
TestPass = false;
}
}
if (checkedListBox1.SelectedIndex == (checkedListBox1.Items.Count - 1))
{
break;
}
checkedListBox1.SelectedIndex++;
}
if (TestPass == false)
{
label_Result.Text = "FAILED!!";
label_Result.BackColor = Color.Red;
label_Result.ImageIndex = 0;
}
else
{
label_Result.Text = "PASS!!";
label_Result.BackColor = Color.Lime;
label_Result.ImageIndex = 1;
}
if (checkBox3.Checked == true)
{
Thread.Sleep(100);
button2_Click_1(this, EventArgs.Empty);
Thread.Sleep(20);
//start_tests();
}
else
{
timer1.Enabled = true;
oThread.Abort();
}
}
推荐答案
context = SynchronizationContext.Current;
并使用此回调从线程中更新主表单的组件
and use this callback to update components of your main form from your thread
SendOrPostCallback callback = delegate(object obj)
{
//Update all the objects here which need delegate
checkedListBox1.SelectedIndex = 0; //no more need delegate
ResetFlag = false; //no more need delegate
};
context.Post(callback, null);
class TestRunner {
public event EventHandler<IntEventArgs> Completed;
public event EventHandler<IntEventArgs> Progress;
public event EventHandler<TestCaseEventArgs> CaseComplete;
public List<decimal> TestCases { get; set; }
public void RunTests(){
int fails = 0;
for(int i = 0; i < TestCases.Count; i++){
decimal d = TestCases[i];
input = ExecCommand("TESTSEQ" + d.ToString().PadLeft(2, ''0'') + "\r", 3000, "No responese from OVPT");
// ... etc
if(!TestPassed) fails++;
EventHandler<TestCaseEventArgs> completeHandler = CaseComplete;
if(null != completeHandler) completeHandler(this, new TestCaseEventArgs(i, d, TestPassed);
EventHandler<IntEventArgs> progressHandler = Progress;
if(null != progressHandler) progressHandler(this, new IntCaseEventArgs(i);
}
EventHandler<IntEventArgs> completedHandler = Completed;
if(null != completedHandler) completedHandler(this, new IntCaseEventArgs(fails);
}
public class TestCaseEventArgs: EventArgs {
public int Index { get; private set; }
public decimal Value { get; private set; }
public bool Passed { get; private set; }
public TestCompleteEventArgs(int index, decimal value, bool passed) { Index = index; Value = value; Passed = passed; }
}
}
public class IntEventArgs: EventArgs {
public int Value { get; private set; }
public TestCompleteEventArgs(int value) { Value = value; }
}
然后,您的主窗体应构造用于测试运行的输入数据并挂接事件.事件处理程序将需要使用Invoke或BeginInvoke,但这仅是3种方法.
Then your main form should construct the input data for the test run and hook the events. The event handlers will need to use Invoke or BeginInvoke, but that''s only 3 methods.
class MainForm {
// ...
TestRunner testRunner = new TestRunner();
private void StartTests(){
Thread t = new Thread(testRunner.RunTests);
SetControlState(false); // You''ll want to disable most of the UI when a test is running
// Set up the test cases
List<decimal> cases = new List<decimal>();
for(int i = 0; i < checkedListBox1.Items.Count; i++){
if(checkedListBox1.Items[i].Selected) cases.Add(i);
}
progressBar.MaxValue = cases.Count;
testRunner.TestCases = cases;
t.Start();
}
public MainForm(){
// some stuff already here
testRunner.Completed += TestComplete;
testRunner.Progress += TestProgress;
testRunner.CaseComplete += CaseComplete;
}
private void TestProgress(object sender, IntEventArgs e){
Invoke( () => progressBar.Value = e.Value );
}
private void CaseComplete(object sender, TestRunner.TestCaseEventArgs e){
Invoke ( () => {
// stuff to do in the UI for a case
});
}
private void TestComplete(object sender, IntEventArgs e){
Invoke( ()=> {
if (e.Value > 0)
{
label_Result.Text = "FAILED!!";
label_Result.BackColor = Color.Red;
label_Result.ImageIndex = 0;
}
else
{
label_Result.Text = "PASS!!";
label_Result.BackColor = Color.Lime;
label_Result.ImageIndex = 1;
}
SetControlState(true);
} );
void SetControlState(bool state){
// Set various controls to enabled or disabled in here
}
}
(如果您不使用.Net 4,则必须使用适当的方法或匿名委托进行调用,而不是前一阵子显示的那整齐的lambda技巧.)
可能有一个用于测试运行程序的BackgroundWorkerThread,它报告进度和完成情况,但是我不确定它会带来很多好处(这里的线程类非常简单).
(If you''re not using .Net 4 you''ll have to Invoke on a proper method or anonymous delegate, instead of this rather neat lambda trick I was shown a while back.)
It''s probably possible to have a BackgroundWorkerThread for the test runner, which reports progress and completion, but I''m not sure it gains a lot (the thread class is pretty simple here).
这篇关于跨线程操作-新手问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!