事件属性更改不会触发

问题描述 投票:0回答:3

所以我创建了一个事件,每当属性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);



    }
c# events properties triggers serial-port
3个回答
0
投票

在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


0
投票

如果在非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类有方法InvokeRequiredInvokeBeginInvoke

  • InvokeRequired指示控件是属于不同的线程(true)还是属于当前线程(false)。
  • InvokeRequiredtrue时,必须使用InvokeBeginInvoke。这两种方法都将另一个委托封送到拥有该控件的GUI线程。必须从该代理执行所有控制操作。
  • 这两种方法的区别在于Invoke阻塞调用线程,直到委托在GUI线程上执行,而BeginInvoke只是将调用提交给队列并立即返回。编组是通过发送到窗口消息队列的特殊Windows消息执行的。

更多信息:https://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired(v=vs.110).aspx

实现这一点的通常模式是在事件处理程序中检查InvokeRequired,如果它是true,则调用InvokeBeginInvoke并再次为此相同的事件处理程序提供委托。然后在GUI线程上重新调用处理程序,其中InvokeRequiredfalse,然后代码安全地操作表单控件。


0
投票

我终于弄明白了原因。我在主线程上使用Thread.Sleep()。当ActualVoltage改变时,主线程正在休眠,这就是GUI不更新的原因。为了解决这个问题,我使用BackGroudWorker,一切都很好。

© www.soinside.com 2019 - 2024. All rights reserved.