C# 如何在新线程打开的新窗口中更新文本框?
我能够通过以下代码在新线程中打开一个新窗口 以下代码来自MainWindow.xaml.csC# 如何在新线程打开的新窗口中更新文本框?,c#,wpf,multithreading,C#,Wpf,Multithreading,我能够通过以下代码在新线程中打开一个新窗口 以下代码来自MainWindow.xaml.cs private void buttonStartStop_Click(object sender, RoutedEventArgs e) { Test test = new Test(); Thread newWindowThread = new Thread(new ThreadStart(test.start)); newWindowThread.SetApartmentSt
private void buttonStartStop_Click(object sender, RoutedEventArgs e)
{
Test test = new Test();
Thread newWindowThread = new Thread(new ThreadStart(test.start));
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
}
以及test.start()中的以下内容
下面是来自输出类的
public static void print(String str)
{
Dispatcher uiDispatcher = OutputWindow.myOutputWindow.Dispatcher;
uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.AppendText(str + "\n"); }));
uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.ScrollToLine(OutputWindow.myOutputWindow.textBoxOutput.LineCount - 1); }));
}
public static void printOnSameLine(String str)
{
Dispatcher uiDispatcher = OutputWindow.myOutputWindow.Dispatcher;
uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.AppendText(str); }));
uiDispatcher.BeginInvoke(new Action(delegate() { OutputWindow.myOutputWindow.textBoxOutput.ScrollToLine(OutputWindow.myOutputWindow.textBoxOutput.LineCount - 1); }));
}
“Begin”确实会打印在文本框中,但“FINAL”不会,我希望Test类中的start方法在整个程序中更新outputwindow中的文本框。最好的方法是什么
提前谢谢你我不知道你想做什么。FINAL不打印是正常的,因为您调用了System.Windows.Threading.Dispatcher.Run()。此方法使线程保持活动状态并侦听事件。您可以将其视为在Run方法中有while(true){}。方法将继续运行,直到Dispatcher关闭。当需要设置消息时,应该保持后台线程的活动状态,并从另一个线程调用静态方法。下面是一个例子:
// reference to window in another thread
Window outputWindow = null;
Thread thread = new Thread(() =>
{
// another thread
outputWindow = new Window();
outputWindow.Show();
// run event loop
System.Windows.Threading.Dispatcher.Run();
}) { ApartmentState = ApartmentState.STA, IsBackground = true };
thread.Start();
while (outputWindow == null)
{
// wait until the window in another thread has been created
Thread.Sleep(100);
}
// simulate process
for (int i = 0; i < 10; i++)
{
outputWindow.Dispatcher.BeginInvoke((Action)(() => { outputWindow.Title = i.ToString(); }), System.Windows.Threading.DispatcherPriority.Normal);
Thread.Sleep(500); // simulate some hard work so we can see the change on another window's title
}
// close the window or shutdown dispatcher or abort the thread...
thread.Abort();
//在另一个线程中引用窗口
窗口输出窗口=null;
线程线程=新线程(()=>
{
//另一根线
outputWindow=新窗口();
outputWindow.Show();
//运行事件循环
System.Windows.Threading.Dispatcher.Run();
}){ApartmentState=ApartmentState.STA,IsBackground=true};
thread.Start();
while(outputWindow==null)
{
//等待另一个线程中的窗口被创建
睡眠(100);
}
//模拟过程
对于(int i=0;i<10;i++)
{
outputWindow.Dispatcher.BeginInvoke((操作)(()=>{outputWindow.Title=i.ToString();}),System.Windows.Threading.DispatcherPriority.Normal);
Thread.Sleep(500);//模拟一些艰苦的工作,以便我们可以看到另一个窗口标题上的更改
}
//关闭窗口或关闭调度程序或中止线程。。。
thread.Abort();
编辑:
这可能是一个快速而肮脏的通用解决方案。DoSomeWork为显示进度信息的等待窗口创建另一个GUI线程。此窗口创建实际执行工作的工作线程。工作在方法操作中实现。第一个参数是等待窗口,所以您可以从工作线程更改它。当然,在现实世界中,您应该通过接口,而不是直接到窗口实现,但这只是一个示例。第二个参数是object,所以您可以将所需的任何内容传递给工作线程。如果需要更多参数,请传递对象[]或修改方法签名。在这个例子中,我用计数器和睡眠来模拟艰苦的工作。您可以多次单击按钮执行此代码,您将看到所有等待窗口都在不冻结的情况下计数自己的计数器。代码如下:
public static void DoSomeHardWork(Action<Window, object> toDo, object actionParams)
{
Thread windowThread = new Thread(() =>
{
Window waitWindow = new Window();
waitWindow.Loaded += (s, e) =>
{
Thread workThread = new Thread(() =>
{
// Run work method in work thread passing the
// wait window as parameter
toDo(waitWindow, actionParams);
}) { IsBackground = true };
// Start the work thread.
workThread.Start();
};
waitWindow.Show();
Dispatcher.Run();
}) { ApartmentState = ApartmentState.STA, IsBackground = true };
// Start the wait window thread.
// When window loads, it will create work thread and start it.
windowThread.Start();
}
private void MyWork(Window waitWindow, object parameters)
{
for (int i = 0; i < 10; i++)
{
// Report progress to user through wait window.
waitWindow.Dispatcher.BeginInvoke((Action)(() => waitWindow.Title = string.Format("{0}: {1}", parameters, i)), DispatcherPriority.Normal);
// Simulate long work.
Thread.Sleep(500);
}
// The work is done. Shutdown the wait window dispather.
// This will stop listening for events and will eventualy terminate
// the wait window thread.
waitWindow.Dispatcher.InvokeShutdown();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
DoSomeHardWork(MyWork, DateTime.Now);
}
publicstaticvoiddosomework(操作待办事项、对象操作参数)
{
线程窗口线程=新线程(()=>
{
窗口等待窗口=新窗口();
waitWindow.Loaded+=(s,e)=>
{
线程工作线程=新线程(()=>
{
//在通过
//等待窗口作为参数
toDo(waitWindow,actionParams);
}){IsBackground=true};
//启动工作线程。
workThread.Start();
};
waitWindow.Show();
Dispatcher.Run();
}){ApartmentState=ApartmentState.STA,IsBackground=true};
//启动等待窗口线程。
//当窗口加载时,它将创建工作线程并启动它。
windowThread.Start();
}
私有void MyWork(窗口等待窗口,对象参数)
{
对于(int i=0;i<10;i++)
{
//通过等待窗口向用户报告进度。
waitWindow.Dispatcher.BeginInvoke((操作)(()=>waitWindow.Title=string.Format(“{0}:{1}”,参数,i)),DispatcherPriority.Normal);
//模拟长时间工作。
睡眠(500);
}
//工作完成。关闭等待窗口dispather。
//这将停止侦听事件,并最终终止
//等待窗口线程。
waitWindow.Dispatcher.InvokeShutdown();
}
私有无效按钮1\u单击(对象发送者,路由目标)
{
DoSomeHardWork(我的工作,DateTime.Now);
}
理想情况下,创建UI元素的线程(UI线程)也会拥有这些元素。使用dispatcher,您所做的只是将与UI无关的处理推送到后台线程中。后台进程完成后,结果将再次推回到主UI线程。查看示例:谢谢您的回复和代码。这就是我想做的:1。单击buttonStartStop时,我希望另一个类中的方法在另一个线程中启动和运行。2.“开始”方法将打开一个新窗口,其中包含一个文本框,当它工作时,它将更新文本框以提供用户反馈。为什么不先创建文本框表单,然后新表单可以创建线程并启动它。在这种情况下,我将在当前GUI线程中正常打开窗口,并在后台线程中完成所有其他工作。打开的窗口上的更新可以直接通过GUI调度程序进行。你将如何组织并不重要。只要考虑一下:1。若窗口是在后台线程中创建的,那个么必须将线程设置为STA,并在Show()之后调用Dispatcher.Run()。2.对已打开窗口的所有调用都应通过其dispatcher对象进行。3.“进度信息”窗口不应位于执行处理的同一线程中,否则将被阻止。如果你需要一些代码。。。请评论我。@user1018735谢谢,我希望有一些示例代码。我一直在努力让这一切顺利进行
public static void DoSomeHardWork(Action<Window, object> toDo, object actionParams)
{
Thread windowThread = new Thread(() =>
{
Window waitWindow = new Window();
waitWindow.Loaded += (s, e) =>
{
Thread workThread = new Thread(() =>
{
// Run work method in work thread passing the
// wait window as parameter
toDo(waitWindow, actionParams);
}) { IsBackground = true };
// Start the work thread.
workThread.Start();
};
waitWindow.Show();
Dispatcher.Run();
}) { ApartmentState = ApartmentState.STA, IsBackground = true };
// Start the wait window thread.
// When window loads, it will create work thread and start it.
windowThread.Start();
}
private void MyWork(Window waitWindow, object parameters)
{
for (int i = 0; i < 10; i++)
{
// Report progress to user through wait window.
waitWindow.Dispatcher.BeginInvoke((Action)(() => waitWindow.Title = string.Format("{0}: {1}", parameters, i)), DispatcherPriority.Normal);
// Simulate long work.
Thread.Sleep(500);
}
// The work is done. Shutdown the wait window dispather.
// This will stop listening for events and will eventualy terminate
// the wait window thread.
waitWindow.Dispatcher.InvokeShutdown();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
DoSomeHardWork(MyWork, DateTime.Now);
}