对不起,很长的帖子,但我试图非常详细地解释这个问题,以免引起混淆。最后一句包含实际问题。
我正在用 C#/.NET 编写一个多线程应用程序。
该应用程序由一个主窗口组成,该窗口可视化来自压力传感器的数据。传感器数据在自己的线程中获取。
数据也记录在类的实例中ListView
:
可以通过“保存”按钮将记录的数据保存到磁盘上的文件(应该打开 .NET 类的实例SaveFileDialog
)。
这SaveFileDialog
也在自己的线程中运行。现在调用方法时出现问题SaveFileDialog.ShowDialog()
:
System.InvalidOperationException 未处理 Message="Cross-thread operation not valid: Control 'tlpMain' 从创建它的线程以外的线程访问。" 源="系统.Windows.Forms"
出现问题是因为SaveFileDialog的所有者(主窗口)在另一个线程中运行。
这是为 SaveFileDialog() 创建线程的代码:
private void bSave_Click(object sender, EventArgs e)
{
Thread saveFileDialog = new Thread(OpenSaveFileDialog);
saveFileDialog.SetApartmentState(ApartmentState.STA);
saveFileDialog.Start();
}
方法 OpenSaveFileDialog() 的代码:
private void OpenSaveFileDialog()
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "Text Files (*.txt)|*.txt|CSV (*.csv)|*.csv|All Files (*.*)|*.*";
saveFileDialog.FilterIndex = 0;
/* Call "ShowDialog" with an owner ("this.Parent") to achieve, so that
* the parent window is blocked and "unclickable".
*
* Danger of an "InvalidOperationException" because "this.Parent" control
* is running (was created) in another thread.
* But "this.Parent" should not be modified by this method call.
*/
DialogResult pressedButton = saveFileDialog.ShowDialog(this.Parent);
...
InvalidOperationException仅在使用 Visual Studio 的调试器运行应用程序时引发/显示。到目前为止,“正常”运行应用程序时没有问题。
但我想避免这个问题。
我尝试构建一个包装方法(SaveFileDialog):
private void OpenSaveFileDialog()
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
...
SaveFileDialog(saveFileDialog, this.Parent);
}
包装方法:
private void SaveFileDialog(SaveFileDialog saveFileDialog, Control owner)
{
if (owner.InvokeRequired)
BeginInvoke(new dSaveFileDialog(SaveFileDialog), new object[] { saveFileDialog, owner });
else
{
DialogResult pressedButton = saveFileDialog.ShowDialog(owner);
...
这导致TargetInvocationException
尽管该Main()
方法标有[STAThreadAttribute]
:
InnerException: System.Threading.ThreadStateException Message="当前线程必须设置为单线程单元 (STA) 模式才能进行 OLE 调用。确保您的 Main 函数上标记了 STAThreadAttribute。仅当调试器是附加到过程中。” 源="系统.Windows.Forms"
有没有人知道如何以SaveFileDialog
某种方式打开主窗口,以便在没有(线程)麻烦的情况下阻止主窗口(“不可点击”)?
谢谢你。