An Introduction to KnockoutJS for XAML Developers

by Administrator 17. December 2011 18:58

I've recently been working with KnockoutJS and have found it to be a very comfortable paradigm to use in constructing a web site.  Having worked with XAML a good bit over the last few years, the benefits of MVVM have been made apparent to me time and again and the approach is familiar.

KnockoutJS lets you use very nearly the same MVVM approach you're used to using in WPF or Silverlight development.  I've attached a sample application, below.  Let's have a look at it.

If you run the sample application, you'll see the following web page open in the browser.

RunningApp

There is an editable table that allows the user to edit existing contacts. Clicking the Add Contact button adds a new blank row to the table.

The ViewModel

The project contains a Javascript file named ViewModel.cs, in the Scripts directory.  The contexts of this file are listed below.

   1:  var viewModel = {
   2:      contacts : ko.observableArray([
   3:          { firstName : "Bob", lastName : "Marley" },
   4:          { firstName : "Larry", lastName : "The Cable Guy" },
   5:          { firstName : "Maxwell", lastName : "Smart" }
   6:      ]),
   7:   
   8:      addContact : function() {
   9:          this.contacts.push( { firstName : "", lastName : "" } );
  10:      }
  11:  }
  12:   
  13:  $(document).ready(function() {
  14:      
  15:      ko.applyBindings(viewModel); 
  16:  })
 
 

In the first code block, lines 1 – 11, we create a view model.  In WPF or Silverlight, out view model would contain properties and commands that we could bind to in our view.  The same is true with KnockoutJS.  Here, we have a property that is a collection of contacts and a function (command).  In lines 13 – 16, we ask Knockout to parse our view and connect the data bindings to our view model.

Notice that our property is an instance of an observableArray.  In XAML data binding, we have the concept of  the view and view model communicating with one another where events are raised when values change so that data and the controls bound to it stay in sync.  This same functionality is encapsulated in the observableArray for arrays and observable for simple properties.    So, modifying a bound property from the view model will cause a control in the view that is bound to the property to change, as well.  The reverse is also true, modifying the contents of the control will update the view model property.

The View

   1:  @{
   2:      Layout = null;
   3:  }
   4:   
   5:  <!DOCTYPE html>
   6:  <html>
   7:  <head>
   8:      <title>Index</title>
   9:      <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
  10:      <script src="../../Scripts/jQuery.tmpl.js" type="text/javascript"></script>
  11:      <script src="../../Scripts/knockout-1.2.1.js" type="text/javascript"></script>
  12:      <script src="../../Scripts/ViewModel.js" type="text/javascript"></script>
  13:  </head>
  14:  <body>
  15:      <div>
  16:          <fieldset>
  17:              <legend>Email Addresses</legend>
  18:   
  19:                  <table>
  20:                  <thead>
  21:                      <tr>
  22:                          <th>First Name</th>
  23:                          <th>Last Name</th>
  24:                      </tr>
  25:                  </thead>
  26:                  <tbody 
  27:                    data-bind='template: { name: "contactRowTemplate", foreach: contacts }'>
  28:                  </tbody>
  29:              </table>
  30:   
  31:              <button data-bind="click: addContact">Add Contact</button>
  32:   
  33:              <script type="text/html" id="contactRowTemplate">
  34:                  <tr>
  35:                      <td><input class="required" 
  36:                          data-bind="value: firstName, uniqueName: false"/></td>
  37:                      <td><input class="required" 
  38:                          data-bind="value: lastName, uniqueName: false"/></td>
  39:                  </tr>
  40:              </script>
  41:   
  42:          </fieldset>
  43:      </div>
  44:  </body>
  45:  </html>
 

We start by setting up our html table.  All probably looks familiar up to line 27.  In Xaml, we use Binding expressions to state what we want to bind to and how that binding is to behave.  KnockoutJS uses the "data-bind" attribute to specify these bindings.  In line 27 a binding is expresses that says, "for each item in the collection of contacts on the view model, create and populate an instance of the template named 'contactRowTemplate'".  You can see the template definition in lines 33 – 40.

