I recently was writing a video player in Silverlight 2 beta 2 and there was a requrement that when you hit PLAY on one player, all the others stopped. That's fine, I thought, I'll just create a static list and add each instance to the list in the constructor. Only trouble was, this didn't work because these were different instances of Silverlight on the page, so different CLR instances. What I needed was a way to call across app domains between the Silverlight instances. What I did was pretty clean so I thought I'd post about it.

I registered my class as JavaScript callable, then called it from C# using the Silverlight bridge!

private const string player_name = "My_Silverlight_VideoPlayer";
private
static int instanceCount = 0;
private int thisInstance = 0;

public Player()
{
    this.thisInstance = ++instanceCount;
    RegisterPlayerWithJavaScript();
}

// We want to call methods on all other instances of this class (eg to Pause all videos on a
// page when we are playing). However, the other players are in other instances of Silverlight
// controls which each host their own instance of the CLR, so we can't use statics. Instead
// we register ourself with JavaScript interop (which is global to the HTML page), and call the
// other instances through interop. See the GetPlayers() function below.

private void RegisterPlayerWithJavaScript()
{
   
for (int i = 0; i < 100; i++)
    {
       
string name = player_name + i.ToString();
       
object obj = HtmlPage.Window.GetProperty(name); // Look for an unused name
       
if (obj == null)
        {
           
HtmlPage.Window.SetProperty(name, HtmlPage.Plugin.Id + "," + this.thisInstance.ToString());
           
HtmlPage.RegisterScriptableObject("Player" + this.thisInstance.ToString(), this);
           
break;
        }
    }
}

private List<ScriptObject> GetPlayers(bool includeMe)
{
   
// return all players on the page
   
List<ScriptObject> list = new List<ScriptObject>();
   
for (int i = 0; i < 100; i++)
    {
       
string name = player_name + i.ToString();
       
string token = (string)HtmlPage.Window.GetProperty(name);
       
if (token == null)
        {
           
break;
        }

        string[] parts = token.Split(',');
       
string id = parts[0];
       
string instance = parts[1];
       
if (includeMe || id != HtmlPage.Plugin.Id || instance != this.thisInstance.ToString())
        {
           
ScriptObject that = (ScriptObject)HtmlPage.Window.Eval("document.getElementById('" + id + "').Content.Player" + instance);
            list.Add(that);
        }
    }
   
return list;
}

[ScriptableMember]
public void Pause()
{
    playerMediaElement.Pause();
}

// Usage - Pause all the players on the page (not including us)
foreach (ScriptObject that in GetPlayers(false))
{
    that.Invoke(
"Pause");
}

Cheers,
Paul