Sunday, November 21, 2010

Using DocX to insert text into an existing document.

Maybe I'm just slow, but I found this hard to do. Here is a simple bit of code that finally did it. It seemed to me that I should have been able to use some simpler, more obvious methods to achieve this, but they just didn't work for me.


private void button1_Click(object sender, RoutedEventArgs e)
{
using (DocX doc = DocX.Load(@"..\..\Templates\source.docx"))
{

int index = FindParagraphIndexContaining("@Marker@", doc);

Paragraph p = doc.Paragraphs[index];

Paragraph p2 = p.InsertParagraphAfterSelf("");
p2.Append("Here is a new paragraph.").Font(new System.Drawing.FontFamily("Verdana")).FontSize(11);
p2.IndentationBefore = 1.0f;

p.Remove(false);

doc.SaveAs(@"..\..\Templates\saved.docx");

MessageBox.Show("Done!");
}
}

private int FindParagraphIndexContaining(string text, DocX doc)
{
int i;

for (i = 0; i < doc.Paragraphs.Count; i++)
{
if (doc.Paragraphs[i].FindAll(text).Count > 0)
{
return i;
}
}
return -1;
}

Thursday, June 3, 2010

MSI Deployment of a Trusted Silverlight 4 Out-of-Browser Application

For our corporate network, we want to be able to deploy elevated trust Silverlight 4 applications to our users via an MSI deployment. The reason being that SL4's typical approach to installing an OOB application leaves a few things to be desired. Namely:

  • In order to do automatic updates, all XAPs must be signed. In some organisations this may not be an issue, but our department doesn't like the use of PKI.

  • In order to install an application, the user must first go to a web page where it is hosted. From then on they may run it from their Start menu. We'd like the app to be installed for them straight away.

  • Many of our users do hot-desking with their computers, and since OOB apps are installed on a per-user-per-workstation basis, these users would regularly be having to install (and update!) each application on a machine they haven't used before.



So what about sllauncher.exe?

Sllauncher.exe is great because it allows an OOB application to be installed without the user first having to go to a webpage. The shortcomings of Sllauncher are:

  • Running Sllauncher only installs the application for the current user, and only on that machine. Other users of the machine will not have the application installed. If the current user goes to another machine, they will have to then install or update the app again.

  • In order to do auto-updates, PKI must still be used.

  • Auto-updating of OOB apps is a little akward, since when an update is detected, the user is forced to exit and re-run the application before the updates take effect.



An MSI based solution

Since all our other applications are installed using MSIs and group policy, we wanted an MSI packaging option that fixed all these problems. In particular, we wanted the ability to:

  • Deliver the installation automatically via group policy when the user starts up their workstation.

  • Be able to deliver updates by either updating the XAP on the web, or even from a shared file location on the LAN

  • Not have the need for the user to exit the application before updates take effect.

  • Have the icon for the application automatically installed in their start menu.

  • Be able to take advangate of elevated trust without the need for PKI.



The solution was to create a wrapper around Sllauncher that could do this for us. It is installed in the Program Files directory of a client workstation, and is called instead of Sllauncher. It takes as a parameter the URI of the XAP for the application. When it is executed it does the following:

  • Checks to see if the OOB application is installed for the current user.

  • If the application is not installed, or if it is an older version than what is on the Intranet/LAN, it is updated.

  • Runs the application.



With this done, it is a relatively simple matter of creating a deployment project that includes this wrapper. Once installed, an app is deployed by giving the user a shortcut. Updates to the application are done by placing a new version of the XAP on the Intranet/LAN, and the wrapper will automatically update the client workstation when it is next run.

The code is shown below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Configuration;
using System.Net;

