从另一个线程在UI线程上运行方法

Kri*_*son 1 c# multithreading

我有一节课,播放这样的音乐.它还在构造期间将GUI线程id保存在私有int中:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

是否可以调用FireOnTrackComplete()具有特定ID的线程.在这种情况下,ID存储在this.GuiThreadId?

我遇到的大多数解决方案都建议我在监听OnTrackComplete事件处理程序的方法中使用GUI代码中的调用.我想避免这样做.我想在MediaPlayer课堂上做所有事情


根据接受的答案,这是我改变代码的方式

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 7

该的SynchronizationContext类是为了解决这个问题.在构造函数中复制其Current属性的值,稍后使用其Post()或Send()方法.这可确保您的库可以与任何GUI类库一起使用.像这样:

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;
}
Run Code Online (Sandbox Code Playgroud)