There are times when the response from a click is going to take a little while - fetching information from a web page, downloading a file, queuing a video...some of these things take time, and the user doesn't like to have their Media Center 'lock up' while they are waiting for it.
When this happens, it's time to bring out the good old Thread class once again, and start playing.
There are a couple of things you should be aware of though before you write your threaded application.
If you have some experience with Windows Forms applications (and I hope you do - it will make your Media Center development life much easier), you will know that it is impossible to change the text or the appearance of a control from any thread other than the thread the window was opened in (eg. the Application Thread).
The same rule applies to Media Center applications and the FirePropertyChanged function of ModelItem. If you are going to call FirePropertyChanged, it must be from the application thread, otherwise it will fail.
Note that if you call FirePropertyChanged from the wrong thread, you probably won't get an exception like you do with Windows Forms - the notification will be 'lost' and you may start getting erratic behaviour out of your application.
So how do you manage to change a property value then? Well, you create a member function that takes a single parameter of type 'object' (even if you don't USE the parameter, create it) and then call...
Application.DeferredInvoke(<function name>,<parameter>);
The 'Application' object is a global one, and the DeferredInvoke function tells Media Center and the .NET system to run the <function name> function in the APPLICATION's thread, next time that thread is available for a little extra work.
I personally like to make my work even easier, by using the following code in any property that I expect to be accessed from a thread other than the main application thread...
In The Object That Has Properties....
internal void FPC(object Val)
{
String Value = (String)Val;
if (Application.IsApplicationThread() == true)
FirePropertyChanged(Value);
else
{
Application.DeferredInvoke(FPC,Value);
}
}
The Actual Property Itself...
string _MyStringValue;
public string MyStringValue
{
get { return _MyStringValue; }
set
{
_MyStringValue = value;
FPC("MyStringValue");
}
};
Because the FPC (which is short for FirePropertyChanged) actually conforms to the format needed to pass to the DeferredInvoke function, it's actually recursive. If you try to set the MyStringValue property, FPC is called.
If FPC detects that it has been called from the application thread (by using the IsApplicationThread() command), it simply calls FirePropertyChanged. If it finds that it isn't in the application's thread, it calls itself again using DeferredInvoke. The 2nd time it runs, it WILL be in the right thread.
This greatly simplifies your programming, because you simply have to make sure that you ALWAYS use the publically exposed property name when you are accessing MyStringValue.
Unfortunately, while this protects you when playing with your own properties that are based on simple type (eg. Int32, String, Bool etc.) it won't help with any type that is already based on ModelItem.
These types - like IntRangedValue, Choice, EditableText, ArrayListDataSet etc. already use FirePropertyChanged internally. So you must ensure that you only actually interact with these classes in the correct Application thread.