namespace SlLauncher2
{
class Program
{

// The path to the Sllauncher.exe
private static readonly string _sllauncher = string.Format("\"{0}\\Microsoft Silverlight\\sllauncher.exe\"", Environment.GetEnvironmentVariable("ProgramFiles"));

static void Main(string[] args)
{
// e.g. http://localhost/ClientBin/myapp.xap OR
// e.g. file://F:/Development/SL4Com/SL4Com/Bin/Debug/SL4Com.xap
string appUrl = args[0];
Uri appUri = new Uri(appUrl);

LaunchApplication(appUri);
}

/// <summary>
/// Does the work of installing or updating the application as necessary, and then executing it.
/// </summary>
/// <param name="appUri"></param>
private static void LaunchApplication(Uri appUri)
{
string xapFilename = appUri.Segments[appUri.Segments.Length - 1];

DateTime? installedXapLastModified; // The last modifed date of the currently installed XAP (if found)
DateTime? webXapLastModified =
GetLastModified(appUri);

// Determine the App ID of the installed version (null if not found)
string appId = GetAppId(appUri, out installedXapLastModified);

// If the xap was not found or the timestamps differ....
if (appId == null || webXapLastModified > installedXapLastModified)
{
// Install the app...
Console.WriteLine("Installing from web");
string fileName = DownloadXap(appUri);
InstallApp(appUri, fileName);
File.Delete(fileName);
}
else
{
Console.WriteLine("XAP was up to date");
}

// Run the app
OpenApp(GetAppId(appUri, out installedXapLastModified));
}

/// <summary>
/// Downloads the XAP to a temporary file.
/// </summary>
/// <param name="appUrl"></param>
/// <returns>The full path to the file.</returns>
private static string DownloadXap(Uri appUri)
{
WebRequest request = WebRequest.Create(appUri);
request.Method = "GET";

WebResponse response = request.GetResponse();
Stream receiveStream = response.GetResponseStream();

string fileName = Environment.GetEnvironmentVariable("TEMP") + @"\" + Guid.NewGuid().ToString();

FileStream output = new FileStream(fileName, FileMode.CreateNew);
BinaryWriter writer = new BinaryWriter(output);
BinaryReader reader = new BinaryReader(receiveStream);

byte[] buffer = reader.ReadBytes(1024);
while (buffer.Length > 0)
{
writer.Write(buffer);
buffer = reader.ReadBytes(1024);
}

reader.Close();
receiveStream.Close();
writer.Close();
output.Close();

return fileName;
}

/// <summary>
/// Determines the last modified date of the XAP at the specified URI.
/// </summary>
/// <param name="appUri"></param>
/// <returns></returns>
private static DateTime GetLastModified(Uri appUri)
{
WebRequest request = WebRequest.Create(appUri);

request.Method = "HEAD";

WebResponse response = request.GetResponse();

DateTime lastModified;

if (request.GetType() == typeof(HttpWebRequest))
{
lastModified = DateTime.Parse(response.Headers["Last-Modified"]);
}
else
{
lastModified = (new FileInfo(appUri.LocalPath)).LastWriteTime;
}

return lastModified;
}

/// <summary>
/// Launches the specified app ID
/// </summary>
/// <param name="appId"></param>
private static void OpenApp(string appId)
{
System.Diagnostics.Process.Start(_sllauncher, appId);
}

/// <summary>
/// Installs the specified OOB app
/// </summary>
/// <param name="appUrl"></param>
/// <param name="xapFilename"></param>
private static void InstallApp(Uri appUri, string xapFilename)
{
ProcessStartInfo startInfo = new ProcessStartInfo(_sllauncher, string.Format("/install:{0} /origin:{1} /shortcut:none /overwrite", xapFilename, appUri.OriginalString));
Console.WriteLine(_sllauncher + " " + startInfo.Arguments);

startInfo.RedirectStandardOutput = true;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;

Process process = new Process();
process.StartInfo = startInfo;
process.Start();
string result = process.StandardOutput.ReadToEnd();
}

/// <summary>
/// Searches for the app ID of the given application
/// </summary>
/// <param name="appUrl"></param>
/// <param name="lastModified">The last modified date of the XAP, if found</param>
/// <returns>Null if not found</returns>
private static string GetAppId(Uri appUri, out DateTime? lastModified)
{
// This needs to be improved as it currently needs to be different on Windows XP/7.
string dataPath = Environment.GetEnvironmentVariable("APPDATA") + @"\..\Local Settings\Application Data\Microsoft\Silverlight\OutOfBrowser";
string appId = null;

lastModified = null;

// Search each metadata file for the XAP
foreach (string directory in Directory.GetDirectories(dataPath))
{
string file = directory + @"\metadata";
if (File.Exists(file))
{
using (StreamReader reader = new StreamReader(file, Encoding.Unicode))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();

if (line.Contains("OriginalSourceUri=" + appUri.OriginalString))
{
FileInfo fileInfo = new FileInfo(file);

appId = (new FileInfo(directory)).Name;
lastModified = fileInfo.LastWriteTime;
break;
}
}
}
}
}

return appId;
}
}
}

Silverlight 4 Deployment Guide

Documentation from Microsoft:
Silverlight 4 Deployment Guide
Group Policy Settings

