簡體   English   中英

防止掛在Windows窗體中

[英]Prevent hanging in windows forms

我有問題 因此,我構建了一個應用程序,該應用程序以圖表和datagridview的形式顯示數據。 他們都反應靈敏。 這意味着它們將重新縮放並隨數據一起移動。 我猜這需要一些計算能力。

同時,我有計時器,使它們全部以f = 4Hz周期性運行。

現在:當我運行該應用程序並打開定期讀數時,該應用程序在調整大小時會掛起。 我該如何預防呢?

我已經嘗試使用backgroundworker,但是在訪問在“其他線程”中聲明(並使用)的datagridview和chart時,就會出現問題(如VS所說)

所以..我該如何預防呢? 也許我應該以其他方式利用背景工作者?

我對背景工作人員的嘗試:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //Control.CheckForIllegalCrossThreadCalls = false;
            if (!GetConnectionStatus())
            {
                stop_ticking();
                if (MessageBox.Show("Device not connected", "Connection status", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error) == DialogResult.Retry)
                    messaging();
                else
                    return;
            }

            //  TEMP READ
            Read_temp(tlist);
            float[] t = new float[3];
            float[] r = new float[3];
            float[] av = new float[1];
            float[] st = new float[1];

            //  TEMP IMPORT
            tlist.Give_current_temp(t, r, av, st);
            string time_stamp = tlist.Give_current_time();

            rows_nr++;

            //  ADDING TO GRID
            dataGridView1.Invoke(new Action(() => { dataGridView1.Rows.Add(new object[] { rows_nr, time_stamp, av[0], st[0], (t[0]).ToString(), (r[0]).ToString(), (t[1]).ToString(), (r[1]).ToString(), (t[2]).ToString(), (r[2]).ToString() }); }));
            //dataGridView1.Rows.Add(new object[] { rows_nr, time_stamp, av[0], st[0], (t[0]).ToString(), (r[0]).ToString(), (t[1]).ToString(), (r[1]).ToString(), (t[2]).ToString(), (r[2]).ToString() });
            dataGridView1.Invoke(new Action(() => { dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.RowCount - 1; }));
            //dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.RowCount - 1;

            //  ADDING TO CHART
            for (int i = 0; i < 3; i++)
                chart1.Invoke(new Action(() => { chart1.Series[series_names[i]].Points.AddXY((rows_nr), (t[i])); }));
            //chart1.Series[series_names[i]].Points.AddXY((rows_nr), (t[i]));
            chart1.Invoke(new Action(() => { chart1.Series["average"].Points.AddXY((rows_nr), (av[0])); }));
            //chart1.Series["average"].Points.AddXY((rows_nr), (av[0]));
            //chart1.Series["std1"].Points.AddXY((rows_nr), (av[0] + Math.Abs(st[0])));
            //chart1.Series["std2"].Points.AddXY((rows_nr), (av[0] - Math.Abs(st[0])));

            //  MOVING CHART
            if (chart1.Series[series_names[0]].Points.Count > nr_of_noints_graph)
            {
                for (int i = 0; i < 3; i++)
                    chart1.Series[series_names[i]].Points.RemoveAt(0);
                chart1.Series["average"].Points.RemoveAt(0);
                //chart1.Series["std1"].Points.RemoveAt(0);
                //chart1.Series["std2"].Points.RemoveAt(0);

                chart1.ChartAreas[0].AxisX.Minimum = rows_nr - (nr_of_noints_graph - 1);
                chart1.ChartAreas[0].AxisX.Maximum = rows_nr;
                dataGridView1.Rows.RemoveAt(0);
            }

            chart1.Invoke(new Action(() => { chart1.ChartAreas[0].RecalculateAxesScale(); }));
            //chart1.ChartAreas[0].RecalculateAxesScale();
        }

