<September 2010>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910
MVVM + DLR: Use DynamicObject as the base class for a ViewModel

When you’re creating a ViewModel for a View to consume, your are often writing mapping Code in the ViewModel that forward to properties of the Model, if you’re not subclassing that is, but that brings problems of it’s own.

For example the View.xaml contains a Binding like this:

   1: <Label Content="{Binding Version}" />

and your Model looks like this:

   1: public class SettingsModel
   2: {
   3:     public string Version { get; set; }
   4:  
   5:     // ...
   6: }

so your ViewModel looks something like this:

   1: public class SettingsViewModel
   2: {
   3:     public SettingsModel Model { get; set; }
   4:  
   5:     public string Version { get { return Model.Version; } set { Model.Version = value; } }
   6:  
   7:     // ...additional properties (IsSelected, ...)
   8: }

This is error prone and tedious, but you can get rid of those problems by using the DLR. You can keep the View and the Model but change the ViewModel into a base class that is derived of a DynamicObject:

   1: public class BaseViewModel<T> : DynamicObject
   2: {
   3:     public T Model { get; private set; }
   4:     private Dictionary<string, PropertyInfo> ModelProperties = new Dictionary<string, PropertyInfo>();
   5:  
   6:     public BaseViewModel(T model)
   7:         : base()
   8:     {
   9:         this.Model = model;
  10:  
  11:         PropertyInfo[] modelProperties = model.GetType().GetProperties();
  12:         foreach (PropertyInfo property in modelProperties)
  13:                 ModelProperties.Add(property.Name, property);
  14:     }
  15:  
  16:     public override bool TrySetMember(SetMemberBinder binder, object value)
  17:     {
  18:         bool valueSet = false;
  19:  
  20:         if (ModelProperties.ContainsKey(binder.Name))
  21:         {
  22:             try
  23:             {
  24:                 ModelProperties[binder.Name].SetValue(this.Model, value, null);
  25:                 valueSet = true;
  26:             }
  27:             catch { }
  28:         }
  29:         return valueSet;
  30:     }
  31:  
  32:     public override bool TryGetMember(GetMemberBinder binder, out object result)
  33:     {
  34:         bool valueGet = false;
  35:         result = null;
  36:  
  37:         PropertyInfo property;
  38:  
  39:         if (ModelProperties.TryGetValue(binder.Name, out property))
  40:         {
  41:             try
  42:             {
  43:                 result = property.GetValue(this.Model, null);
  44:                 valueGet = true;
  45:             }
  46:             catch { }
  47:         }
  48:  
  49:         return valueGet;
  50:     }
  51: }

and the actual implementation:

   1: public class SettingsViewModel : BaseViewModel<SettingsModel>
   2: {
   3:     // ...additional properties (IsSelected, ...)
   4:  
   5:     public SettingsViewModel(SettingsModel settings)
   6:         : base(settings)
   7:     {
   8:     }
   9: }

Now every property of the Model is accessible for the View by Accessing the ViewModel and you can simply add additional Properties to the ViewModel, for those that are missing. If you want to “override” the dynamic Property you can also simply implement it in the ViewModel.

You could also implement IDynamicMetaObjectProvider yourself instead of deriving from DynamicObject.

Start applications elevated from the command prompt

I wrote a very simple command line app named elevate to start applications with the elevation prompt in Win7/Vista.

The function that starts it up is “ShellExecute” and the 2nd parameter is the one that tells windows to start it elevated.

// Launch the Application elevated
HINSTANCE hResult = ShellExecute(NULL, _T("runas"), argv[1], cmdLine, NULL, SW_SHOWNORMAL);

You can rename it to 'el.exe' and put it in a folder referenced by the PATH environment variable so that it can be launched from everywhere.

It forwards supplied parameters to the launched appliction.

Usage: 'elevate cmd' or 'elevate notepad c:\test.txt'.

Sourcecode and the compiled app can be downloaded below.

Batch printing pdf files

The Problem: Printing a Pdf

Lately I needed to print pdfs (not create them by using a pdf printer, which is a different matter and there are free products available like the adfree Bullzip Pdf Printer) programmatically. After searching the web I found some notes about using acrobat reader to do the printing, some using commandline switches which only work for old versions of the acrobat reader, some using DDE like (here and here), which bring dependencies of it's own to the game and if you read on adobes support page "These are unsupported but have worked for some developers." well than thats not what I was looking for. Both solutions are known to leave a lingering instance of the acrobat reader in the background, as the newer versions don't seem to exit after doing their job anymore.

Of course there are commercial solutions available, so I tried the demo version, but it wasn't even able to display the 1-Page sample document I fed it, which was rendered by the reporting services, as the only thing that showed up was the trial watermark. With some other pdfs I had laying around I was more lucky, at least some of the pages were legible.

The Solution: Foxit reader + cmdline switch '/t'

I am using the foxit pdf reader for reading pdfs on my machine, which is a rather lightweight viewer (the download is 5.3 MB, it consists of only 1 executable [9.2 MB] and no dlls) compared to the acrobat reader (even the Download is about 27 MB). Sure enough it supports printing the pdf and it also supports silent printing (with no ui) to the default printer by using explorer's context menu on a pdf file of your choice. So I took a look in the registry to find the commandline switch (which btw. is '/p', who would have guessed :-p) and I found a second switch '/t' named 'PrintTo' under 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\FoxitReader.Document\shell\printto\command' which sounded even more interesting. PrintTo uses the '/t' switch and supports more than one argument, which you can use to specify the printers name. In comparison to the acrobat reader, Foxit's reader is a good citizen and exits after doing it's job so you can just invoke it and keep it's process WaitHandle to be notified when it has done it's work.

You can use it like: foxit reader.exe /t sample.pdf Printer1 where Printer1 is the name of your printer

Advantages

  • Easy
  • Silent
  • Free
  • Can choose the printer
  • you can script it
Rss
  
Elevate Source (3.6 KB)
Sourcecode for elevate command line tool
Elevate.exe (20.7 KB)
Elevate commandline tool

Rss
Tag Cloud