Group policy settings allow control of:

  • Digital Rights Management — enable or disable playback of DRM enabled content

  • Silverlight Automatic Update Mechanism — disable the automatic update mechanism which is separate from Microsoft Update

  • Silverlight Trusted Applications — allows users to install out-of-browser applications via the Install dialog

  • WebCam and Microphone — allows webpages and applications to access the microphone and webcam

  • UDP Multicast Networking — allows webpages and applications to do UDP multicast networking

Monday, May 24, 2010

Playing around with the WPF Chromium web browser control

I've spent a little time today playing around with WPF Chromium, using version 1.5 of the Awesomium wrapper. I'm evaluating some web browser controls for embedding in our WPF applications at work. There's a new beta version of Awesomium out at the moment, and it looks as if the WPF Chromium author has some plans to support it, but for the moment version 1.5 is all I have to play with.

What's great about this control:

  • A real WPF control, so it embeds nicely into a WPF UI with no (known) graphical oddities (like the control rendering over the top of the rest of the UI).



What's lacking (at the moment):

  • Windows Auth doesn't work. Apparently Chrome v5 Beta has some support for this, so when that will flow through to this control is unclear.

  • Drag & drop doesn't seem to work, even just within the browser.

  • Silverlight behaves strangely (it appears to work perfectly within GeckoFX)



At the moment, WPF Chromium really isn't an option. Maybe when the control supports Awesomium 1.6 it will fix some/all of these issues, but in the meantime, GeckoFX is looking like a winner.

Playing around with the GeckoFX web browser control

Have been playing around with GeckoFX as an embedded browser control replacement for MS's IE control. MS's IE control lacks any HTML5 support and we'd really like to be able to take advantage of some of the cool drag & drop features, such as those used here. Much to my surprise, using features like this allows us to do drag & drop of objects between web applications and our custom WPF/WinForm apps. Extremely cool.