Compare this binding with a similar Xaml binding and you'll find:

  • It's possible to do an ItemsSource type binding in KnockoutJS where an item is generated for each entry in an array.
  • Adding or removing an item from the array causes row corresponding to that item to appear or disappear respectively.
  • A template can be specified for how each item in the list will be constructed.  Compare this with the ability to specify an ItemTemplate in Xaml (note that you can organize the container of the list as you wish which is very similar to ControlTemplate's.
  • In Xaml, the data context flows in a predictable way through all an item's sub-items.  Note that the binding on the <tbody> element is to an array and the bindings inside the template are to a single item in the array.  This behaves the same as in Xaml.

The button in line 31 uses a click binding to bind the click event to the function we defined on our view model.

Yes, the binding syntax is different and there are many more binding types available than are used in this simple sample, but the library is very well documented here and the familiarity of the MVVM approach to constructing a UI make KnockoutJS a very easy library to get started with.

Download File - KnockoutSampleSolution

Tags: , , , ,

.Net | ASP.Net | JavaScript | Silverlight | WPF

What is a JavaScript Closure, Anyway?

by Administrator 10. December 2011 14:15

Back in the late nineties, during the .com boom, I worked on a huge web application that used XmlHttp (now known as AJAX) and extensive lots of JavaScript.  The language and how it's perceived has changed a lot since then and so has the maturity of the community using it.  Techniques have come about that make JavaScript easier to use in large internet applications.  Most of these techniques have come about because developers are learning to go with the flow of the language instead of fighting it; to use the unique qualities of the language to advantage.

An Example

Consider the following JavaScript:

   1:  function MyClass(x) {
   2:     var Addend = x;
   3:   
   4:      return AddTo = function (y) {
   5:          return y + Addend;
   6:      }
   7:  }
   8:   
   9:  var AddToTen = MyClass(10);
  10:  alert(AddToTen(10));
  11:   
  12:  var AddToFive = MyClass(5);
  13:  alert(AddToFive(10));

Beginning in line 1, a function is being defined.  Inside this function, we define a local variable and set its value equal to the passed in parameter.  Then, an inner function is returned.  This inner function refers to the local variable defined in the outer function.  Once the outer function has completed execution, it cannot be garbage collected because it is still being referred to by the inner function.  It's also very important to understand that whatever value the local variable has at the time the inner function is returned, is the value that will be visible to the inner function when it is executed from an external call.

When lines 9 and 10 run, 10 is passed in to the outer function and the local variable is set to 10.  When the inner function is returned, it will always see Addend as having the value of 10.  Thus, this script will pop the first alert with a value of 20 and then a second with the value of 15. 

In short, whenever an inner function is returned from an outer one, a logical copy of the outer functions state is made available to the inner function and this state can be accessed each time the inner function is invoked.

What About a .Net Example

We can duplicate this behavior in C#.  I created a Console application to illustrate this.

    class Program
    {
        static void Main(string[] args)
        {
            var five = MyMethod(5);
            Console.WriteLine(five(10));

            var ten = MyMethod(10);
            Console.WriteLine(ten(10));
            Console.ReadLine();
        }

        static Func<int, int> MyMethod(int x)
        {
            int addend = x;

            return new Func<int, int>((y) =>
            {
                return addend + y;
            });
        }
    }

Tags: , ,

.Net | ASP.Net | JavaScript

View PDF files in Silverlight Applications

by mgordon 12. August 2010 08:27

I’ve amassed quite a collection of ebooks in PDF format and I recently had the idea to make them available from my server at home over the internet so I could access them from wherever I happened to be.  I wanted to write the application in Silverlight, but how to actually view the PDF’s?

The solution to this problem is possible because of the tight integration between Silverlight and the browser DOM.  Recall that if I enter the URL of a PDF document into the browser address bar, and I have a PDF viewer installed, an instance of the PDF viewer is created in the browser and it renders the PDF document.  We can use this behavior to render the PDF and make it look as though the PDF document is being viewed from the Silverlight application.

 

The HTML

Since we want to be able to leverage the browser’s HTML rendering behavior to show the PDF file, we need to create some HTML for the browser to render.  In the page that’s hosting the Silverlight application, create an iframe or div tag:

 

 

<iframe id="pdfFrame" style="visibility:hidden; position:absolute"><b>No Content</b></iframe>

 

 

Control Via Silverlight

No, in the Silverlight application, you need to create a control to “host” the IFrame.  You can’t actually insert the IFrame into the Silverlight visual tree, but we’re going to tie the IFrame and this control together in such a way that it looks like this control is hosted inside our application.  For our purposes, a grid will do nicely.

 

<Grid x:Name="LayoutRoot">
        <Grid.Background>
            <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                <GradientStop Color="#FF101010" Offset="0.98299998044967651" />
                <GradientStop Color="Black" Offset="0" />
                <GradientStop Color="White" Offset="0.546999990940094" />
            </LinearGradientBrush>
        </Grid.Background>
        <Grid x:Name="pdfHost" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
              Margin="10" Background="White" LayoutUpdated="Grid_LayoutUpdated">
        </Grid>
    </Grid>

 

Notice that I’ve hooked the LayoutUpdated event.  In the handler for this event, we can tie the size and shape of our IFrame with that of the grid.

 

 

private void Grid_LayoutUpdated(object sender, EventArgs e)
       {
           ShowPreview();
       }
       private void ShowPreview()
       {
           GeneralTransform gt = pdfHost.TransformToVisual(Application.Current.RootVisual as UIElement);
           Point offset = gt.Transform(new Point(0, 0));  // Here you find your Panel Top/Left position
           int controlLeft = (int)offset.X;
           int controlTop = (int)offset.Y;
           HtmlElement m = HtmlPage.Document.GetElementById("pdfFrame");  // Find your HTML DIV
           if (m != null)
           {
               m.SetStyleAttribute("left", controlLeft.ToString() + "px");  // Set the Div position
               m.SetStyleAttribute("top", controlTop.ToString() + "px");
               m.SetStyleAttribute("visibility", "visible");
               m.SetStyleAttribute("height", pdfHost.ActualHeight.ToString() + "px");
               m.SetStyleAttribute("width", pdfHost.ActualWidth.ToString() + "px");
               m.SetStyleAttribute("z-index", "1000");
           }
       }

Here, you find the location of your grid and set the style of the IFrame to match its position and size.  In effect, every time the grid is resized or repositioned, the IFrame will follow it.  Notice how we use the HtmlPage class to access the host page’s DOM and find our IFrame.

 

Show the PDF

No that we have the IFrame tied to our grid, how do we actually show the PDF in the IFrame?

 

HtmlElement el = HtmlPage.Document.GetElementById("pdfFrame");
           el.SetProperty("src", "showpdf.aspx?key=" + key.ToString());

First, get a reference to the IFrame, again, and then set it’s src property.  Here, I have an aspx page that pulls the pdf file from another location and streams it to my IFrame.  If the PDF is located within your web directory structure, you can bypass the aspx page and just specify the path to you pdf file.

Tags: , ,

Silverlight | ASP.Net | PDF

Access Role Provider from ASP.Net Ajax and Silverlight

by mgordon 19. June 2009 05:00

In an earlier postI detailed how to access the Membership provider’s services from Silverlight and ASP.Net Ajax.  This is great for logging users into your site, but what if you want to make only certain parts of the application available to these users based on their role in the system at the time they log in or just check the user’s role before allowing them to perform an action? 

I found a great post by Satheesh Babu that describes how to access the Role provider from within the browser. 

Tags:

.Net | ASP.Net | Silverlight

The Best Service Reference Strategy for Silverlight

by mgordon 12. June 2009 06:08

When first learning Silverlight, having often utilized the “Add Web Reference” functionality in Visual Studio in days gone by, I reached for the alluring “Add Service Reference” functionality when adding references to WCF services to my Silverlight projects. I encountered a few problems using this approach and began to search for a better way to reference WCF services.

Project Bloat

The first problem I noticed was the sheer number of files generated by Visual Studio when you add a service reference.  If you’re using source control (and you should be), any modification made to a service reference is going to delete several files and replace them with new ones.  When checking these changes into source control, it can sometimes be confusing trying to figure out how to get your source checked in in a valid state.

Reusing Referenced Assemblies

Second problem I found I was having was that I was often getting errors and warnings when adding or modifying a service reference.  These came in different flavors, but most all complained about the format of the WSDL being received from the service.  With some trial and error, I figured out that the problems were being caused by the default behavior of Visual Studio when adding a reference in respect to reusing types in referenced assemblies. When adding a service reference, the below dialog appears.

AddRef

If you click on the Advanced button, this dialog appears.

Advanced

By default, the “Reuse types in referenced assemblies” checkbox is checked and the “Reuse types in all referenced assemblies” radio button is selected.  If you’re having problems getting client proxies to generate for your services, try clearing the checkbox as this seemed to be the solution for me.

Location, Location, Location

The third problem I’ve had with adding references this way is probably the most important.  With the Add Web Reference I knew and loved, it was a fairly simple matter to modify the generated Reference.cs file to pull the URL for the web service endpoint from a configuration file.  But, when adding a service reference with visual studio, whatever endpoint you specify when adding the reference gets scattered through various of the generated files which makes manual modification extremely difficult.

When I’m working with a Silverlight project, I typically like to have all the services running locally while I’m developing to facilitate debugging and modification of the services which means that my service references need to be pointing to localhost.  Before I deploy, I have to go to each reference and reconfigure it to point to the production server which means that any modified version of my services have to already exist on the server and all this makes deployment a huge headache.  If my shop employed a full set of environments - dev, QA, staging, prod – I’m sure I’d go postal.

The Search for a Better Way

In thinking about the problem, I realized that what I needed was a simple way to generate a client proxy.  I could then build my address, binding and channel in code, pulling any of the necessary pieces of configuration from a config file.  My first thought was to create the proxy class using SvcUtil.exe.  I soon found, though, that the proxies generated by this tool are incompatible with Silverlight.  I then found out about a tool called SlSvcUtil.exe that generates proxies specifically for Silverlight.  Unfortunately, this tool is supposed to ship with Silverlight 3 and I’m still working in version 2.

For now, I’ve found two alternatives.  First is a bit of a hack, but still a fairly easy way to generate proxies that I found here.  Basically, this blog post suggests using the “Add Service Reference” functionality in Visual Studio to generate a reference.cs, saving that class and then deleting the service reference.  I also found an article by David Betz, here, that takes you through an excellent explanation of the details of the inner workings of WCF with Silverlight and suggests writing proxies by hand.

It’s good to have choices and I’m sure I can find circumstances where each approach will be beneficial.

Tags:

.Net | ASP.Net | Silverlight | WCF

Windows 7, Silverlight and the Unrecognized Element Exception

by mgordon 12. June 2009 04:22

I recently rebuilt my development laptop with Windows 7 and have been developing on it.  I have an existing Silverlight application that I have been deploying to a Windows Server 2003 machine and encountered some odd behavior after making modifications to in on the Windows 7 box and deploying it to the server.  The application ran fine on the development box, but after deploying to Windows 2003, any time the application made a call to a WCF service, an exception was raised declaring that an unrecognized element had been encountered.  After looking through several of the XML files in the solution, I happened upon the problem.

When looking at the ServiceReferences.ClientConfig file, I found the bindings defined there looked like this:

<binding name="BasicHttpBinding_Processing" maxBufferSize="2147483647"
    maxReceivedMessageSize="2147483647">
    <security>
        <transport>
            <extendedProtectionPolicy policyEnforcement="Never" />
        </transport>
    </security>
</binding>

The security element and everything within it was added when I modified one of the service references in my Silverlight project.  Removing all occurrences of these tags solves the problem.  These tags are not added under the same circumstances when developing on Vista or XP.

I’m still not sure why these tags were added.  I’m running .Net 3.5 SP1 on both my development machine and the server.

Tags:

.Net | ASP.Net | Silverlight | WCF

Accessing the Membership Provider from Silverlight

by mgordon 13. May 2009 04:50

In a particular Silverlight application, I felt it would be common for a user to have the application open for long periods, but not necessarily be interacting with it all the time.  This meant that there was always a chance the user’s session would time out.  Since the application uses the Membership and Role providers, nasty errors were being raised from web service calls depending on data from these providers if the session was not available.

To handle this situation, I tested for a valid session in my services and raised a custom exception if it wasn’t available.  Then, using the ideas in my last post I trapped that exception in my Silverlight application and showed a login box to the user so they could log back into the application and re-establish a valid session.

The next piece of this puzzle to solve was how to gain access to the Membership Provider from the Silverlight application to log the user back in.  Turns out there are two ways to go and both are equally valid for an Ajax application as well as Silverlight, though one is clearly more suitable for Ajax than Silverlight.

ASP.Net Ajax

The first solution is to use functionality built into the ASP.Net Ajax framework.  There is a javascript object in the framework, Sys.Services.AuthenticationService, that provides the needed functionality.  So, if you have all the necessary parts of the Ajax framework set up, in JavaScript you can say

var ssa = Sys.Services.AuthenticationService;

ssa.login(username,
              password,
              isPersistent,
              customInfo,
              redirectUrl,
              onLoginComplete,
              onError);

Of course you pass the username and password.  IsPersistent is a bool value indicating whether or not the user wants to be “remembered” by the application.  CustomInfo can be null as can the redirectUrl.  Of course, if you would like the user to be redirected to a certain Url after a successful log in, you’d specify that Url. The last two values are pointers to the methods to call when the login has completed or has errored out.  If you’re calling this from a web page it’s straight forward and from Silverlight, you’d need to wrap this code in a JavaScript function, and then call it from Silverlight like this.

Exposing Authentication as Web Service

Brad Abrams has an excellent tutorial on how to expose the needed functionality as a web service, here.  This was the approach I ended up using in my Silverlight application because it fit well with how the rest of the application was designed.   Once the functionality has been exposed as a web service, you could call this web service the same way you’d call any other from an Ajax application.

Tags:

.Net | Silverlight | WCF | ASP.Net