调用线程必须是 STA 线程,因为它被许多 UI 个具有 livechart 的组件所需要

The calling thread must be an STA thread because it is required by many UI components with livechart

也许我的问题是重复的,但实际上我尝试了其他解决方案,但无法解决问题。 Plot 窗体不是我的主窗体,但它从主窗体打开。在主程序中,我在 Main() 之前有 [STAThread]。如果 sql table 中的数据发生任何变化,我想定期 运行 Ploting() 更新绘图。 我的代码如下:

namespace MainProject1{
  public partial class Plot : Form
{
    System.Timers.Timer timer = new System.Timers.Timer();
    BackgroundWorker PlotWorker;  

    public Plot()
    {
        InitializeComponent();
        timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

        PlotWorker = new BackgroundWorker();
        PlotWorker.DoWork += new DoWorkEventHandler(PlotWorker_DoWork);
        PlotWorker.WorkerSupportsCancellation = true;

        //Ploting(); //here it works
    }

    void PlotWorker_DoWork(object sender, DoWorkEventArgs e)
    {

        while (true)
        {
            //Ploting(); //here also receive the error.
            if (PlotWorker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }
        }
    }

    private void timer_Elapsed(object sender, ElapsedEventArgs elapsedEventArg)
    {
        Ploting(); //here i receive the error
    }

    private void test_Click(object sender, EventArgs e)
    {
        timer.AutoReset = true;
        timer.Interval = 100;
        timer.Start();
    }

    private void Ploting()
    {
        try
        {
            var list1 = new List<double>();
            var list2 = new List<double>();

            SqlResultTable rt = new SqlResultTable();
            rt.ReadtoPlot(84, "readingS", ref list1, ref list2); //here i read the data from sql. it works corrrect.
            cartesianChart1.Series = new SeriesCollection
            {
                new ScatterSeries
                {
                    Title = "Setpoints",
                    Values = new ChartValues<double>(list1),
                    PointGeometry = DefaultGeometries.Diamond,
                    StrokeThickness = 2,
                    Fill = Brushes.Transparent,
                },
                new LineSeries
                {
                    Title = "UUT readings",
                    Values = new ChartValues<double>(list2),
                    LineSmoothness = 0,
                    PointGeometrySize = 10
                },
            };
            cartesianChart1.DataClick += CartesianChart1OnDataClick;
        }
        catch(Exception err)
        {
            MessageBox.Show(err.Message);
        }
    }

    private void CartesianChart1OnDataClick(object sender, ChartPoint chartPoint)
    {
        MessageBox.Show("You clicked (" + chartPoint.X + "," + chartPoint.Y + ")");
    }
}

}

当我在构造函数中使用 Ploting() 方法时,它可以工作,但是当我在 worker 或 timer_Elapsed 中使用它时,我再次收到错误。我知道它与线程有关,但不知道如何解决。我试图在后台工作程序或 timer_Elapsed 中创建新线程,但收到另一个错误。 很抱歉这个问题。我是 C# 新手!

新更新:委托代码:

  namespace MainProject1{
  public partial class Plot : Form
{
    public delegate void plotDel(); //**** new added ***
    System.Timers.Timer timer = new System.Timers.Timer();
    BackgroundWorker PlotWorker;  

    public Plot()
    {
        InitializeComponent();
        timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

        PlotWorker = new BackgroundWorker();
        PlotWorker.DoWork += new DoWorkEventHandler(PlotWorker_DoWork);
        PlotWorker.WorkerSupportsCancellation = true;

        plotDel pl1 = OnPlotNeeded; //**** new added ***
        //Ploting(); //here it works
    }

    protected virtual void OnPlotNeeded()  //**** new added ***
    {
        Ploting();
    }
    void PlotWorker_DoWork(object sender, DoWorkEventArgs e)
    {

        while (true)
        {
            //Ploting(); //here also receive the error.
            if (PlotWorker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }
        }
    }

    private void timer_Elapsed(object sender, ElapsedEventArgs elapsedEventArg)
    {
        System.Threading.SynchronizationContext.Current.Post(new System.Threading.SendOrPostCallback(o => Ploting()), null); //when i add this line, it does not go to next line(no error, no action) and without it, again receive the error as before!
        OnPlotNeeded();
    }

    private void test_Click(object sender, EventArgs e)
    {
        timer.AutoReset = true;
        timer.Interval = 100;
        timer.Start();
    }

    private void Ploting()
    {
        // the inside code is same as first code
    }

    private void CartesianChart1OnDataClick(object sender, ChartPoint chartPoint)
    {
        MessageBox.Show("You clicked (" + chartPoint.X + "," + chartPoint.Y + ")");
    }
}

}

问题大概是 timer_Elapsed 没有在 UiThread 上执行(实际上这就是异常试图告诉你的)。但是您可以将对 Ploting() 的调用委托回 UiThread。

试试这个 timer_Elapsed

的变体
private void timer_Elapsed(object sender, ElapsedEventArgs elapsedEventArg)
{
    System.Threading.SynchronizationContext.Current.Post(delegate { this.Ploting(); }, null);
}

并且还将对 Plotting() 的所有其他调用替换为延迟。

编辑: 在创建时将 SynchronizationContext 保存在 class 变量中,如

private readonly SynchronizationContext syncContext;

public Plot()
{
    InitializeComponent();
    this.syncContext = System.Threading.SynchronizationContext.Current;
    ...
}

然后使用此上下文调用 Plotting(),如下所示:

private void Timer_Elapsed(object sender, ElapsedEventArgs e) => this.DelagetePloting();

private void DelagetePloting()
    => this.syncContext.Post(delegate
    {
        this.Ploting();
    }, null);

private void Ploting()
{
    // your work
}