I have also had a quick look at WPF Chromium and a super quick glance at WebKit .NET. I plan to take a closer look at them soon, but for the moment, here are the things I like best about GeckoFX:


  • Drag & drop works within the browser, and to external apps (in the quick look I've taken, I've been unable to do this with WPF Chromium

  • Windows Auth appears to work. This is vital to what we're doing at work, since this is how all our apps are secured. If the other options don't support this, then they're not contenders at all.

  • Although I haven't played with it yet, using GeckoFX I imagine we can use GreaseMonkey to help integrate web applications with our desktop environment in ways we may not have been able to do, especially for 3rd party products that otherwise wouldn't allow such a high degree of customisation.

  • Silverlight runs very happily.



The only thing I really wish is that it was a true WPF control, rather than WinForms. Since most of our development is WPF, we have to use the WinForms integration, which is OK, but causes some graphical issues (such as the web control always rendering over the top of the WPF content - note that the IE control has these problems too.) WPF Chromium does not have this problem, and really allows some seriously cool graphical effects.

Thursday, April 22, 2010

Using an Observable while still supporting multiple ViewModel instances

This post follows on from my previous post, Using the Observable for Change Notification in Calculated/Dependent Properties.

An upcoming project has the need for the Views in a module to be loaded multiple times in potentially many different places in the Shell. This made me realise the shortcoming of my post that describes using an Observable to share data between Views. The problem is in how the module registers the Observable. The code is below:

protected void RegisterViewsAndServices()
{
...
_container.RegisterInstance(
_container.Resolve<ISelectedContactObservable>());
...
}


This works well in the example project give in my previous post, but it all goes awry when we want to load multiple instances of our Views, because each instance of the View will needs its own Observable. By registering an instance with Unity in this way, our hands are tied.


So what to do instead? Well, following on from another previous post, we can use a controller to overcome this limitation. The controller becomes responsible for calling Unity and obtaining our Views. At this time it can therefore also create a fresh instance of the Observable and supply it to the ViewModels. The code from the attached project (at the end of this post) looks like this:


public class MainModuleController :
IMainModuleController
{
...
/// <summary>
/// Listens for requests to load the View
/// into a Region.
/// </summary>
///
public void LoadViewsEventHandler(
LoadViewsEventArgs payload)
{
// Create a fresh Observable that is used to share data
// between the two Views
ISelectedContactObservable observable =
_container.Resolve<ISelectedContactObservable>();
observable.SelectedContact = null;

// Create the Views using Unity
...
// Assign the Observable to each of them
detailsViewModel.SelectedContact = observable;
selectionViewModel.SelectedContact = observable;
...
}
}


Using the controller this way ensures correct creation of Observable classes.


The sample project can be downloaded here
.

Wednesday, April 21, 2010

Ensuring your Prism Modules can load multiple instances in your UI

In many Prism examples I have seen, such as the StockTrader Reference Implementation, it's not unusual to see a module register its View with the region it wants it loaded into. For example, the StockTrader's MarketModule has code like this:
public void Initialize()
{
...
this.regionManager.RegisterViewWithRegion
(RegionNames.ResearchRegion, () =>
this.container.Resolve
<ITrendLinePresentationModel>().View);
}

This has never really sat all that well with me, and it wasn't until recently that I realised why. An upcoming project has the requirement to not only load multiple instances of a Module's Views, but to load them in different Regions that could be user defined. Code like that above simply won't work in a situation like this. Unfortunately, it's also the way I've been writing my applications, and now I wish I hadn't.


So, what's a better way to have Views loaded into regions? I think the first thing to do is to never make a Module responsible for registering its Views with Regions. Instead, have a Module perform it's initialisation (such as registering all its types with Unity) and then sit there and wait for instructions on what to do next. A good idea could be to have it listen for a composite event that tells it when to load a View, and the name of the Region into which it should be loaded. By taking responsibility for determining when and where a View should be loaded away from the Module, it becomes so much more re-usable.


So what component should tell the Module what to do next? A reasonable choice would be the Shell itself, after all, the Shell is the component that defines the Regions, so it is therefore a good candidate for knowing what they should be used for.


Inside the Module itself, it will listen for load requests and respond accordingly. The code snippet below shows a method inside the Module Controller that when called will load the Modules Views into the Regions specified inside the Composite Event's payload:

/// <summary>
/// Listens for requests to load the View into a Region.
/// </summary>
/// <param name="payload">The regions to load into</param>
public void LoadViewsEventHandler(LoadViewsEventArgs payload)
{
// Create the Views using Unity
Views.IDetailsViewModel detailsViewModel =
_container.Resolve<Views.IDetailsViewModel>();

// Inject them into the given Regions
_regionManager.AddToRegion(payload.DetailsRegion,
detailsViewModel.View);
}


And lastly, the code snippet below shows the code inside the Shell's ViewModel that is called after all the Modules have been initialised. It loads three new instances of the Module's Views into different Regions inside the Shell:

public void LoadViews()
{
// Load all the views we want to show in the Shell
_eventAggregator.GetEvent<LoadViewsEvent>().Publish(
new LoadViewsEventArgs()
{
DetailsRegion = "DetailsRegion1",
});

_eventAggregator.GetEvent<LoadViewsEvent>().Publish(
new LoadViewsEventArgs()
{
DetailsRegion = "DetailsRegion2",
});

_eventAggregator.GetEvent<LoadViewsEvent>().Publish(
new LoadViewsEventArgs()
{
DetailsRegion = "DetailsRegion3",
});
}

I've included a sample project that demonstrates the concepts described here.

Friday, April 9, 2010

Just spent ages trying to get csExWB to work on Windows 7 64 bit

Am playing with csExWB to try to get IE to do things it normally wouldn't. Couldn't get it working on my 64 bit Windows 7 installation. After spending a ridiculous amount of time Googling, found the answer here.

Sunday, March 28, 2010

Using GetDataBack, ddrescue and SystemRescureCD to recover data from a crashed hard disk

A friend recently called me in a panic. He'd lost a lot of valuable work from his laptop, which was now refusing to boot into Vista. To cut what would otherwise be a very long story short, the vast majority of the data was recovered, and here's what I used to do it.

SystemRescueCD (a free Linux distro) was used to make a bootable CD. It comes with ddrescue preinstalled (don't confuse this with dd_rescue, which is not as good). This program was used to do a low-level copy of the damaged disk to another (larger and new) disk. The beauty of ddrescue is that it initally copies the entire disk, skipping any errors it encouters. Once complete, it goes back and tries various techniques for reading any salvagable information from the damaged areas of the disk.

The vital files on the disk were still unreadable, with the folder holding the most important files returning an I/O error. Booting my personal computer into Windows, I then used a program called GetDataBack (commercial tool, US$79) to scan the disk and it successfully read the folders that Linux and Windows could not. It then allowed me to copy the data out onto (yet) another disk, and burn it to DVD for him.

Tuesday, February 16, 2010

Blend throwing System.MissingMethodException with custom-made Sample Data

Blend 3 has a pretty cool new feature called Sample Data. It's great for quickly building some design-time data that can be displayed in the design view and give the developer/designer a good idea of what the screen will look like at run-time (with a few quirks here and there).

Personally though, for developing a real application I don't like it much. It's cumbersome having to use the Blend UI for building the data when compared to the speed with which it can be accomplished writing a few lines of code. The UI has limitations too, for example, when creating a sample data object with several properties of the same complex data type. You can spend hours in the UI fiddling around with the data doing something that you could accomplish in code in minutes... or less. Additionally, you do additional things such as defining commands in your sample data, which you can quickly set breakpoints on when you run a test harness and confirm that your databindings are working correctly.

Oh, and don't ever try fiddingly around with the generated code for the sample data. You'll get bitten, trust me.

However, for our interaction designers here, it's absolutely perfect for their rapid prototypes they want to show to the client. Considering they also don't have much of a clue about coding in .NET and it's pretty much a no-brainer.

That said, for our actual implementation I prefer that our team hand write the sample data. Ultimately it's quicker.

That leads me to a problem I spent the entirety of the last day on at work. During design-time, Blend starting throwing System.MissingMethodExceptions, and the design-time data on some controls was not working. Attaching Blend to the Visual Studio debugger revealed that when loading the offending XAML file, .NET was complaining of the type being declared in multiple DLLs.

Turns out the problem (it appears) was to do with the fact that the project in question is targeted at both WPF and Silverlight, with both projects in the same solution (and using the P&P Project Linker to help manage the shared code). Since both project haves some DLLs with exactly the same name (in this case, the Models DLL that is generated from the WCF service's WSDL) Blend was getting confused. In the end I saw no alternative other than to separate the WPF and Silverlight projects into separate solution files. The problem disappeared immediately

Oddly enough, I couldn't find anything about this anywhere on the web. So I figured I'd write about it here before I forget about it and wonder why things had been split into separate solutions.

Monday, February 8, 2010

Why are we using Silverlight at Work?

I had to remind myself today how it actually came to be that we had adopted Silverlight at work. Not because I'm wishing we hadn't mind you, but just because we're about to go back and evaluate technologies again (well, we are if it can't be avoided, it's madness if we do I think) and I thought I'd better make sure I'm covered if I start getting grilled on why we took this direction in the first place. So here's how it happened, in a seriously abridged format:

Why is Silverlight/WPF our chosen platform?
Outcome of the capability enhancement project in 2008.

How was it an outcome of that project?
Various platforms were rapidly assessed for further investigation against a large number of criteria. Microsoft platforms were chosen due to time constraints and due to our existing large investment in this area. WPF came out on top, Silverlight next. This report is available in the electronic libary.

The chosen technology was investigated, architectures assessed, proofs of concept conducted, standards/guidelines developed. They were then used in our next two UI projects with a good level of success. Silverlight 4 delivers further benefits making it a better fit than it did before. Indeed, the WPF project that integrated tightly with Office and the desktop could have been written in Silverlight 4 had it been available.

Why not use an HTML based solution?
Products like one of those developed that integrate tightly with the desktop do not lend themselves to browser based solutions. By using Silverlight we can adopt a consistent architecture that brings the power of tight desktop integration with the ease of web based deployment. Adopting HTML based solutions we will still need a desktop architecture for products that require privileged access to local resources. By using Silverlight we can realise considerable savings by adopting an architecture that fits both needs.

Additional benefits
  • Tools are free (i.e. included in existing licence agreements with Microsoft)
  • Technology based on .NET/C# which we are already heavily invested in
  • Silverlight is rapidly growing with many new features being added to Silverlight 4 less than 12 months after the release of Silverlight 3. Features such as trusted applications will allow us to use a single architecture to tackle almost any conceivable business requirement

Tuesday, February 2, 2010

Sharing ViewModel Data in a Decentralised Way

Yesterday I asked some colleagues to give me some constructive feedback on my last two posts about using an Observer pattern to share ViewModel data within a Prism Module. One comment was that it would be nice to have something sharing the data in a decentralised manner using Prism's EventAggregator.

This got me thinking that this sounded like a good idea. Eventually however I remembered that I'd considered this a while ago (but had subsequently forgotten about it, should have made an blog entry!) The reason I didn't pursue this approach for long was that I was concerned about how ViewModels would be initialised with the shared data values.

For example, imagine an application that has several ViewModels all using the EventAggregator to communicate to each other about changes in a shared piece of data. Imagine now that the user initiates an action that instantiates a new instance of another ViewModel to come online (for example, they have just clicked the Next button in a Wizard style workflow). How would this new ViewModel determine the current value of the shared data?

Try as I might, I couldn't see a nice way to do this. The ViewModel could raise an event asking what the value is, but then who should reply? Since the data has no "home" per se, there is no single definitive source that can supply an answer. Ultimately it would decsend into a pile of spaghetti for anything but the simplest of situations.

Now, this is not to say that there is not good way to do it. I just couldn't think of one. In the end, I like the Observer, as it gives the data a home, a place to live, which is nice.

Monday, February 1, 2010

Using the Observable Object for Change Notification in Calculated/Dependent Properties

Extending on my previous post, how could the Observable be employed when there are dependent/calculated properties that rely on the shared data inside the observable object?

Imagine a situation where the UI contains a drop down list whose selected index is databound to an Observable Object. Next to the drop down list is an info box that is visible only when a value in the list is selected. The visibility of the info box will be bound to a calculated property on the ViewModel, whose value is dependent on the value in the observable object. Therefore, if the value in the observable object changes, the visibility value needs to change too, and the View notified.

In the simplest case where there is no shared data and an observable object is not used, the XAML for an app such as this may look like this):

<ComboBox
Width="150"
Height="22"
Margin="5"
VerticalAlignment="Top"
HorizontalAlignment="Left"
ItemsSource="{Binding Contacts}"
SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}"
ItemTemplate="{StaticResource _itemTemplate}"
/>
<StackPanel Orientation="Vertical" Visibility="{Binding IsConfirmSelectionVisible, Converter={StaticResource VisibleIfTrue}}">
<TextBlock Margin="5" Text="Is this the correct selection?" />
<TextBlock Margin="5" Text="{Binding SelectedContact.SelectedContact.ContactId}" />


The ViewModel may look like this:

public int SelectedIndex
{
get
{
return _selectedIndex;
}
set
{
_selectedIndex = value;
RaisePropertyChanged("SelectedIndex");
RaisePropertyChanged("IsConfirmSelectionVisible");
}
}

public bool IsConfirmSelectionVisible
{
get
{
return SelectedIndex != -1;
}
}



Nice and simple. However, what if the SelectedIndex was a shared value between multiple ViewModels? As described in the previous post, a good method for doing this is to implement an Observable. The XAML would then look like this (the selected index property of the ComboBox is altered to use an Observable Object:

<ComboBox
Width="150"
Height="22"
Margin="5"
VerticalAlignment="Top"
HorizontalAlignment="Left"
ItemsSource="{Binding Contacts}"
SelectedIndex="{Binding SelectedIndexObservable.SelectedIndex, Mode=TwoWay}"
ItemTemplate="{StaticResource _itemTemplate}"
/>
<StackPanel Orientation="Vertical" Visibility="{Binding IsConfirmSelectionVisible, Converter={StaticResource VisibleIfTrue}}">
<TextBlock Margin="5" Text="Is this the correct selection?" />
<TextBlock Margin="5" Text="{Binding SelectedContact.SelectedContact.ContactId}" />



And the ViewModel like this:

public int SelectedIndexObservable
{
get
{
return _selectedIndexObservable;
}
set
{
_selectedIndexObservable = value;
RaisePropertyChanged("SelectedIndexObservable");
}
}

public bool IsConfirmSelectionVisible
{
get
{
return SelectedIndex != -1;
}
}


The problem here now is that when the SelectedIndex property is updated, the change notification will no longer work, as the change is occuring inside the observable. Raising the property changed event for IsConfirmSelectionVisible in there will not propogate to the UI. The way I see it, there are two options:

Option 1: Move IsConfirmSelectionVisible to the Observable

The property IsConfirmSelectionVisible is moved to the observable and the XAML for the StatckPanel's Visibility property is updated accordingly. Although this results in a minimal amount of additional code it is unclean in that code specifically intended for a View has been relocated into a shared resource (the Observable).

Option 2: Listen for changes in the Observable and React

In this scenario, when the Observable is injected into the ViewModel via the constructor, the ViewModel attaches itself to it and listens for property changed events. The code might look like this:

public SelectionViewModel
(
ISelectionView selectionView,
ISelectedContactObservable selectedContactObservable
)
{
...
View = selectionView;
View.ViewModel = this;

...

// Listen for property change events on the selected contact,
// as this controls whether some parts of the UI are visible or hidden
selectedContactObservable.PropertyChanged += HandleSelectedContactPropertyChanged;
...
}


Inside the HandleSelectedContactPropertyChanged event, the event is examined and the ViewModel reacts accordingly to notify the View of any relevant changes. The code might look like this:

private void HandleSelectedContactPropertyChanged
(
object sender,
PropertyChangedEventArgs args
)
{
switch (args.PropertyName)
{
case "SelectedIndex":
RaisePropertyChanged("IsConfirmSelectionVisible");
break;
default:
break;
}
}


This option requires additional code and some event wire-up. However, it maintains a better separation of concern between the View specific code and the shared Observable implementation.

Conclusion

Despite the requirement for some additional code, Option 2 is my preferred choice due to the better separation of concerns.

A working simple example of this is available in this example Silverlight project.

Monday, January 18, 2010

Using an Observable Object to share data between ViewModels

A good option for sharing data between ViewModels in Prism is to implement a simple Observer pattern. The Observable Object has a registered instance inside Unity and can be exposed to any ViewModel that needs to read/write to the shared data it holds.

The Observable implementation I describe below can really be thought of as a purpose-built, shared ViewModel. So why not call it a ViewModel? Simply because of one important difference - the Observable Object has no View. Furthermore, the name Observable implies that the class will be shared among any number of interested parties, rather than being tied to a View.

Step 1. Defining the Observable class

The class must implement INotifyPropertyChanged. E.g.:

public class SelectedContactObservable : INotifyPropertyChanged,
ISelectedContactObservable
{
...
}


Step 2. Configuring Unity

Unity is configured to use the class, then a single instance is registered so that it may be shared among all consumers.

_container.RegisterType(typeof(ISelectedContactObservable),
typeof(SelectedContactObservable));
_container.RegisterInstance(_container.Resolve<ISelectedContactObservable>());

Step 3. Use the Observable Object in your ViewModels

Use the Observable Object in any number of consumer classes (ViewModels) using constuctor injection.

public class ContactListViewModel : INotifyPropertyChanged
{
public ContactListViewModel(ISelectedContactObservable
selectedContactObservable)
{
...
}

public ISelectedContactObservable SelectedContactObservable
{
...
}
}

Step 4. Databind to the Observable Object in your Views

<TextBlock Text="{Binding SelectedContactObservable.SelectedContact.LastName}" />
<TextBlock Text="{Binding SelectedContactObservable.SelectedContact.FirstName}" />

Note that the actual observable object itself is exposed as a property on the ViewModel (rather than having some or all of its properties wrapped inside the ViewModel). This allows the change notifications to work with the databinding without the need of any additional code.

UPDATE: I have further worked this scenario to support dependent/calculated properties in this post.

Sunday, January 17, 2010

Justin Angel's Automatic INotifyPropertyChanged

Justin Angel has come up with another way to auto implement INPC. This time using low-level IL re-writing in the DLLs in after the project has been compiled. Advantages to this from my perspective are:
  • Minimal intrusion into the application's code;
  • Will work with Prism easily as it does not need to use proxy creators that must integrate with Prism/Unity;
  • No extra dependencies on the project... Sort of... Since there has to be adding of some DLLs that are exectued post-build to tweak the IL;

What I don't like (at this stage at least) is:

  • Bleeding edge example that is probably not ready for production use yet (at one point in the code the comments actually say "This is the worst hack in the history of the known universe"!;
  • I had numerous issues compiling the project, with it locking files, which is no doubt related to the hack mentioned above, as it has to create temporary copies of DLLs in order to tweak the IL;
  • I suspect it will only work for automatic properties, so if the property is made more complex with validation code etc. (as most of ours are, as we perform data validation in our ViewModel property setters - to support Silverlight 3 data validation). This may in fact not be the case, but I spent too much time working with the compilation issues and never got the solution building reliably enough to be able to start modifying the code to find out;

It's still very interesting, and hopefully something more solid will come of it, but at this stage it's not ready for me to start using in our systems.

Thursday, January 14, 2010

Another Automatic INotifyPropertyChanged Contender

ActiveSharp is another option here. However I don't like it since I suspect what it does is simple enough to do myself, and you still have to implement various piece of the infrastructure yourself.

I guess I'm just hanging out for Silverlight Unity to implement Interception. Seeing as the problem I am looking to solve is not a big one, I'd rather live with it than choose a solution that is sub-optimal.

Wednesday, January 13, 2010

In Summary: Automating INotifyPropertyChanged in Silverlight/Prism

Well, I've about exhausted my options and it's safe to say there is currently no quick win here.
  • Option 1: PostSharp : Has issues with derived types that break databinding
  • Option 2: Unity with Interception : Interception has not been implemented in Unity for Silverlight. Seems there are no plans on the horizon to do it either.
  • Option 3: Using Castle DynamicProxy : Might have been easy to do if I had been able to use the Prism Contrib project's Windsor adapter, but unfortunately it has not been updated for Prism V2.
  • Option 4: Use DynamicProxy with Unity : Would probably require writing a custom Unity extension. Not something I have time for right now.

So I think I'll have to leave it at that for the moment and move on.

No Interception for Silverlight Unity 1.2 :-(

And from what I can see there are no plans to add it. Thankfully there is Castle Dynamic Proxy, but so far with everything I've done in Prism, we've used Unity. Since I want to be able to do some AOP for automating INotifyPropertyChanged, and (hopefully) simplify using the Event Aggregator for shared data, I'm going to look into using Castle Windsor with Prism.

Luckily a nice person has already added support to the Prism contrib project. It looks a bit old, so hopefully it supports Silverlight.

UPDATE: It is too old. The Windsor adapter is for Prism V1, with no update for V2. Hmmmmm... I'm running out of options. Perhaps if I can get Castle Dynamic Proxy to work with Unity??

Using PostSharp 1.5 to automate INotifyPropertyChanged

I've spent some time today working with PostSharp for Silverlight, trying to use it to simplify implementing the INotifyPropertyChanged interface on my view models. Ultimately I hope to also simplify doing change notification via Prism's Event Aggregator too.

Unfortunately, as nice a solution as this appears to be, I will probably be throwing it away. The view model below works fine when databound:

[NotifyPropertyChanged]
public class MyViewModel
{
...
public int Age
{
get;
set;
}
...
}

However, this one breaks databinding - no change notification works at all:

[NotifyPropertyChanged]
public class MyBaseViewModel
{
...
}

public class MyViewModel
{
...
public int Age
{
get;
set;
}
...
}

So next I think I'll be looking at using Castle Dynamic Proxy to do it for me. Jonas Follesoe has been discussing it recently. What's extra nice is that he's also dealt with dependent properties too.

Tuesday, January 12, 2010

Sharing Objects Between ViewModels

An application we recently finished off at work highlighted a weakness within our architecture when it came to sharing data in the UI between the various ViewModels within our module.

Imagine an application with two screens (Views), arranged in a wizard work-flow way. The first screen allows you to select a file, and the second displays the properties of that file. The screen has typical “Next” and “Back” buttons and each View has its own ViewModel (say SelectionViewModel and PropertiesViewModel).

Upon selecting a file in the SelectionViewModel, how should the PropertiesViewModel receive/store the data that it needs to display?

In the case of our application, two different approaches were implemented in various places, both of which were quite unappealing. Here they are:

Approach 1: Binding to a shared ViewModel

One solution was to give PropertiesViewModel a reference to the SelectionViewModel and databind to it in the View. The constructor for the PropertiesViewModel would receive the SelectionViewModel instance, fed to it by Unity. Unity was also configured to store a single instance of the SelectionViewModel by using the RegisterInstance() method.

A sample piece of XAML in the PropertiesView might look like this:
<TextBlock Text="{Binding PropertiesViewModel.SelectedFile.Filename}" />

Approach 2: Using Events with a shared ViewModel

Imagine the same application, but this time rather than binding to the shared ViewModel, properties are created for binding, and are updated when the shared ViewModel changes. For example, imagine a Filename property created in the PropertiesViewModel, defined like any other. However, since the Filename is dependent upon which file is selected, eventing is used to listen for changes on the SelectionViewModel and update the Filename accordingly.

The PropertiesViewModel still needs to hold a reference to the SelectionViewModel, but this time it takes advantage of the fact that it implements INotifyPropertyChanged to listen for changes on it. E.g.:
/// <summary>
/// Initialise data for this view model
/// </summary>
public void Initialise()
{
// Because we are exposing properties reliant on SelectionViewModel, we
// are interested in knowing when properties change on that object.
SelectionViewModel.PropertyChanged += SelectionViewModelPropertyChanged;

...

}

...

/// <summary>
/// Fires when a property on the attachments SelectionViewModel changes
/// </summary>
/// <param name="sender">not used</param>
/// <param name="e">the property that has changed</param>
private void SelectionViewModelPropertyChanged (object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "SelectedFile")
{
OnPropertyChanged("Filename");
}
}

...

/// <summary>
/// Return the text to be displayed as the filename.
/// </summary>
public String Filename
{
get
{
return _ SelectionViewModel.SelectedFile.Filename;
}
}


So what’s wrong with these approaches? Right from the start it felt dirty to be passing around instances of one ViewModel to another (thus creating dependencies between them), and using the RegisterInstance method of Unity to ensure we only ever had one instance. It seems there should be some much cleaner approaches, and I think that using Prism’s Event Aggregator it should be easy enough to do. I’m planning on looking into this over the next few days if I find the time and hopefully post some better options soon.