0

これが私のアプリケーションで達成しようとしていることです.HTMLファイルが(FileSystemWatcherを使用して)ディレクトリに追加されると、WebBrowserを使用してすぐにこれを印刷したいと思います. これが発生すると、次のエラーが発生します。

System.Threading.ThreadStateException: ActiveX control GUID cannot be instantiated because the current thread is not in a single-threaded apartment

この問題が発生している私が使用しているコードは次のとおりです。(Main() の前に [STAThread] があります)

public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        //  Create a FileSystemWatcher to monitor all files on drive C.
        FileSystemWatcher fsw = new FileSystemWatcher("C:\\Test");

        //  Watch for changes in LastAccess and LastWrite times, and 
        //  the renaming of files or directories. 
        fsw.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
            | NotifyFilters.FileName | NotifyFilters.DirectoryName;

        //  Register a handler that gets called when a  
        //  file is created, changed, or deleted.
        //fsw.Changed += new FileSystemEventHandler(OnChanged);

        fsw.Created += new FileSystemEventHandler(OnChanged);

        //fsw.Deleted += new FileSystemEventHandler(OnChanged);
        fsw.EnableRaisingEvents = true;

        PrinterSettings settings = new PrinterSettings();
        label2.Text = settings.PrinterName;

        Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
    }

    private void OnChanged(object source, FileSystemEventArgs e)
    {
        notifyIcon1.BalloonTipText = "Printing document " + e.Name + "...";
        notifyIcon1.BalloonTipTitle = "Printing Application";
        notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
        notifyIcon1.ShowBalloonTip(500);

        PrintCOAPage(e.Name);
    }

    private void PrintCOAPage(string name)
    {
        try
        {
            // Create a WebBrowser instance. 
            WebBrowser webBrowserForPrinting = new WebBrowser();

            // Add an event handler that prints the document after it loads.
            webBrowserForPrinting.DocumentCompleted +=
                new WebBrowserDocumentCompletedEventHandler(PrintDocument);

            // Set the Url property to load the document.
            webBrowserForPrinting.Url = new Uri(@"C:\\Test\\" + name);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }

    private void PrintDocument(object sender,
        WebBrowserDocumentCompletedEventArgs e)
    {
        try
        {
            // Print the document now that it is fully loaded.
            ((WebBrowser)sender).Print();

            // Dispose the WebBrowser now that the task is complete. 
            ((WebBrowser)sender).Dispose();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }

    }

    private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
    {
        this.Show();
        this.Activate();
        if (this.WindowState == FormWindowState.Minimized)
        {
            this.WindowState = FormWindowState.Normal;
        }
    }

    private void Form1_Resize(object sender, EventArgs e)
    {
        if (FormWindowState.Minimized == WindowState)
        {
            Hide();
        }  
    }

これについて何か洞察があれば、助けていただければ幸いです。WebBrowser を使用して HTML ファイルを印刷するべきではないのでしょうか。

4

1 に答える 1

2

Created など、FSW によって発生するイベントは、ワーカー スレッドで発生します。これは非常に重要です。これにより、通知ができるだけ早く配信され、FSW が使用する内部バッファーがオーバーフローしないことが保証されます。エラーイベントをサブスクライブすることを忘れないでください。

イベント ハンドラーでできることは限られていますが、コードが別のスレッドで実行されることに常に注意する必要があります。スレッドの安全性は常に考慮されます。ここで発生している特定のエラーは、WebBrowser がスレッドセーフなクラスではないことが原因です。スレッド化をサポートしないクラスを使用しているという警告を実際に受け取る数少ないケースの 1 つは、より一般的な問題は、ランダムな誤動作です。

とにかく、FSWはこれを非常に簡単に解決します。代わりに、UI スレッドでイベントを発生させるように依頼できます。次の 1 行のコードが必要です。

  fsw.SynchronizingObject = this;

これにより FSW が停止することに注意してください。イベントの頻度が高い場合は、UI スレッドの応答性を維持する必要があります。そのエラー イベントをスキップしないでください。FSW をブラウザーから分離することは、スレッドセーフ キューを使用して技術的に可能です。別のスレッドで WebBrowser を実行するために必要なコードの種類については、この回答を参照してください。

于 2013-02-27T21:51:54.783 に答える