事件属性更改不会触发
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了事件属性更改不会触发相关的知识,希望对你有一定的参考价值。
所以我创建了一个事件,每当属性ActualVoltage发生变化时,它将在Form1中更新,但它不会。属性ActualVoltage更改,当我向机器发送设定电压命令时,它将发回一个数字并将该数字分配给AcutalVoltage。请帮助我,请告诉我我的错误在哪里,并为我解释,就像我是一个5岁的孩子。这是我的事件代码:
public delegate void ValueChange();
public event ValueChange Change;
public double ActualVoltage
{
get { return actualVoltage; }
set
{
if (actualVoltage == value) return;
else
{
actualVoltage = value;
OnValueChange();
}
}
}
private void OnValueChange()
{
Change?.Invoke();
}
在Form1中:
private void Form1_Load(object sender, EventArgs e)
{
ps.Change += ps_change;
}
private void ps_change()
{
lblValueActualVoltage.Text = ps.ActualVoltage.ToString();
lblValueActualCurrent.Text = ps.ActualCurrent.ToString();
lblHexCur.Text = ps.HexActualCurrent1;
lblHexVol.Text = ps.HexActualVoltage1;
}
更新:在PS2000B类
public void GetDeviceStatusInformation(byte[] rawData)
{
remoteMode = ((byte)(rawData[0] & 0b1)).ToString();
outputMode = ((byte)(rawData[1] & 0b1)).ToString();
List<byte> temp = new List<byte>();
foreach (var v in rawData)
temp.Add(v);
byte[] vontageBytes = temp.GetRange(2, 2).ToArray();
HexActualVoltage = BitConverter.ToString(vontageBytes);
Array.Reverse(vontageBytes);
byte[] currentBytes = temp.GetRange(4, 2).ToArray();
HexActualCurrent = BitConverter.ToString(currentBytes);
Array.Reverse(currentBytes);
var a = (BitConverter.ToInt16(vontageBytes, 0));
ActualVoltage =Math.Round( BitConverter.ToInt16(vontageBytes, 0) * nominalVoltage / 25600.0,2);
ActualCurrent = BitConverter.ToInt16(currentBytes, 0) * nominalCurrent / 25600.0;
}
public void RunTest(string safeFileName,string save)
{
Stopwatch st = new Stopwatch();
List<string> timeMeasure = new List<string>();
List<string> CurrentResults = new List<string>();
List<int> Time = new List<int>();
List<string> Voltage = new List<string>();
FileStream file = new FileStream(safeFileName, FileMode.Open, FileAccess.Read);
StreamReader reader = new StreamReader(file);
string strRead = reader.ReadLine();
while (strRead != null)
{
string[] temp = strRead.Split(';');
Voltage.Add(temp[0]);
Time.Add(int.Parse(temp[1]));
strRead = reader.ReadLine();
}
reader.Close();
file.Close();
int n = 0;
st.Start();
for (int i = 0; i < Voltage.Count(); i++)
{
SetVoltage(Voltage[i]);
for (int j = 0; j < Time[i]/300; j++)
{
UpdateStatusInfomationAndActualValue();
CurrentResults.Add(Voltage[i]+";"+0.3*n+";"+ActualCurrent.ToString()+";"+ HexActualCurrent);
n++;
}
}
st.Stop();
FileStream wfile = new FileStream(save +"\results.txt", FileMode.Create, FileAccess.Write);
StreamWriter writer = new StreamWriter(wfile);
writer.WriteLine("VOlTAGE;TIME;CURRENT");
foreach (var v in CurrentResults)
writer.WriteLine(v);
writer.WriteLine("TOTAL TIME: "+st.Elapsed);
writer.Close();
wfile.Close();
}
public void SetVoltage(string vol)
{
vol = vol.Replace('.', ',');
ToPowerSupply ToPowerSupply = new ToPowerSupply();
var b = Convert.ToInt16(Single.Parse(vol) * 25600 / nominalVoltage);
var input = BitConverter.GetBytes(b);
Array.Reverse(input);
var temp = ToPowerSupply.SendCommand(0b11, ObjectList.SET_U, input, 2);
ComPort.Write(temp, 0, temp.Count());
Thread.Sleep(150);
int bytes = ComPort.BytesToRead;
byte[] rawData = new byte[bytes];
ComPort.Read(rawData, 0, bytes);
}
在Form1.cs之后正确处理事件:
public delegate void ValueChange();
public event ValueChange Change;
private double actualVoltage;
public double ActualVoltage
{
get { return actualVoltage; }
set
{
if (actualVoltage == value) return;
else
{
actualVoltage = value;
OnValueChange();
}
}
}
private void ps_change()
{
//UI updates here
}
private void OnValueChange()
{
Change?.Invoke();
}
private void Form1_Load(object sender, EventArgs e)
{
Change += ps_change;
}
请注意:如果您的属性设置器是在非GUI线程中调用的,那么您应该将GUI更新代码封送到UI线程,如上所述here
如果在非GUI线程上调用属性setter,则ps_change
方法应如下所示:
private void ps_change()
{
if (InvokeRequired)
{
BeginInvoke(new Action(ps_change));
return;
}
lblValueActualVoltage.Text = ps.ActualVoltage.ToString();
lblValueActualCurrent.Text = ps.ActualCurrent.ToString();
lblHexCur.Text = ps.HexActualCurrent1;
lblHexVol.Text = ps.HexActualVoltage1;
}
Why?
我在GUI线程上调用属性setter。
无法从非GUI线程处理表单上的控件。这是因为Windows窗体控件绑定到Windows句柄,而Windows句柄由线程拥有。如果在一个线程(很可能是主应用程序线程)上创建控件(在这种情况下为Form或Label),则不能在不同的线程上执行其句柄上的操作(例如,更改文本)。
要解决这个问题,Control
类有方法InvokeRequired
,Invoke
和BeginInvoke
:
InvokeRequired
指示控件是属于不同的线程(true
)还是属于当前线程(false
)。- 当
InvokeRequired
是true
时,必须使用Invoke
或BeginInvoke
。这两种方法都将另一个委托封送到拥有该控件的GUI线程。必须从该代理执行所有控制操作。 - 这两种方法的区别在于
Invoke
阻塞调用线程,直到委托在GUI线程上执行,而BeginInvoke
只是将调用提交给队列并立即返回。编组是通过发送到窗口消息队列的特殊Windows消息执行的。
更多信息:https://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired(v=vs.110).aspx
实现这一点的通常模式是在事件处理程序中检查InvokeRequired
,如果它是true
,则调用Invoke
或BeginInvoke
并再次为此相同的事件处理程序提供委托。然后在GUI线程上重新调用处理程序,其中InvokeRequired
是false
,然后代码安全地操作表单控件。
我终于弄明白了原因。我在主线程上使用Thread.Sleep()。当ActualVoltage改变时,主线程正在休眠,这就是GUI不更新的原因。为了解决这个问题,我使用BackGroudWorker,一切都很好。
以上是关于事件属性更改不会触发的主要内容,如果未能解决你的问题,请参考以下文章