欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# 工控开发日记001:Winform报错_线程间操作无效

程序员文章站 2022-07-05 21:29:57
传送门原程序架构出现的问题解决思路总结原程序架构此程序有一功能是通过ListBox记录按钮操作,包含【Initialize】、【Disable】、【Read Volt】和【Keep Read】。其中【Initialize】、【Disable】、【Read Volt】按钮均是单次读取,并没有使用线程,所以能直接在按钮事件中对ListBox执行Iteam.Add()方法。如下举例Disable按钮的事件处理,应该很好理解。private void btnDisable_Click(object send...

原程序架构

此程序有一功能是通过ListBox记录按钮操作,包含【Initialize】、【Disable】、【Read Volt】和【Keep Read】。
其中【Initialize】、【Disable】、【Read Volt】按钮均是单次读取,并没有使用线程,所以能直接在按钮事件中对ListBox执行Iteam.Add()方法。如下举例Disable按钮的事件处理,应该很好理解。

private void btnDisable_Click(object sender, EventArgs e)
{
    bool ret = My9113CardDevice.CardRelease();//卡Release,返回值表示是否成功。
    if (ret)
    {
        ShowActionAtListBox("Release Card Finish!",MsgType.Action);//MsgType是个枚举,这里可忽略其作用。
    }
    else
    {
        ShowActionAtListBox("Release Card Failed!",MsgType.Error);
    }
}

ListBox项目添加信息的方法。

private void ShowActionAtListBox(string ActionString , MsgType msgType)
{
     string[] MT = new string[] { "  _ Action_ : ", " _ Warning_ : ", "   _ Alarm_ : ", "   _ Error_ : ", "   _ Other_ : " };
     this.lbShowMsg.Items.Add(DateTime.Now.ToString() + MT[(int)msgType] + ActionString);
     this.lbShowMsg.SelectedIndex = this.lbShowMsg.Items.Count - 1;
}

但对于【Keep Read】按钮,为了用户体验(连续读取的时候软件不卡死),就创建线程执行方法:每隔500ms对ListBox执行Iteam.Add()。【Keep Read】按钮事件处理如下。

private void btnKepReadVolt_Click(object sender, EventArgs e)
{
    if (iskeepReadVolt==false)
    {
        Thread thrKeepReadVolt = new Thread(new ThreadStart(KepReadVoltMeoth));
        thrKeepReadVolt.Start();
        iskeepReadVolt = true; 
    }
    else
    {
        iskeepReadVolt = false;
    }
    this.btnKepReadVolt.Text = iskeepReadVolt ? "Stop Read" : "Keep Read";
    
}

线程所调用的方法如下:

private void KepReadVoltMeoth()
{
    while (iskeepReadVolt)
    {
        ShowActionAtListBox("Read Vel", MsgType.Action);
        Thread.Sleep(500);
    }          
}

想法很理想。
不是连续执行的按钮,直接顺序执行,也不影响用户体验。
需要连续执行的按钮,按下后→创建一个线程→线程连续执行。
然而出错了。

出现的问题

当按下【Initialize】、【Disable】、【Read Volt】按钮能顺利显示相应信息。但当按下【Keep Read】。出现如下报错:线程间操作无效。
C# 工控开发日记001:Winform报错_线程间操作无效

解决思路

创建委托,用委托创建一个事件。然后ListBox订阅这个事件。
在Button KeyDown事件中创建线程,线程用异步调用的方式触发事件。事件的订阅者调用ListBox的方法。
完美。

代码如下:

//创建委托和委托类型的事件。
public delegate void dlgTemp(string ActionString, MsgType msgType);
public event dlgTemp EventTemp;
public WF9113()
{            
	InitializeComponent();
	//订阅事件,事件处理方法为ListBox.Item.Add();
	this.EventTemp += ShowActionAtListBox;
}
//相应按键的事件代码不用修改
private void btnKepReadVolt_Click(object sender, EventArgs e)
{
    if (iskeepReadVolt==false)
    {
    	//此处启动线程
        Thread thrKeepReadVolt = new Thread(new ThreadStart(KepReadVoltMeoth));
        thrKeepReadVolt.Start();
        iskeepReadVolt = true; 
    }
    else
    {
        iskeepReadVolt = false;
    }
    this.btnKepReadVolt.Text = iskeepReadVolt ? "Stop Read" : "Keep Read";
    
}
private void KepReadVoltMeoth()
{
    while (iskeepReadVolt)
    {
    	//使用异步调用的方式调用EventTemp事件。从而触发KepReadVoltMeoth方法
        this.lbShowMsg.Invoke(EventTemp, "Read Vel", MsgType.Action);
        Thread.Sleep(500);
    }          
}

效果如下,此时在连续读取的情况下也可以对其他按钮进行操作。
C# 工控开发日记001:Winform报错_线程间操作无效

总结

此文最后编辑于2020年10月25日,只对现象进行大概表述,临时做一个问题处理记录。
一些原理和技术要点,肯定有不妥、错漏,日后再补充,也希望朋友能提出宝贵意见和建议。

本文地址:https://blog.csdn.net/CSDN_PEN/article/details/109271417

相关标签: C#