如何在新线程中打开窗口并传递数据?

时间:2017-01-06 00:10:05

标签: c# wpf visual-studio

我有一个带富文本框的窗口。如何在新主题中打开它,然后写入文本框?

我已经尝试过Dispatcher.BeginInvoke以及使用Thread和BackgroundWorker的许多不同方法,但我没有正确设置它。我收到错误,例如“调用线程无法访问此对象,因为另一个线程拥有它”。当试图打开窗户或写作时。

我使用Hide()启动隐藏的背景窗口,使用Show()打开:

MainWindow mainwindow = this;

myWindow = new NewWindow(mainwindow);
myWindow.Left = this.Left + 605;
myWindow.Top = this.Top + 0;
myWindow.Hide();

myWindow.myRichTextBox.Cursor = Cursors.Arrow;

我使用保存到列表中的Actions写入它,然后在某个时间调用:

List<Action> LogActions = new List<Action>();
Action WriteAction;

// Create Multiple Actions 
WriteAction = () =>
{
    myWindow.myRichTextBox.Document = new FlowDocument(paragraph);
    paragraph.Inlines.Add(new LineBreak());
    paragraph.Inlines.Add(new Bold(new Run("Example")) { Foreground = Brushes.White });
};
// Add Actions to List
LogActions.Add(WriteAction);

// Write All Actions in List
foreach (Action Write in LogActions)
{
    Write();
}

为了简化,它基本上是这样做的:

myWindow.myRichTextBox.AppendText("Example");

现在可以在没有新线程的情况下传递数据。但是当写入Rich Text Box时,鼠标会冻结几秒钟,我想这可能会释放它。有人会建议不要在新线程中打开吗?

1 个答案:

答案 0 :(得分:2)

通常最好的做法是让用户界面留在主应用程序线程中,UI可以在其中生成后台线程以执行更长时间运行的任务。这样,在后台工作正在进行时,UI线程仍然可以响应用户输入。

如果是一个窗口,myWindow带有要附加邮件的Rich Text Box,myWindow将使用BackgroundWorker在单独的帖子中收集邮件,然后通过线程终止的回调更新RTF控件(对于BackgroundWorker,这是OnRunWorkerCompleted方法。

如果窗口必须作为单独的线程运行,则此助手类将WPF窗口包装在新线程中并使用新的SynchronizationContext进行设置,但是,如果您仍需要线程安全的消息传递想在不同线程的窗口之间进行通信。 ConcurrentQueue<T>集合提供了一个可用于此目的的线程安全集合。

public static class WindowThreadHelpers
{
    public static void LaunchWindowInNewThread<T>() where T : Window, new()
    {
        Dispatcher.CurrentDispatcher.Invoke(new ThreadStart(ThreadStartingPoint<T>));
    }

    private static void ThreadStartingPoint<T>() where T : Window, new()
    {
        SynchronizationContext.SetSynchronizationContext(
            new DispatcherSynchronizationContext(
                Dispatcher.CurrentDispatcher));

        var win = new T();
        win.Closing += (sender, args) =>
        {
            Dispatcher.ExitAllFrames();
            win.Dispatcher.InvokeShutdown();
        };

        win.Show();
        Dispatcher.Run();
    }
}

以下是如何从主线程

中使用它的示例
WindowThreadHelpers.LaunchWindowInNewThread<NewWindow>();