Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从另一个线程在UI线程上运行方法_C#_Multithreading - Fatal编程技术网

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

C# 从另一个线程在UI线程上运行方法,c#,multithreading,C#,Multithreading,我有一个班,播放一些像这样的音乐。在构造期间,它还将GUI线程id保存在私有int中: public class MediaPlayer { public event EventHandler<Track> OnTrackComplete; private int GuiThreadId; public MediaPlayer(...){ ... this.GuiThreadId = Thread.CurrentThread.Man

我有一个班,播放一些像这样的音乐。在构造期间,它还将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);
    }
}

为了能够在另一个线程上执行代码,必须有一个队列或消息泵等待处理新项目

这已经在winforms和wpf中通过
Control.Invoke
IDispatcher.Invoke
完成。如果您真的不想让
控件
执行监听,则必须将该控件传递到
MediaPlayer
。这真的很尴尬,但是有一个很大的抱怨,所以第一个答案是“你停止做你想做的事情怎么样?”。。下面是:

public class MediaPlayer {

    public event EventHandler<Track> OnTrackComplete;
    private int GuiThreadId;
    private readonly Control control;

    public MediaPlayer(..., Control control){
      ...
      this.GuiThreadId = Thread.CurrentThread.ManagedThreadId;
      this.contrl = control;
    }

    public void Play(){
        Task t = Task.Factory.StartNew(() =>
        {

            //On Song complete
            FireOnTrackComplete();
        });
    }

    protected virtual void FireOnTrackComplete()
    {
        var trackComplete = OnTrackComplete;
        if (onTrackComplete != null)
            this.control.Invoke((MethodInvoker) delegate {trackComplete(this, loadedTrack);});
    }
}
公共类MediaPlayer{
公共事件事件处理程序OnTrackComplete;
私有int-id;
专用只读控制;
公共媒体播放器(…,控制){
...
this.GuiThreadId=Thread.CurrentThread.ManagedThreadId;
this.controll=控制;
}
公共游戏{
Task t=Task.Factory.StartNew(()=>
{
//歌曲全集
FireOnTrackComplete();
});
}
受保护的虚拟void FireOnTrackComplete()
{
var trackComplete=OnTrackComplete;
如果(onTrackComplete!=null)
调用((MethodInvoker)委托{trackComplete(this,loadedTrack);});
}
}

抱歉,如果有错别字,我面前没有任何东西可以核实;但这应该能让您了解您的目的。

为了能够在另一个线程上执行代码,您必须有一个队列或消息泵等待处理新项目

这已经在winforms和wpf中通过
Control.Invoke
IDispatcher.Invoke
完成。如果您真的不想让
控件
执行监听,则必须将该控件传递到
MediaPlayer
。这真的很尴尬,但是有一个很大的抱怨,所以第一个答案是“你停止做你想做的事情怎么样?”。。下面是:

public class MediaPlayer {

    public event EventHandler<Track> OnTrackComplete;
    private int GuiThreadId;
    private readonly Control control;

    public MediaPlayer(..., Control control){
      ...
      this.GuiThreadId = Thread.CurrentThread.ManagedThreadId;
      this.contrl = control;
    }

    public void Play(){
        Task t = Task.Factory.StartNew(() =>
        {

            //On Song complete
            FireOnTrackComplete();
        });
    }

    protected virtual void FireOnTrackComplete()
    {
        var trackComplete = OnTrackComplete;
        if (onTrackComplete != null)
            this.control.Invoke((MethodInvoker) delegate {trackComplete(this, loadedTrack);});
    }
}
公共类MediaPlayer{
公共事件事件处理程序OnTrackComplete;
私有int-id;
专用只读控制;
公共媒体播放器(…,控制){
...
this.GuiThreadId=Thread.CurrentThread.ManagedThreadId;
this.controll=控制;
}
公共游戏{
Task t=Task.Factory.StartNew(()=>
{
//歌曲全集
FireOnTrackComplete();
});
}
受保护的虚拟void FireOnTrackComplete()
{
var trackComplete=OnTrackComplete;
如果(onTrackComplete!=null)
调用((MethodInvoker)委托{trackComplete(this,loadedTrack);});
}
}
抱歉,如果有错别字,我面前没有任何东西可以核实;但这会让你得到你想要的东西。

本书旨在解决这个问题。在构造函数中复制其当前属性的值,稍后使用其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;
}
这个计划的目的是解决这个问题。在构造函数中复制其当前属性的值,稍后使用其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;
}

