I am working on a Youtube search by keyword programmatically and using Youtube API to do this. I want to fire an event when a search progress is completed and return the result in
YoutubeSearchCompletedEventArgs
YoutubeSearchCompleted
YoutubeSearchCompleted
Form.cs
AsyncOperation.Post
InvalidOperationException
Youtube search class
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
Most likely the issue is caused by AsyncOperation
created too early. You can check that with the following:
if (!(aop.SynchronizationContext is WindowsFormsSynchronizationContext))
{
// Oops - we have an issue
}
Why is that? The AsyncOperation
stores the SynchronizationContext.Current
at the construction time, and normally all Control
derived classes (including the Form
) install WindowsFormsSynchronizationContext
from inside the Control
class constructor.
But imagine the Forgm1
is your startup form (e.g. the typical Application.Run(new Form1());
call from Main
). Since Any instance variable initializers in the derived class are executed before the base class constructor, at the time aop
variable is initialized (through yam
field initializer), the Control
class constructor has not been ran yet, hence the WindowsFormsSynchronizationContext
is not installed, so the AsynOperation
is initialized with the default SynchronozationContext
, which implements Post
by simply executing it on separate thread.
The fix is simple - don't use initializer, just define the field
YouTubeManager yam;
and move the initialization
yam = new YouTubeManager();
inside the form constructor or load event.