调用线程必须是 STA 线程,因为许多具有实时图表的 UI 组件都需要它



也许我的问题重复,但实际上我尝试了其他解决方案,但无法解决问题。绘图窗体不是我的主窗体,但它从主窗体打开。在主程序中,我在 Main(( 之前有 [STAThread]。我想在 sql 表中的数据发生任何变化时自动运行 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保存在类变量中,例如

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
}

相关内容

  • 没有找到相关文章

最新更新