Just something that someone asked me about today so sharing here. Imagine that you want to define a portion of your Silverlight application but leave some other piece to run time.
For example - a calculation engine or perhaps something more complicated like a piece of UI with interaction.
You can dynamically load up a .NET assembly in Silverlight at runtime, pull out known types from it and interact with them just like you would in any other .NET application.
I made my example as simple as possible. I defined a core UI which looks like this;
The idea is that the red bit is the "host" and the yellow bit is for the plug-in editor. I define an interface to live between my host and my plug-in editor;
public class TextEventArgs : EventArgs
{
public string TheText { get; set; }
}
public interface IEditUI
{
UIElement GetControls();
void SetText(string text);
event EventHandler TextChanged;
}
and then an implementation of that which I put into an assembly called Implementation which is not referenced by my Silverlight application.
public class Editor : IEditUI
{
public Editor()
{
textBox = new TextBox();
}
public UIElement GetControls()
{
StackPanel stackPanel = new StackPanel();
stackPanel.Margin = new Thickness(5);
stackPanel.Orientation = Orientation.Horizontal;
textBox = new TextBox();
textBox.Width = 100;
Button button = new Button();
button.Content = "Click Me";
button.Click += OnButtonClick;
stackPanel.Children.Add(textBox);
stackPanel.Children.Add(button);
return (stackPanel);
}
void OnButtonClick(object sender, RoutedEventArgs e)
{
if (TextChanged != null)
{
TextChanged(this, new TextEventArgs() { TheText = textBox.Text });
}
}
public void SetText(string text)
{
textBox.Text = text;
}
private TextBox textBox;
public event EventHandler TextChanged;
}
Then, at runtime I can write code which will load this up and make use of it as in;
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}
void OnLoadDynamicEditor(object sender, EventArgs args)
{
WebClient client = new WebClient();
client.OpenReadCompleted += new OpenReadCompletedEventHandler(OnAssemblyOpened);
client.OpenReadAsync(new Uri("Implementation.dll", UriKind.Relative));
}
void OnAssemblyOpened(object sender, OpenReadCompletedEventArgs e)
{
AssemblyPart assemblyPart = new AssemblyPart();
Assembly assembly = assemblyPart.Load(e.Result);
editor = assembly.CreateInstance("Implementation.Editor") as IEditUI;
if (editor != null)
{
hostGrid.Children.Add(editor.GetControls());
editor.TextChanged += OnEditorTextChanged;
}
}
void OnSendToEditor(object sender, EventArgs args)
{
if (editor != null)
{
editor.SetText(txtHost.Text);
}
}
void OnEditorTextChanged(object sender, TextEventArgs e)
{
txtHost.Text = e.TheText;
}
IEditUI editor;
}
And now I have a ( very basic! ) but hosted UI inside of another piece of UI. I put the project file here for download. Note: The Implementation.dll assembly needs to be manually copied to the ClientBin folder of the website project in order for this to work.