2

在下面的代码中,我有一个名为GetExcelData. 完成后,我想显示一个对话框以将其内容保存到 TXT 文件中。

问题是,在调试时,我收到以下错误:

在进行 OLE 调用之前,必须将当前线程设置为单线程单元 (STA) 模式。确保您的 Main 函数上标记了 STAThreadAttribute。仅当调试器附加到进程时才会引发此异常。

这是我的代码。错误发生在读取的行上saveFileDialog1.ShowDialog();

FileInfo existingFile = new FileInfo("C:\\MyExcelFile.xlsx");

ConsoleApplication2.Program.ExcelData data = ConsoleApplication2.Program.GetExcelData(existingFile, _worker);

var json = new JavaScriptSerializer().Serialize(data);

SaveFileDialog saveFileDialog1 = new SaveFileDialog();

saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
saveFileDialog1.ShowDialog();

if (saveFileDialog1.FileName != "")
{
    File.WriteAllText(saveFileDialog1.FileName, json);
}

我尝试将[STAThread]属性添加到我从中调用它的方法中,但它似乎不起作用。

请让我提供更多代码,以便更清楚地了解我正在尝试做什么:

以下内容存在于引用我的控制台项目的 WPF 项目中:

private BackgroundWorker _backgroundWorker = new BackgroundWorker();

public MainWindow()
{
    InitializeComponent();

    // Set up the BackgroundWorker.
    this._backgroundWorker.WorkerReportsProgress = true;
    this._backgroundWorker.WorkerSupportsCancellation = true;
    this._backgroundWorker.DoWork += new DoWorkEventHandler(bw_DoWork);
    this._backgroundWorker.ProgressChanged +=
                              new ProgressChangedEventHandler(bw_ProgressChanged);
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    if (this._backgroundWorker.IsBusy == false)
    {
        this._backgroundWorker.RunWorkerAsync();
    }
    e.Handled = true;
}

void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // Set the Value porperty when porgress changed.
    this.progressBar1.Value = (double)e.ProgressPercentage;
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker _worker = sender as BackgroundWorker;
    if (_worker != null)
    {
        FileInfo existingFile = new FileInfo("C:\\MyExcelFile.xlsx");

        ConsoleApplication2.Program.ExcelData data = ConsoleApplication2.Program.GetExcelData(existingFile, _worker);

        var json = new JavaScriptSerializer().Serialize(data);

        SaveFileDialog saveFileDialog1 = new SaveFileDialog();

        saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
        saveFileDialog1.ShowDialog();

        if (saveFileDialog1.FileName != "")
        {
            File.WriteAllText(saveFileDialog1.FileName, json);
        }
    }
}
4

3 回答 3

1

将与 UI 交互的代码移动到处理 UI 元素的同一线程。最简单的方法是通过 RunWorkerCompleted 事件

  this._backgroundWorker.RunWorkerCompleted +=
                          new RunWorkerCompletedEventHandler(bw_WorkComplete);

  ....

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker _worker = sender as BackgroundWorker;
    if (_worker != null)
    {
        FileInfo existingFile = new FileInfo("C:\\MyExcelFile.xlsx");
        ConsoleApplication2.Program.ExcelData data = ConsoleApplication2.Program.GetExcelData(existingFile, _worker);

        e.Result = new JavaScriptSerializer().Serialize(data);
     }
 }

 private void bw_WorkComplete(object sender, RunWorkerCompletedEventArgs e)
 {
    SaveFileDialog saveFileDialog1 = new SaveFileDialog();
    saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
    saveFileDialog1.ShowDialog();

    if (saveFileDialog1.FileName != "")
    {
       string json = e.Result.ToString();
       File.WriteAllText(saveFileDialog1.FileName, json);
    }
}

在 DoWork 方法中,将 json 字符串保存在 DoWorkEventArgs 类的 e.Result 属性中,并在 RunWorkerCompleted 事件中从同名的 RunWorkerCOmpletedEventArgs 属性中检索它。

于 2013-08-13T15:08:21.050 回答
1

为什么?

基本上发生的事情是你saveFileDialog1.ShowDialog();bw_DoWork. 这是不对的。Dialog是 UI 控件,应该从 UI 线程运行,并且bw_DoWork方法在单独的线程(非 UI)中执行。

如何解决这个问题?

将对话框显示代码从bw_DoWork方法中移开并传递所需的字符串。所以算法看起来像

  • 单击按钮或任何操作以显示对话框 [UI 线程]
  • 打开对话框 [UI 线程]
  • 验证您从对话框 [UI 线程] 中获得了有效的字符串
  • 启动后台工作者并传递文件路径字符串 [UI 线程]
  • 写入文件[后台工作线程]
于 2013-08-13T15:08:29.503 回答
0

修改您Program.cs的方法的声明Main如下所示:

[STAThread]
static void Main()
于 2013-08-13T14:53:57.407 回答