請看一下背景工作者樣本。 你做錯了。 后台工作程序DoWork不應調用UI控件,並且應在非UI線程中執行,它應執行耗時的計算並調用worker.ReportProgress()。 雖然ReportProgress方法可以訪問UI控件,但是此方法中的代碼在UI線程中執行。 在添加/刪除點時,某些圖表控件比較笨拙。 可能因為掛住而掛起。 減少更新的頻率(例如1秒1秒鍾),然后查看其是否掛起。

https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.backgroundworker?view=netframework-4.7.2

在Stopwatch中包裝操作,並使用System.Diagnostics.Debug.WriteLine跟蹤執行流程和操作時間。

移動圖表部件不起作用,因為它在沒有調用UI線程的情況下訪問了非ui線程中的UI元素。

如果不是背景工作者,我會這樣寫:

    //  MOVING CHART
        chart1.Invoke(new Action(()=>
    {
          if (chart1.Series[series_names[0]].Points.Count > nr_of_noints_graph)
          {
               for (int i = 0; i < 3; i++)
                   chart1.Series[series_names[i]].Points.RemoveAt(0);
               chart1.Series["average"].Points.RemoveAt(0);
               chart1.ChartAreas[0].AxisX.Minimum = rows_nr - (nr_of_noints_graph - 1);
               chart1.ChartAreas[0].AxisX.Maximum = rows_nr;
          }
     }
)); 

我也不會將每個操作都包裝在單獨的Invokes中。

關於您的問題,沒有足夠的信息來檢測出問題所在,請提供最小的可運行樣本以證明問題所在。

由於@Access拒絕狀態,您應該改善GUI和后台工作線程之間的分離。 您可以在后台線程上執行// TEMP READ// TEMP IMPORT操作,並在所有數據就緒后通過.Invoke方法調用GUI線程。 請閱讀“如何:對Windows窗體控件進行線程安全的調用”一文,以了解更多信息。

DataGridView添加/更新數據時,請使用.BeginUpdate / .EndUpdate方法來防止控件更新,直到刷新所有數據為止。

另一種方法是使用虛擬模式 如果網格中有很多項目,這將特別有用。

使用后台線程時,您不得創建,更新甚至訪問任何UI元素。

您需要將檢索數據的工作(較慢的部分)與更新圖表的工作(非常快)分開。

真正歸結為這樣:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    if (!GetConnectionStatus())
    {
        stop_ticking();
        return;
    }

    //  TEMP READ
    Read_temp(tlist);
    float[] t = new float[3];
    float[] r = new float[3];
    float[] av = new float[1];
    float[] st = new float[1];

    //  TEMP IMPORT
    tlist.Give_current_temp(t, r, av, st);
    string time_stamp = tlist.Give_current_time();

    rows_nr++;

    chart1.Invoke(new Action(() =>
    {
        //  ADDING TO GRID
        dataGridView1.Rows.Add(new object[] { rows_nr, time_stamp, av[0], st[0], (t[0]).ToString(), (r[0]).ToString(), (t[1]).ToString(), (r[1]).ToString(), (t[2]).ToString(), (r[2]).ToString() });
        dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.RowCount - 1;

        //  ADDING TO CHART
        for (int i = 0; i < 3; i++)
        {
            chart1.Series[series_names[i]].Points.AddXY((rows_nr), (t[i]));
        }

        chart1.Series["average"].Points.AddXY((rows_nr), (av[0]));

        //  MOVING CHART
        if (chart1.Series[series_names[0]].Points.Count > nr_of_noints_graph)
        {
            for (int i = 0; i < 3; i++)
            {
                chart1.Series[series_names[i]].Points.RemoveAt(0);
            }
            chart1.Series["average"].Points.RemoveAt(0);

            chart1.ChartAreas[0].AxisX.Minimum = rows_nr - (nr_of_noints_graph - 1);
            chart1.ChartAreas[0].AxisX.Maximum = rows_nr;
            dataGridView1.Rows.RemoveAt(0);
        }

        chart1.ChartAreas[0].RecalculateAxesScale();
    }));
}

如果必須顯示一個MessageBox,則還需要調用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM