![](/img/trans.png)
[英]Inconsistent handling of UI calls from non-UI thread for TabControl
[英]Block UI thread but keep handling incoming calls
我正在為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。 這將阻止代碼繼續執行,但異步調用仍將繼續處理。 我知道,這是奇怪的行為。 更奇怪的是,當renderengine完成調用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);
}
}
除了消息框部分之外,這真是太好了。 我不想顯示一個消息框,我只是想暫停我的代碼而不阻塞整個線程(因為仍然接受從renderengine到ui線程的調用)。
如果renderengine不異步完成工作,那會容易得多。
我覺得這不是最好的答案,但希望它就是您要尋找的。 這就是您阻止線程繼續的方式。
// 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(); }
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.