我正在主线程上进行一些繁重的计算,这些计算无法在单独的线程上运行。
我希望在运行这些计算时在应用程序UI上显示“忙碌指示符”(即旋转小部件)。因此,当这些计算正在运行时,由于UI被锁定,我无法在主线程上显示忙碌指示符。
要解决此问题,我尝试将忙指示符移动到单独的线程。在this post的帮助下,我可以将忙指示符放在单独的线程上。但是,我无法与此线程通信以启动或停止忙指示符。
private HostVisual CreateBusyIndicatorOnWorkerThread()
{
// Create the HostVisual that will "contain" the VisualTarget
// on the worker thread.
HostVisual hostVisual = new HostVisual();
Thread thread = new Thread(new ParameterizedThreadStart(BusyIndicatorWorkerThread));
thread.ApartmentState = ApartmentState.STA;
thread.IsBackground = true;
thread.Start(hostVisual);
// Wait for the worker thread to spin up and create the VisualTarget.
s_event.WaitOne();
return hostVisual;
}
private static AutoResetEvent s_event = new AutoResetEvent(false);
private void BusyIndicatorWorkerThread(object arg)
{
// Create the VisualTargetPresentationSource and then signal the
// calling thread, so that it can continue without waiting for us.
HostVisual hostVisual = (HostVisual)arg;
VisualTargetPresentationSource visualTargetPS = new VisualTargetPresentationSource(hostVisual);
s_event.Set();
// Create a MediaElement and use it as the root visual for the
// VisualTarget.
visualTargetPS.RootVisual = CreateBusyIndicator();
// Run a dispatcher for this worker thread. This is the central
// processing loop for WPF.
System.Windows.Threading.Dispatcher.Run();
}
private FrameworkElement CreateBusyIndicator()
{
var busyIndicator = new MyBusyIndicator();
//busyIndicator.DataContext = this.
Binding myBinding = new Binding("IsBusy");
myBinding.Source = this;
busyIndicator.SetBinding(MyBusyIndicator.IsBusyProperty, myBinding);
}
我总是得到一个异常“调用线程无法访问此对象,因为另一个线程拥有它”。这是因为我正在尝试从主线程更新忙指示符,而忙指示符由另一个线程拥有。
我也试过this article,
中给出的方法private void CreateAndShowContent()
{
Dispatcher = Dispatcher.CurrentDispatcher;
VisualTargetPresentationSource source =
new VisualTargetPresentationSource(_hostVisual);
_sync.Set();
source.RootVisual = _createContent();
DesiredSize = source.DesiredSize;
_invalidateMeasure();
Dispatcher.Run();
source.Dispose();
}
但是使用这种方法Dispatcher.Run()在完成计算之后才会发生任何事情,然后显示忙碌指示符。
我想从主线程到具有忙指示符的线程进行通信。有人有办法吗?
答案 0 :(得分:4)
没有理由在UI线程中运行“繁重的计算”。更多 - 这是一个不好的做法。而是使用BackgroundWorker
这将起作用,同时活着的UI线程将显示加载/计算:
var worker = new BackgroundWorker();
worker.DoWork += (s, e) => {
// This part will last at a separate thread without blocking UI.
// Excellent place for heavy computations.
}
worker.RunWorkerCompleted += (s, e) => {
// Here we're back to UI thread - so you can change states and stop animations.
}
// And finally start async computation
worker.RunWorkerAsync();
用户界面应该包含BusyIndicator
控件,当启动/完成工作时,激活/停止。
答案 1 :(得分:1)
请停止你正在做的事......这是完全错误的。 @Anatolii Gabuza是正确的......你不应使用UI线程任何长时间运行的进程,因为这会阻止它,使得应用程序在这些时候无法使用。除非你的长时间运行过程是渲染UI对象,否则确实有没有的理由使用UI线程...让我们知道它是什么,我们可以帮助你在后台运行它线程正确。
所以你发现你无法在UI线程上显示繁忙的指示器,因为它忙于你长时间运行的过程......此时,大多数开发人员会意识到他们的错误,但不幸的是,不是你。你不是接受长时间运行的进程应该在后台线程上运行,而是完全相反,现在想在后台线程中显示一些UI元素,同时用长时间运行的进程阻塞UI线程???
这真是疯狂,如果你想避免一些可怕的问题,请停止。如果你继续,那么你最好习惯看到那个例外:
调用线程无法访问此对象,因为另一个线程拥有它。
答案 2 :(得分:1)
您需要调用busyContainer调度程序。使用如下
this.busyContainer.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
{
//update busy Container
}));
答案 3 :(得分:-4)
我从SO那里得到了这个,但是在SO上找不到它 在UI线程上运行此命令,并将任务放在任务很长的任务
中public class WaitCursor : IDisposable
{
private Cursor _previousCursor;
public WaitCursor()
{
_previousCursor = Mouse.OverrideCursor;
Mouse.OverrideCursor = Cursors.Wait;
}
#region IDisposable Members
public void Dispose()
{
Mouse.OverrideCursor = _previousCursor;
}
#endregion
}
using (new WaitCursor())
{
// very long task
}