从另一个线程在UI线程上运行方法 [英] Run method on UI thread from another thread
问题描述
我有一堂课,播放这样的音乐.还将在构建过程中将GUI线程ID保存在一个私有int中:
I have a class which plays some music like this. It also saves the GUI thread id in a private int during construction:
public class MediaPlayer {
public event EventHandler<Track> OnTrackComplete;
private int GuiThreadId;
public MediaPlayer(...){
...
this.GuiThreadId = Thread.CurrentThread.ManagedThreadId;
}
public void Play(){
Task t = Task.Factory.StartNew(() =>
{
//On Song complete
FireOnTrackComplete();
});
}
protected virtual void FireOnTrackComplete()
{
if (OnTrackComplete != null)
OnTrackComplete(this, loadedTrack);
}
}
是否可以在具有特定ID的线程上调用FireOnTrackComplete()
.在这种情况下,ID存储在this.GuiThreadId
?
Is it possible to call FireOnTrackComplete()
on a Thread with a specific ID. In this case, the ID is stored in the this.GuiThreadId
?
我遇到的大多数解决方案都建议我在GUI代码中使用侦听OnTrackComplete
事件处理程序的方法中的调用.我想避免这样做.我想做MediaPlayer
类
Most of the solutions I have come across suggest I use invokes in my GUI code in methods which listen to the OnTrackComplete
event handler. I want to avoid doing this. I want to do everything in the MediaPlayer
class
根据下面给出的答案,这就是我更改代码的方式
public class MediaPlayer {
public event EventHandler<Track> OnTrackComplete;
private SynchronizationContext callerCtx;
public MediaPlayer(...){
...
callerCtx = System.Threading.SynchronizationContext.Current;
}
public void Play(){
Task t = Task.Factory.StartNew(() =>
{
//On Song complete
FireOnTrackComplete();
});
}
protected virtual void FireOnTrackComplete()
{
Action e = () =>
{
if (OnTrackComplete != null)
OnTrackComplete(this, loadedTrack);
};
FireEvent(e);
}
//... Other events ... //
protected virtual void FireEvent(Action e)
{
if (callerCtx == null)
e();
else
callerCtx.Post(new SendOrPostCallback((_) => e()), null);
}
}
推荐答案
The SynchronizationContext class was meant to solve this problem. Copy the value of its Current property in the constructor, use its Post() or Send() method later. This ensures your library will work with any GUI class library. Like this:
class MediaPlayer {
public MediaPlayer() {
callersCtx = System.Threading.SynchronizationContext.Current;
//...
}
private void FireOnTrackComplete() {
if (callersCtx == null) FireOnTrackCompleteImpl();
else callersCtx.Post(new System.Threading.SendOrPostCallback((_) => FireOnTrackCompleteImpl()), null);
}
protected virtual void FireOnTrackCompleteImpl() {
var handler = OnTrackComplete;
if (handler != null) handler(this, loadedTrack);
}
private System.Threading.SynchronizationContext callersCtx;
}
这篇关于从另一个线程在UI线程上运行方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!