Monthly Archives: March 2013

Data-driven Knockout views

I’m using Caliburn.Micro in my Silverlight and WPF projects. I fell in love with Caliburn automagic – view locator, auto binding, etc. For my NodeJS project I was looking for JavaScript library supporting MVVM pattern and I found KnockoutJS.

Knockout has very nice feature called binding with a simple way of implementing your custom binding.

What I was missing was Caliburn’s binding/convention for ContentControl – data driven view rendering:

<!-- DataContext is RootViewModel -->
<ContentControl Name="ChildViewModel" />

with the view located for value of ParentViewModel.ViewModel property and then rendered.

The solution I come with uses

  • Infuser as a templating engine, more on using Infuser as templating engine for Knockout here
  • TrafficCop used by Infuser and prevents duplicate AJAX requests

Infuser is configured to load the view templates from views directory (I will implement some view locator later):

infuser.defaults.templateSuffix = ".tmpl.html";
infuser.defaults.templateUrl = "/js/app/views/"; 

and every view model object must have a property returning its type name (if someone knows about better way how to do it, please let me know).

var SampleViewModel = kb.ViewModel.extend({
  constructor: function(model) {
    ...
    this.type = 'SampleViewModel';
  }, 
  ...
}

Code of the binding handler:

ko.bindingHandlers.content = {
  'init': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    var options = ko.utils.unwrapObservable(valueAccessor())
    var templateName = options.data.type.replace(/viewmodel/ig, 'View'),
      dataValue = ko.utils.unwrapObservable(options['data']);
    var innerBindingContext = bindingContext['createChildContext'](dataValue, options['as']);
    ko.renderTemplate(templateName || element, innerBindingContext, options, element);
  }
};

and the HTML

<div data-bind="content: { data: childViewModel }"></div>
<script>
  var rootViewModel = kb.ViewModel.extend({
    constructor: function(model, options) {
      this.childViewModel = new SampleViewModel();
    }
  });
  ko.applyBindings(rootViewModel);
</script>

NuGet pack error “Assembly outside lib folder”

When I was working on a NuGet package I noticed that some DLLs (that were not supposed to be placed there) were copied into the content subdirectory of the package.

Added file 'content\lib\Microsoft.Practices.EnterpriseLibrary.Common.dll'.

And that also caused an issue:

Issue: Assembly outside lib folder.
Description: The assembly 'content\lib\Microsoft.Practices.EnterpriseLibrary.Common.dll' is not inside the 'lib' folder and hence it won't be added as reference when the package is installed into a project.
Solution: Move it into the 'lib' folder if it should be referenced.

It took me some time to figure out that NuGet copies all project items with BuildType set to Content to content directory in package. Problem was solved by changing BuildType to None.

How I failed using MSTest on TeamCity without Visual Studio

I was setting up a continuous integration for one project. I have configured a build step in TeamCity to build the solution and another to execute unit tests using MSTest. And that failed – the reason was Visual Studio was not installed on that machine. I googled around and found some useful posts:

The key components for running tests are MSTest.exe and QTAgent.exe. So I copied all the files to desired locations, I didn’t added the DLLs to GAC, opened command line and executed MSTest.exe and …

… an exception! Could not load file or assembly xxx.dll

So I found that DLL on my computer and copied it to directory with MSTest.exe, then fired MSTest.exe and another assembly load exception and again and again.

Because I could I installed VS.NET 2012 on that machine just to avoid this eternal cycle.

For those who can’t I used Fusion Log Viewer (fuslogvw) to log all assembly bindings to disk and then analyzed the files in LinqPad to get the list of loaded DLLs and their locations. See the attached file (some of the binded DLLs might be required by the tested project).

Hope this will help someone.