将引用传递给主调度程序(=GUI线程的调度程序),并使用回调代码直接对其调用Invoke

public class MediaPlayer {

    public event EventHandler<Track> OnTrackComplete;
    private Dispatcher { get; set; }

    public MediaPlayer(Dispatcher guiDispatcher){
        // Other code ...
        if(guiDispatcher == null) 
            throw new ArgumentNullException("guiDispatcher", "Cannot properly initialize media player, since no callback can be fired on GUI thread.");
        Dispatcher = guiDispatcher;
    }

    public void Play() {
        // Fire immediately on thread calling 'Play', since we'll forward exec. on gui thread anyway.
        FireOnTrackComplete(); 
    }

    protected virtual void FireOnTrackComplete()
    {
        // Pretending "loadedTrack" was set somewhere before.
        Dispatcher.Invoke(() => {
            if (OnTrackComplete != null)
                OnTrackComplete(this, loadedTrack);
        });
    }
}
// Somewhere in your initialization code
// ...
MediaPlayer player = new MediaPlayer(App.Current.Dispatcher); // If you use WPF. Don't know if this applies to WinForms too.
// ...
公共类MediaPlayer{
公共事件事件处理程序OnTrackComplete;
专用调度程序{get;set;}
公共媒体播放器(调度程序){
//其他代码。。。
if(guiDispatcher==null)
抛出新ArgumentNullException(“guiDispatcher”,“无法正确初始化媒体播放器,因为无法在GUI线程上触发回调。”);
调度员=guiDispatcher;
}
公共游戏{
//在调用“Play”的线程上立即触发,因为我们将转发gui线程上的exec。
FireOnTrackComplete();
}
受保护的虚拟void FireOnTrackComplete()
{
//假装“loadedTrack”是在以前的某个地方设置的。
Dispatcher.Invoke(()=>{
如果(OnTrackComplete!=null)
OnTrackComplete(此为加载的Track);
});
}
}
//在初始化代码中的某个地方
// ...
MediaPlayer=新的MediaPlayer(App.Current.Dispatcher);//如果你使用WPF。不知道这是否也适用于WinForms。
// ...

将引用传递给主调度程序(=GUI线程的调度程序),并使用回调代码直接调用调用

public class MediaPlayer {

    public event EventHandler<Track> OnTrackComplete;
    private Dispatcher { get; set; }

    public MediaPlayer(Dispatcher guiDispatcher){
        // Other code ...
        if(guiDispatcher == null) 
            throw new ArgumentNullException("guiDispatcher", "Cannot properly initialize media player, since no callback can be fired on GUI thread.");
        Dispatcher = guiDispatcher;
    }

    public void Play() {
        // Fire immediately on thread calling 'Play', since we'll forward exec. on gui thread anyway.
        FireOnTrackComplete(); 
    }

    protected virtual void FireOnTrackComplete()
    {
        // Pretending "loadedTrack" was set somewhere before.
        Dispatcher.Invoke(() => {
            if (OnTrackComplete != null)
                OnTrackComplete(this, loadedTrack);
        });
    }
}
// Somewhere in your initialization code
// ...
MediaPlayer player = new MediaPlayer(App.Current.Dispatcher); // If you use WPF. Don't know if this applies to WinForms too.
// ...
公共类MediaPlayer{
公共事件事件处理程序OnTrackComplete;
专用调度程序{get;set;}
公共媒体播放器(调度程序){
//其他代码。。。
if(guiDispatcher==null)
抛出新ArgumentNullException(“guiDispatcher”,“无法正确初始化媒体播放器,因为无法在GUI线程上触发回调。”);
调度员=guiDispatcher;
}
公共游戏{
//在调用“Play”的线程上立即触发,因为我们将转发gui线程上的exec。
FireOnTrackComplete();
}
受保护的虚拟void FireOnTrackComplete()
{
//假装“loadedTrack”是在以前的某个地方设置的。
Dispatcher.Invoke(()=>{
如果(OnTrackComplete!=null)
OnTrackComplete(此为加载的Track);
});
}
}
//在初始化代码中的某个地方
// ...
MediaPlayer=新的MediaPlayer(App.Current.Dispatcher);//如果你使用WPF。不知道这是否也适用于WinForms。
// ...

我建议立即存储对主(=GUI)调度器的引用,而不是冗余地存储threadId和控件。这样您就可以简单地执行:
\u guiDispatcher.Invoke(()=>{FireOnTrackComplete();})@Jay是的我可以这么做但是