事件中的控制文本更新会引发非法的跨线程异常

时间:2017-02-05 16:56:33

标签: c# asynchronous invalidoperationexception

我正在通过关键字以编程方式进行Youtube搜索,并使用Youtube API执行此操作。我希望在搜索进度完成时触发事件,并将结果返回YoutubeSearchCompletedEventArgs发送的YoutubeSearchCompleted

但是YoutubeSearchCompleted中的Form.cs中的代码会引发跨线程非法操作异常。通常,使用AsyncOperation.Post方法时,它不能抛出InvalidOperationException。因为我之前在下载管理器项目中使用了相同的方法并且运行良好。所以我无法理解为什么会这样。

  

Youtube搜索类

class YouTubeManager
{
    public delegate void YoutubeSearchCompletedEventHandler(object sender, YoutubeSearchCompletedEventArgs e);
    public event YoutubeSearchCompletedEventHandler YoutubeSearchCompleted;
    AsyncOperation aop = AsyncOperationManager.CreateOperation(null);

    List<YoutubeVideo> SearchByKeyword(string keyword)
    {
        List<YoutubeVideo> videos = new List<YoutubeVideo>();

        //.......
        //...Youtube data api search codes....
        //.......

        return videos;
    }
    public void Search(string keyword)
    {
        Task.Run(() =>
        {
            List<YoutubeVideo> list = SearchByKeyword(keyword);
            aop.Post(new System.Threading.SendOrPostCallback(delegate
            {
                if (YoutubeSearchCompleted != null)
                    YoutubeSearchCompleted(this, 
                        new YoutubeSearchCompletedEventArgs(keyword, list);
            }), null);
        });
    }
}
  

Form.cs

public partial class Form1 : Form
{
    YouTubeManager yam = new YouTubeManager();
    public Form1()
    {
        InitializeComponent();
        this.Load += Form1_Load;
    }

    void Form1_Load(object sender, EventArgs e)
    {
        yam.YoutubeSearchCompleted += yam_YoutubeSearchCompleted;
        yam.Search("Blues");
    }

    void yam_YoutubeSearchCompleted(object sender, YoutubeSearchCompletedEventArgs e)
    {
        if (e.Videos.Count < 1) return;

        textBox1.Text = e.Videos[0].Title();
    }
}

在此代码中,textBox1.Text = e.Videos[0].Title();行抛出InvalidOperationException。我该如何解决这个问题?

注意:我不想要Invoke方法,只需AsyncOperation

1 个答案:

答案 0 :(得分:3)

问题很可能是由AsyncOperation过早创建引起的。您可以通过以下方式检查:

if (!(aop.SynchronizationContext is WindowsFormsSynchronizationContext))
{
    // Oops - we have an issue
}

为什么? AsyncOperation在构建时存储SynchronizationContext.Current,通常所有Control派生类(包括Form)在WindowsFormsSynchronizationContext内安装Control类构造函数。

但请设想Forgm1是您的创业形式(例如来自Application.Run(new Form1());的典型Main)。从Any instance variable initializers in the derived class are executed before the base class constructor开始,在aop变量初始化时(通过yam字段初始值设定项),Control类构造函数尚未运行,因此WindowsFormsSynchronizationContext未安装,因此使用默认AsynOperation初始化SynchronozationContext,默认Post通过在单独的线程上执行它来实现YouTubeManager yam;

修复很简单 - 不要使用初始化程序,只需定义字段

yam = new YouTubeManager();

并移动初始化

SceneKit Editor

在表单构造函数或load事件中。