从另一个线程在UI线程上运行方法 [英] Run method on UI thread from another thread

查看:101
本文介绍了从另一个线程在UI线程上运行方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一堂课,播放这样的音乐.还将在构建过程中将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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