阻止UI线程,但继续处理传入呼叫
本文关键字:处理 入呼叫 继续 UI 线程 阻止 | 更新日期: 2023-09-27 18:26:33
我正在为3D建模应用程序开发一个插件。对于这个应用程序,还有一个第三方插件(一个渲染引擎),我想自动化它。
我所做的是创建一个Camera List<Camera> cameraViews
的列表,遍历所有这些列表,并告诉渲染引擎开始渲染
foreach ( Camera camera in cameraViews )
{
// tell the modellingApplication to apply camera
modellingApplication.ApplyCameraToView(camera);
// tell the render engine to render the image
string path = "somePathWhereIWantToSaveTheImage"
renderEngine.renderCurrentScene(path)
// .renderCurrentScene() seems to be async, because my code, which is on the UI thread
// continues... so:
// make sure that the image is saved before continuing to the next image
while ( !File.Exists(path) )
{
Thread.Sleep(500);
}
}
然而,这是行不通的。renderingplugin似乎做了一些异步工作,但在做这种异步工作时,它调用的是用于检索信息的主线程。
我找到了一个解决方法:在调用渲染引擎进行渲染后,立即调用MessageBox。这将阻止代码继续运行,但异步调用仍在处理中。我知道,这是一种奇怪的行为。更奇怪的是,当渲染引擎调用UI线程获取信息并在自己的进程中继续时,我的MessageBox会自动关闭。让我的代码继续执行while循环,检查图像是否保存在磁盘上。
foreach ( Camera camera in cameraViews )
{
// tell the modellingApplication to apply camera
modellingApplication.ApplyCameraToView(camera);
// tell the render engine to render the image
string path = "somePathWhereIWantToSaveTheImage"
renderEngine.renderCurrentScene(path)
// .renderCurrentScene() seems to be async, because my code, which is on the UI thread
// continues... so:
// show the messagebox, as this will block the code but not the renderengine.. (?)
MessageBox.Show("Currently processed: " + path);
// hmm, messagebox gets automatically closed, that's great, but weird...
// make sure that the image is saved before continuing to the next image
while ( !File.Exists(path) )
{
Thread.Sleep(500);
}
}
这太棒了,除了消息框部分。我不想显示消息框,我只想暂停我的代码而不阻塞整个线程(因为从渲染引擎到ui线程的调用仍然可以接受)。。
如果渲染引擎没有异步完成他的工作,那会容易得多。。
我觉得这不是最好的答案,但希望这正是你想要的。这就是阻止线程继续的方法。
// Your UI thread should already have a Dispatcher object. If you do this elsewhere, then you will need your class to inherit DispatcherObject.
private DispatcherFrame ThisFrame;
public void Main()
{
// Pausing the Thread
Pause();
}
public void Pause()
{
ThisFrame = new DispatcherFrame(true);
Dispatcher.PushFrame(ThisFrame);
}
public void UnPause()
{
if (ThisFrame != null && ThisFrame.Continue)
{
ThisFrame.Continue = false;
ThisFrame = null;
}
}
如果你想在中间阻塞的同时仍然接收并在该线程上执行操作,你可以这样做。这感觉,嗯…有点烦人,所以不要只是复制和粘贴,而不确保我没有在打字时犯一些重大错误。我还没喝咖啡。
// Used while a work item is processing. If you have something that you want to wait on this process. Or you could use event handlers or something.
private DispatcherFrame CompleteFrame;
// Controls blocking of the thread.
private DispatcherFrame TaskFrame;
// Set to true to stop the task manager.
private bool Close;
// A collection of tasks you want to queue up on this specific thread.
private List<jTask> TaskCollection;
public void QueueTask(jTask newTask)
{
//Task Queued.
lock (TaskCollection) { TaskCollection.Add(newTask); }
if (TaskFrame != null) { TaskFrame.Continue = false; }
}
// Call this method when you want to start the task manager and let it wait for a task.
private void FireTaskManager()
{
do
{
if (TaskCollection != null)
{
if (TaskCollection.Count > 0 && TaskCollection[0] != null)
{
ProcessWorkItem(TaskCollection[0]);
lock (TaskCollection) { TaskCollection.RemoveAt(0); }
}
else { WaitForTask(); }
}
}
while (!Close);
}
// Call if you are waiting for something to complete.
private void WaitForTask()
{
if (CompleteFrame != null) { CompleteFrame.Continue = false; }
// Waiting For Task.
TaskFrame = new DispatcherFrame(true);
Dispatcher.PushFrame(TaskFrame);
TaskFrame = null;
}
/// <summary>
/// Pumping block will release when all queued tasks are complete.
/// </summary>
private void WaitForComplete()
{
if (TaskCollection.Count > 0)
{
CompleteFrame = new DispatcherFrame(true);
Dispatcher.PushFrame(CompleteFrame);
CompleteFrame = null;
}
}
private void ProcessWorkItem(jTask taskItem)
{
if (taskItem != null) { object obj = taskItem.Go(); }
}