I’ve recently been playing around with ASP.NET’s new MVC (Model View Controller) framework and have to say, its pretty cool. You can find MVC downloads, tutorials and other errata here.
However, I ran into abit of a problem with MVC when using Silverlight applications inside MVC Views. Views should simply display the Model data passed to it by the Controller using (as illustrated in diagram 1).
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server"> <h2><%= Html.Encode(ViewData["Message"]) %></h2> <p> To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>. </p> </asp:Content>
If you want your View to contain a Silverlight app that contains no Model data, then there’s no problem. Simply embed the Silverlight into the ASPX View using either the raw HTML or the ASP.NET Silverlight control and it works.
However, the problem comes when you want the Silverlight app to display/manipulate/use the Model data passed to the View by the Controller. You can of course get the Model data into Silverlight using web service calls or by making HTTP requests from Silverlight to your Controller (as illustrated by Tim Heuer in this post), but this violates the MVC pattern. Ideally your Silverlight app should work in a similar way to the MVC Views, simply displaying the data that is passed to it.
So, how do you initialise Silverlight with the data it needs? Well, I found that I could pass all the data my Silverlight app needed to display using the ‘initParams’! – sneaky huh.
Basically, these are the steps involved:
public ActionResult Search() { // Call Model to do Search // Set results as View's Model data (we're using dummy data) ViewData.Model = new SearchResult[] { new SearchResult(){Title="Search Result 1", Relevance=100}, new SearchResult(){Title="Search Result 2", Relevance=75}, new SearchResult(){Title="Search Result 3", Relevance=100} }.ToList(); // Return View ActionResult containing our Model Data return View(); }
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<List<MvcSilverlight.SearchResult>>" %> <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server"> <title>Silverlight</title> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>Silverlight Results Page</h2> <div id="silverlightControlHost"> <% System.Text.StringBuilder jsonText = new System.Text.StringBuilder(); var results = ViewData.Model.Select(sr => new {Title=sr.Title, Relevance = sr.Relevance }); System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); serializer.Serialize(results, jsonText); string initParams = string.Format("{0}={1}","model", HttpUtility.UrlEncode(jsonText.ToString())); %> <object data="data:application/x-silverlight-2" type="application/x-silverlight-2" width="300px" height="300px"> <param name="source" value="/ClientBin/SilverlightApplication1.xap" /> <param name="minRuntimeVersion" value="2.0.31005.0" /> <% Response.Write(string.Format("<param name=\"initParams\" value=\"{0}\"/>", initParams)); %> <param name="windowless" value="true" /> <param name="Background" value="#00FFFFFF" /> </object> </div> </asp:Content>
public static IDictionary<string, string> initParams = new Dictionary<string, string>(); private void Application_Startup(object sender, StartupEventArgs e) { this.RootVisual = new Page(); App.initParams = e.InitParams; }
void Page_Loaded(object sender, RoutedEventArgs e) { // Deserialize Init Params List<SearchResult> results = null; using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(HttpUtility.UrlDecode(App.initParams["model"].ToString())))) { DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<SearchResult>)); results = (List<SearchResult>)serializer.ReadObject(ms); } // Set deserialized search results as DataGrid ItemsSource this.ResultsGrid.ItemsSource = results.ToList(); }
Hope that helps. You can get the source code for this sample here.