本文介绍了跨线程操作-新手问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

背景信息:我有一个应用程序,在其中我不断通过串行端口向微控制器发送命令,并处理来自串行端口的响应.在此过程中,我在主窗体上获取并设置了各种控件属性.
当我启动此主进程时,我无法单击主表单上的任何按钮,也无法选中/取消选中任何复选框等.我猜这是因为所有内容都在单个线程上运行...?
因此,现在我创建了一个单独的线程来运行此过程,但是我仍然需要从主窗体上的控件中更新并获取信息.
我的问题是:我是否需要为我在主窗体上的控件上执行的每个动作创建一个委托"功能,或者是否有其他方法可以做到这一点?我在主窗体上做了很多工作,因此将涉及创建很多委托函数.

任何帮助将不胜感激.

谢谢
新手安德烈:)

这是一些代码来说明:

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).


这篇关于跨线程操作-新手问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 17:05
查看更多