<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7162298</id><updated>2012-01-28T06:50:28.562Z</updated><category term='LOB'/><category term='Windows Forms'/><category term='Visual Studio'/><category term='SSH'/><category term='MVVM'/><category term='PS3'/><category term='Prism'/><category term='SCSFContrib'/><category term='MAF'/><category term='Game'/><category term='Office'/><category term='Add-in'/><category term='Family'/><category term='Code Analysis'/><category term='Dependency Injection'/><category term='CAB'/><category term='MVP'/><category term='Build'/><category term='London'/><category term='MSBuild'/><category term='SCSF'/><category term='XAML'/><category term='Infusion'/><category term='UK/Europe'/><category term='Trac Explorer'/><category term='VSTO'/><category term='MEF'/><category term='Trac'/><category term='WCF'/><category term='System.AddIn'/><category term='Random Thoughts'/><category term='Ubuntu'/><category term='Concerts'/><category term='Free'/><category term='Misc Technical'/><category term='WPF'/><category term='StyleCop'/><category term='C/C++/Assembly'/><category term='Silverlight'/><category term='.NET'/><title type='text'>Kent Boogaart</title><subtitle type='html'>My sliding window.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default?start-index=101&amp;max-results=100'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>142</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7162298.post-2203493672276969829</id><published>2011-11-19T10:19:00.001Z</published><updated>2011-11-23T12:31:45.807Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVVM'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><title type='text'>WindowItemsControl</title><content type='html'>&lt;p&gt;The application I'm currently working on - top secret, mum's the word, your death for my indiscretion, you get the idea - includes a widget-style interface. In order to render these widgets, I use an &lt;font face="Courier New"&gt;ItemsControl&lt;/font&gt; and bind it to a collection of view models, each of which represents a widget. I use a &lt;font face="Courier New"&gt;Canvas &lt;/font&gt;to lay them out according to their &lt;font face="Courier New"&gt;XOffset &lt;/font&gt;and &lt;font face="Courier New"&gt;YOffset &lt;/font&gt;properties. Something like this:&lt;/p&gt;  &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;ItemsControl ItemsSource=&amp;quot;{Binding Widgets}&amp;quot;&amp;gt;
    &amp;lt;ItemsControl.ItemsPanel&amp;gt;
        &amp;lt;ItemsPanelTemplate&amp;gt;
            &amp;lt;Canvas/&amp;gt;
        &amp;lt;/ItemsPanelTemplate&amp;gt;
    &amp;lt;/ItemsControl.ItemsPanel&amp;gt;
    &amp;lt;ItemsControl.ItemContainerStyle&amp;gt;
        &amp;lt;Style&amp;gt;
            &amp;lt;Setter Property=&amp;quot;Canvas.Left&amp;quot; Value=&amp;quot;{Binding XOffset}&amp;quot;/&amp;gt;
            &amp;lt;Setter Property=&amp;quot;Canvas.Top&amp;quot; Value=&amp;quot;{Binding YOffset}&amp;quot;/&amp;gt;
        &amp;lt;/Style&amp;gt;
    &amp;lt;/ItemsControl.ItemContainerStyle&amp;gt;
    &amp;lt;ItemsControl.ItemTemplate&amp;gt;
        &amp;lt;DataTemplate&amp;gt;
            &amp;lt;views:WidgetView/&amp;gt;
        &amp;lt;/DataTemplate&amp;gt;
    &amp;lt;/ItemsControl.ItemTemplate&amp;gt;
&amp;lt;/ItemsControl&amp;gt;&lt;/pre&gt;

&lt;p&gt;This all works fine and I'd even go so far as to say it's a beautiful thing. However, it is only a widget-style interface by virtue of some trickery on my part. Without said trickery, it would be more of an MDI interface.&lt;/p&gt;

&lt;p&gt;With an MDI interface, multiple child windows are contained within a parent window – they cannot appear outside the bounds of the parent. Whilst my widgets &lt;em&gt;look&lt;/em&gt; like windows, they aren't. They're just regular WPF user controls with some additional smarts to allow positioning and what-have-you. And whilst it &lt;em&gt;looks&lt;/em&gt; like they're free to roam wherever they like on the desktop, they're not. They're all contained within the &lt;font face="Courier New"&gt;ItemsControl&lt;/font&gt;, which is within the only &lt;font face="Courier New"&gt;Window &lt;/font&gt;in my application. Thus, they cannot be positioned outside the area in which the &lt;font face="Courier New"&gt;Window &lt;/font&gt;resides. It just so happens that I've stretched that &lt;font face="Courier New"&gt;Window &lt;/font&gt;across the entire desktop and made it transparent. This gives the illusion that I have a widget interface and am thus as cool as &lt;em&gt;The Dude &lt;/em&gt;himself, but I actually have an MDI interface which makes me more &lt;em&gt;Napolean Dynamite &lt;/em&gt;than &lt;em&gt;Lebowski&lt;/em&gt;. Before the dance, that is.&lt;/p&gt;

&lt;p&gt;All this wouldn't concern me terribly (one learns to live with it) but my users are actually privy to more screen real estate than I. And when I say &amp;quot;more&amp;quot;, I mean they have six screens whilst I have two, one of which I can't use for anything of import because it frequently distorts and shows other signs of discontent (no audible screams as yet). Because of this abundance of screen real estate, my &lt;font face="Courier New"&gt;Window &lt;/font&gt;has to to stretch across a huge expanse of pixels in order to keep up this illusion of cool. This has dire consequences for performance. You see, if one's &lt;font face="Courier New"&gt;Window &lt;/font&gt;size exceeds the maximum texture size of one's video card (I don't have one of course, but my users do) then the video card won't be able to accelerate rendering of said &lt;font face="Courier New"&gt;Window&lt;/font&gt;. The &lt;font face="Courier New"&gt;Window &lt;/font&gt;will be software-rendered instead, which is probably going to be a lot slower and less capable of Dude-worthy effects and animations.&lt;/p&gt;

&lt;p&gt;No problem, you say. Just host your widgets inside windows instead and be done with it. And this is indeed what I am going to do.&lt;/p&gt;

&lt;p&gt;But I want it to be seamless with respect to the current code base. I don't want to have to go hook up a bunch of event handlers to create/show/close windows when my widget collection changes. I don't want to have to change the way my view models keep track of widget positions and sizes (all persisted across application restarts, of course). All I want to do is change this:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;ItemsControl ItemsSource=&amp;quot;{Binding Widgets}&amp;quot;&amp;gt;&lt;/pre&gt;

&lt;p&gt;to this:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;WindowItemsControl ItemsSource=&amp;quot;{Binding Widgets}&amp;quot;&amp;gt;&lt;/pre&gt;

&lt;p&gt;But unfortunately WPF doesn't have a &lt;font face="Courier New"&gt;WindowItemsControl&lt;/font&gt;. Boo. And it doesn't seem as though anyone in the community has written one.&lt;/p&gt;

&lt;p&gt;Obviously, then, I set out to write my own.&lt;/p&gt;

&lt;p&gt;My initial approach failed, but it's worth discussing anyway. I tried to have my &lt;font face="Courier New"&gt;WindowItemsControl&lt;/font&gt; create &lt;font face="Courier New"&gt;Window &lt;/font&gt;instances as containers. This failed because internal WPF code was attempting to add these &lt;font face="Courier New"&gt;Window&lt;/font&gt;s as visual children of the &lt;font face="Courier New"&gt;ItemsControl&lt;/font&gt;, and &lt;font face="Courier New"&gt;Window&lt;/font&gt;s must be top-level visual items (makes sense). So I tried to hack around this because I really wanted the logical connection between the &lt;font face="Courier New"&gt;Window &lt;/font&gt;and the &lt;font face="Courier New"&gt;WindowItemsControl&lt;/font&gt;, much the same way there's a logical connection between a &lt;font face="Courier New"&gt;ListBoxItem &lt;/font&gt;and its containing &lt;font face="Courier New"&gt;ListBox&lt;/font&gt;. If I could trick WPF into forgoing the visual connection, I could then attempt the logical connection.&lt;/p&gt;

&lt;p&gt;Well, I tried all sorts of nastiness, and ended up reflectively invoking an internal member to trick WPF into not including the &lt;font face="Courier New"&gt;Window &lt;/font&gt;as a visual child. Success! Right!? Alas, no, because when I then added the &lt;font face="Courier New"&gt;Window &lt;/font&gt;as a &lt;em&gt;logical &lt;/em&gt;child of the &lt;font face="Courier New"&gt;WindowItemsControl&lt;/font&gt;, I got another similar error. I can't remember the details, nor can I explain &lt;em&gt;why &lt;/em&gt;a &lt;font face="Courier New"&gt;Window &lt;/font&gt;cannot be a logical child of another control (it's only a logical connection, after all). But it didn't work and I gave up on this approach entirely.&lt;/p&gt;

&lt;p&gt;My second approach is much more sane but gives up on creating a logical connection between the &lt;font face="Courier New"&gt;Window&lt;/font&gt;s and their host. But I don't really need that anyway – it was a nice-to-have.&lt;/p&gt;

&lt;p&gt;What I did instead was had the &lt;font face="Courier New"&gt;WindowItemsControl &lt;/font&gt;create &lt;font face="Courier New"&gt;WindowItemsControlItem &lt;/font&gt;instances as containers. These containers are really just surrogates for the &lt;font face="Courier New"&gt;Window&lt;/font&gt; they represent. When they're initialized, they display the &lt;font face="Courier New"&gt;Window&lt;/font&gt;. When they're destroyed, they close the &lt;font face="Courier New"&gt;Window&lt;/font&gt;. In addition, if a &lt;font face="Courier New"&gt;Window &lt;/font&gt;is closed ahead of time, the corresponding data item is removed from the underlying collection and thus too the surrogate from the visual tree.&lt;/p&gt;

&lt;p&gt;The code is actually quite neat and compact. Here is the code for &lt;font face="Courier New"&gt;WindowItemsControl&lt;/font&gt;:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class WindowItemsControl : ItemsControl
{
	public static readonly DependencyProperty ShowDialogProperty = DependencyProperty.Register(
		&amp;quot;ShowDialog&amp;quot;,
		typeof(bool),
		typeof(WindowItemsControl));

	public static readonly DependencyProperty OwnerProperty = DependencyProperty.Register(
		&amp;quot;Owner&amp;quot;,
		typeof(Window),
		typeof(WindowItemsControl),
		new FrameworkPropertyMetadata(OnOwnerChanged));

	public static readonly DependencyProperty WindowStartupLocationProperty = DependencyProperty.Register(
		&amp;quot;WindowStartupLocation&amp;quot;,
		typeof(WindowStartupLocation),
		typeof(WindowItemsControl));

	public static readonly DependencyProperty RemoveDataItemWhenWindowClosedProperty = DependencyProperty.Register(
		&amp;quot;RemoveDataItemWhenWindowClosed&amp;quot;,
		typeof(bool),
		typeof(WindowItemsControl),
		new FrameworkPropertyMetadata(true));

	static WindowItemsControl()
	{
		DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowItemsControl), new FrameworkPropertyMetadata(typeof(WindowItemsControl)));
	}

	public bool ShowDialog
	{
		get { return (bool)this.GetValue(ShowDialogProperty); }
		set { this.SetValue(ShowDialogProperty, value); }
	}

	public Window Owner
	{
		get { return this.GetValue(OwnerProperty) as Window; }
		set { this.SetValue(OwnerProperty, value); }
	}

	public WindowStartupLocation WindowStartupLocation
	{
		get { return (WindowStartupLocation)this.GetValue(WindowStartupLocationProperty); }
		set { this.SetValue(WindowStartupLocationProperty, value); }
	}

	public bool RemoveDataItemWhenWindowClosed
	{
		get { return (bool)this.GetValue(RemoveDataItemWhenWindowClosedProperty); }
		set { this.SetValue(RemoveDataItemWhenWindowClosedProperty, value); }
	}

	protected override DependencyObject GetContainerForItemOverride()
	{
		return new WindowItemsControlItem(this);
	}

	protected override bool IsItemItsOwnContainerOverride(object item)
	{
		return item is WindowItemsControlItem;
	}

	protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
	{
		(element as WindowItemsControlItem).Window.Content = item;
	}

	protected override bool ShouldApplyItemContainerStyle(DependencyObject container, object item)
	{
		// the item container style will be applied to the windows, not to the containers (which are surrogates for the window)
		return false;
	}

	private static void OnOwnerChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
	{
		var windowItemsControl = (WindowItemsControl)dependencyObject;
		var owner = (Window)e.NewValue;

		for (var i = 0; i &amp;lt; windowItemsControl.Items.Count; ++i)
		{
			var container = windowItemsControl.ItemContainerGenerator.ContainerFromIndex(i) as WindowItemsControlItem;

			if (container == null)
			{
				continue;
			}

			container.Window.Owner = owner;
		}
	}
}&lt;/pre&gt;

&lt;p&gt;Pretty straightforward stuff. Note the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;it declares some properties (&lt;font face="Courier New"&gt;ShowDialog&lt;/font&gt;, &lt;font face="Courier New"&gt;Owner&lt;/font&gt;, &lt;font face="Courier New"&gt;WindowStartupLocation&lt;/font&gt;) that assist it in the display of child &lt;font face="Courier New"&gt;Window&lt;/font&gt;s&lt;/li&gt;

  &lt;li&gt;it declares a &lt;font face="Courier New"&gt;RemoveDataItemWhenWindowClosed&lt;/font&gt; property that can be used to prevent the control from removing data items when a window is closed. This can be useful in shutdown or other situations where windows are being closed programmatically rather than by the user&lt;/li&gt;

  &lt;li&gt;I don't apply the &lt;font face="Courier New"&gt;ItemContainerStyle &lt;/font&gt;to the containers themselves, but instead hold out so that I can apply them to the &lt;font face="Courier New"&gt;Window&lt;/font&gt;s they represent &lt;/li&gt;

  &lt;li&gt;I also make sure that any change of &lt;font face="Courier New"&gt;Owner &lt;/font&gt;is applied to any existing &lt;font face="Courier New"&gt;Window&lt;/font&gt;s &lt;/li&gt;

  &lt;li&gt;the default style is overridden to remove unnecessary stuff like the &lt;font face="Courier New"&gt;Border&lt;/font&gt;, because the &lt;font face="Courier New"&gt;WindowItemsControl &lt;/font&gt;will never actually be visible on screen &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;font face="Courier New"&gt;WindowItemsControl &lt;/font&gt;works in conjunction with the &lt;font face="Courier New"&gt;WindowItemsControlItem&lt;/font&gt;, which looks like this:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class WindowItemsControlItem : FrameworkElement
{
	private readonly WindowItemsControl windowItemsControl;
	private readonly Window window;

	static WindowItemsControlItem()
	{
		// there is no need for these items to be visible as they are simply surrogates for the windows that they display
		VisibilityProperty.OverrideMetadata(typeof(WindowItemsControlItem), new FrameworkPropertyMetadata(Visibility.Collapsed));
	}

	public WindowItemsControlItem(WindowItemsControl windowItemsControl)
	{
		windowItemsControl.AssertNotNull(&amp;quot;windowItemsControl&amp;quot;);

		this.windowItemsControl = windowItemsControl;
		this.window = this.CreateWindow(windowItemsControl);

		this.Loaded += delegate
		{
			if (this.windowItemsControl.ShowDialog)
			{
				this.window.ShowDialog();
			}
			else
			{
				this.window.Show();
			}
		};

		this.Unloaded += delegate
		{
			this.window.Close();
		};
	}

	public Window Window
	{
		get { return this.window; }
	}

	private Window CreateWindow(WindowItemsControl windowItemsControl)
	{
		var window = new Window
		{
			Owner = windowItemsControl.Owner,
			WindowStartupLocation = windowItemsControl.WindowStartupLocation
		};

		BindingOperations.SetBinding(window, Window.DataContextProperty, new Binding(&amp;quot;Content&amp;quot;) { Source = window });
		BindingOperations.SetBinding(window, Window.StyleProperty, new Binding(&amp;quot;ItemContainerStyle&amp;quot;) { Source = windowItemsControl });
		BindingOperations.SetBinding(window, Window.ContentTemplateProperty, new Binding(&amp;quot;ItemTemplate&amp;quot;) { Source = windowItemsControl });
		BindingOperations.SetBinding(window, Window.ContentTemplateSelectorProperty, new Binding(&amp;quot;ItemTemplateSelector&amp;quot;) { Source = windowItemsControl });

		window.Closed += delegate
		{
			// orphan the content because it might be hosted somewhere else later (including in another window)
			window.Content = null;

			// if the window closes, attempt to remove the original item from the underlying collection, which will result in this surrogate being removed too
			if (windowItemsControl.RemoveDataItemWhenWindowClosed)
			{
				var editableItems = windowItemsControl.Items as IEditableCollectionView;

				if (editableItems != null &amp;amp;&amp;amp; editableItems.CanRemove)
				{
					editableItems.Remove(this.DataContext);
				}
			}
		};

		return window;
	}
}&lt;/pre&gt;

&lt;p&gt;This is all pretty self-explanatory, too. The important points to note are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;relevant properties on the &lt;font face="Courier New"&gt;WindowItemsControl&lt;/font&gt; are bound to the correct properties on the &lt;font face="Courier New"&gt;Window&lt;/font&gt;s themselves &lt;/li&gt;

  &lt;li&gt;&lt;font face="Courier New"&gt;Window&lt;/font&gt;s are displayed when the surrogate is initialized, and closed when the surrogate is unloaded &lt;/li&gt;

  &lt;li&gt;as mentioned earlier, &lt;font face="Courier New"&gt;Window&lt;/font&gt;s that are closed before the surrogate is destroyed (perhaps by the user clicking the close button) result in the related data item in the underlying collection being removed (unless the &lt;font face="Courier New"&gt;RemoveDataItemWhenWindowClosed&lt;/font&gt; property has been set to &lt;font face="Courier New"&gt;false&lt;/font&gt;). This, in turn, will cause the surrogate to be removed from the visual tree. In other words, if I close a widget &lt;font face="Courier New"&gt;Window&lt;/font&gt;, the corresponding &lt;font face="Courier New"&gt;WidgetViewModel &lt;/font&gt;will be removed from my collection of widget view models. Then, the &lt;font face="Courier New"&gt;ItemsControl &lt;/font&gt;will remove the related surrogate container from the visual tree. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, as I yearned for at the beginning of this post, I can simply change my &lt;font face="Courier New"&gt;ItemsControl &lt;/font&gt;to a &lt;font face="Courier New"&gt;WindowItemsControl&lt;/font&gt;, make minor adjustments to my &lt;font face="Courier New"&gt;ItemContainerStyle &lt;/font&gt;and it just magically works.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The Dude abides.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I created a little demo to show how it all works, which you can download below. Enjoy!&lt;/p&gt;
&lt;iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; width: 98px; padding-right: 0px; height: 115px; padding-top: 0px" title="Preview" marginheight="0" src="https://skydrive.live.com/embedicon.aspx/Blog/WindowItemsControl.zip?cid=328ba01b2a22de20&amp;amp;sc=documents" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-2203493672276969829?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/2203493672276969829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=2203493672276969829' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2203493672276969829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2203493672276969829'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/11/application-im-currently-working-on-top.html' title='WindowItemsControl'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-2051145455643128550</id><published>2011-11-12T12:51:00.001Z</published><updated>2011-11-12T15:58:44.572Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MEF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Prism'/><title type='text'>LogExportProvider</title><content type='html'>&lt;p&gt;We all know how important logging is to any non-trivial application, so it stands to reason that we should make it as pain free as possible to add logging to our application components. But at the same time, we don't want to sacrifice too much, such as having to deal with a sub-standard logging API, or with a logging infrastructure that doesn't log the obvious stuff on our behalf.&lt;/p&gt;  &lt;p&gt;Wouldn't it be nice if logging were as simple as this:&lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;namespace SomeNamespace
{
    public class SomeClass
    {
        [ImportingConstructor]
        public SomeClass(ILoggerService loggerService)
        {
            loggerService.Debug(&amp;quot;Created an instance of {0}.&amp;quot;, GetType().Name);
        }
    }
}&lt;/pre&gt;

&lt;p&gt;And, importantly, the resultant log entry looked something like this:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;[2011-11-12 12:09:04,749] [1] [DEBUG] [SomeNamespace.SomeClass] Created an instance of SomeClass.&lt;/pre&gt;

&lt;p&gt;Prism ships with an &lt;font face="Courier New"&gt;ILoggerFacade&lt;/font&gt; interface that looks like this:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public interface ILoggerFacade 
{ 
    void Log(string message, Category category, Priority priority); 
}&lt;/pre&gt;

&lt;p&gt;This is obviously a very bare-bones interface. Every time you write a log statement you'll be forced to:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Format any parameters yourself. &lt;/li&gt;

  &lt;li&gt;Specify the category as a parameter (instead of having separate methods for each category) &lt;/li&gt;

  &lt;li&gt;Choose and specify a priority, even if it makes no sense for your code. &lt;/li&gt;

  &lt;li&gt;Incur the cost of any preparation for the log statement even if the pertinent log level is disabled because you have no way to check whether it is or not. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is not very consumer-friendly at all, and you'll more than likely begin to find logging a more onerous task than it should be.&lt;/p&gt;

&lt;p&gt;Another problem with using &lt;font face="Courier New"&gt;ILoggerFacade&lt;/font&gt; in Prism is the lack of any originating source in the output. There is nothing intrinsic to differentiate log statements from different components. If two components log the same message (&amp;quot;Initialized&amp;quot;, for example), you will have no way to tell which component was initialized!&lt;/p&gt;

&lt;p&gt;These problems forced me to come up with a custom solution. I wanted my logging to be based on log4net, and I wanted MEF to provide my components with a logging service instance. Moreover, that service must produce log entries that are specific to my component.&lt;/p&gt;

&lt;p&gt;The first problem (poor API) was easiest to solve. I defined my own interface as follows:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public interface ILoggerService 
{ 
    bool IsVerboseEnabled 
    { 
        get; 
    }

    bool IsDebugEnabled 
    { 
        get; 
    }

    bool IsInfoEnabled 
    { 
        get; 
    }

    bool IsWarnEnabled 
    { 
        get; 
    }

    bool IsErrorEnabled 
    { 
        get; 
    }

    bool IsPerfEnabled 
    { 
        get; 
    }

    void Verbose(string message);

    void Verbose(string message, Exception exception);

    void Verbose(string message, params object[] args);

    void Debug(string message);

    void Debug(string message, Exception exception);

    void Debug(string message, params object[] args);

    void Info(string message);

    void Info(string message, Exception exception);

    void Info(string message, params object[] args);

    void Warn(string message);

    void Warn(string message, Exception exception);

    void Warn(string message, params object[] args);

    void Error(string message);

    void Error(string message, Exception exception);

    void Error(string message, params object[] args);

    IDisposable Perf(string message);

    IDisposable Perf(string message, params object[] args); 
}&lt;/pre&gt;

&lt;p&gt;As you can see, this interface provides many overloads for all the relevant combinations of parameters you might need. This saves you, the caller, from having to deal with the annoyance of formatting messages or exceptions. There are also properties that can be used to check whether a given log level is enabled, which can be crucial in performance-critical paths. Finally, notice the handy &lt;font face="Courier New"&gt;Perf &lt;/font&gt;overloads which can be used to measure the performance of a block of code like this:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;using (loggerService.Perf(&amp;quot;Authenticating the user&amp;quot;)) 
{ 
    // do authentication here
}&lt;/pre&gt;

&lt;p&gt;The only thing I haven't included (because I haven't needed it) are generic &lt;font face="Courier New"&gt;Write &lt;/font&gt;methods that take the log level as a parameter instead of inferring the log level from the method name. Such methods can be useful in dynamic logging scenarios, so you may want to add your own.&lt;/p&gt;

&lt;p&gt;With the API defined, it was time to write an implementation:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public sealed class Log4NetLoggerService : ILoggerService 
{ 
    private static readonly Level perfLevel = new Level(35000, &amp;quot;PERF&amp;quot;); 
    private readonly ILog log;

    public Log4NetLoggerService(ILog log) 
    { 
        log.AssertNotNull(&amp;quot;log&amp;quot;); 
        this.log = log; 
    }

    public bool IsVerboseEnabled 
    { 
        get { return this.log.Logger.IsEnabledFor(Level.Verbose); } 
    }

    public bool IsDebugEnabled 
    { 
        get { return this.log.IsDebugEnabled; } 
    }

    public bool IsInfoEnabled 
    { 
        get { return this.log.IsInfoEnabled; } 
    }

    public bool IsWarnEnabled 
    { 
        get { return this.log.IsWarnEnabled; } 
    }

    public bool IsErrorEnabled 
    { 
        get { return this.log.IsErrorEnabled; } 
    }

    public bool IsPerfEnabled 
    { 
        get { return this.log.Logger.IsEnabledFor(perfLevel); } 
    }

    public void Verbose(string message) 
    { 
        this.log.Logger.Log(typeof(Log4NetLoggerService), Level.Verbose, message, null); 
    }

    public void Verbose(string message, Exception exception) 
    { 
        this.log.Logger.Log(typeof(Log4NetLoggerService), Level.Verbose, message, exception); 
    }

    public void Verbose(string message, params object[] args) 
    { 
        this.log.Logger.Log(typeof(Log4NetLoggerService), Level.Verbose, new SystemStringFormat(CultureInfo.InvariantCulture, message, args), null); 
    }

    public void Debug(string message) 
    { 
        this.log.Debug(message); 
    }

    public void Debug(string message, Exception exception) 
    { 
        this.log.Debug(message, exception); 
    }

    public void Debug(string message, params object[] args) 
    { 
        this.log.DebugFormat(CultureInfo.InvariantCulture, message, args); 
    }

    public void Info(string message) 
    { 
        this.log.Info(message); 
    }

    public void Info(string message, Exception exception) 
    { 
        this.log.Info(message, exception); 
    }

    public void Info(string message, params object[] args) 
    { 
        this.log.InfoFormat(CultureInfo.InvariantCulture, message, args); 
    }

    public void Warn(string message) 
    { 
        this.log.Warn(message); 
    }

    public void Warn(string message, Exception exception) 
    { 
        this.log.Warn(message, exception); 
    }

    public void Warn(string message, params object[] args) 
    { 
        this.log.WarnFormat(CultureInfo.InvariantCulture, message, args); 
    }

    public void Error(string message) 
    { 
        this.log.Error(message); 
    }

    public void Error(string message, Exception exception) 
    { 
        this.log.Error(message, exception); 
    }

    public void Error(string message, params object[] args) 
    { 
        this.log.ErrorFormat(CultureInfo.InvariantCulture, message, args); 
    }

    public IDisposable Perf(string message) 
    { 
        message.AssertNotNull(&amp;quot;message&amp;quot;); 
        return new PerfBlock(this, message); 
    }

    public IDisposable Perf(string message, params object[] args) 
    { 
        message.AssertNotNull(&amp;quot;message&amp;quot;); 
        args.AssertNotNull(&amp;quot;args&amp;quot;); 
        return new PerfBlock(this, string.Format(CultureInfo.InvariantCulture, message, args)); 
    }

    private sealed class PerfBlock : IDisposable 
    { 
        private readonly Log4NetLoggerService owner; 
        private readonly string message; 
        private readonly Stopwatch stopwatch; 
        private bool disposed;

        public PerfBlock(Log4NetLoggerService owner, string message) 
        { 
            this.owner = owner; 
            this.message = message; 
            this.stopwatch = Stopwatch.StartNew(); 
        }

        public void Dispose() 
        { 
            if (!this.disposed) 
            { 
                this.disposed = true; 
                this.stopwatch.Stop(); 
                var messageWithTimingInfo = string.Format(CultureInfo.InvariantCulture, &amp;quot;{0} [{1}, {2}ms]&amp;quot;, this.message, this.stopwatch.Elapsed, this.stopwatch.ElapsedMilliseconds); 
                this.owner.log.Logger.Log(typeof(Log4NetLoggerService), perfLevel, messageWithTimingInfo, null); 
            } 
        } 
    } 
}&lt;/pre&gt;

&lt;p&gt;It's all pretty straightforward - most of the code just delegates to log4net.&lt;/p&gt;

&lt;p&gt;But notice how the constructor requires a &lt;font face="Courier New"&gt;log4net.ILog&lt;/font&gt;? Log4net provides various ways by which an &lt;font face="Courier New"&gt;ILog &lt;/font&gt;can be obtained, but we would like to use &lt;font face="Courier New"&gt;LogManager.GetLogger(Type ownerType)&lt;/font&gt;, where &lt;font face="Courier New"&gt;ownerType &lt;/font&gt;is the type importing our service. How, then, can we expect MEF to provide instances of &lt;font face="Courier New"&gt;ILoggerService &lt;/font&gt;when our constructor has a dependency that it cannot satisfy?&lt;/p&gt;

&lt;p&gt;MEF supports an abstraction called &lt;font face="Courier New"&gt;ExportProvider&lt;/font&gt;, which is an object that can dynamically provide exports to satisfy matching imports. The trick to making this all work seamlessly is a custom &lt;font face="Courier New"&gt;ExportProvider &lt;/font&gt;that creates instances of &lt;font face="Courier New"&gt;Log4NetLoggerService &lt;/font&gt;on the fly to satisfy imports of type &lt;font face="Courier New"&gt;ILoggerService&lt;/font&gt;. In order to create &lt;font face="Courier New"&gt;Log4NetLoggerService &lt;/font&gt;instances, the export provider must know the type of the object that is importing the service. Thankfully, MEF supports obtaining this information through its reflection services.&lt;/p&gt;

&lt;p&gt;Here is the code for our custom &lt;font face="Courier New"&gt;ExportProvider&lt;/font&gt;:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public sealed class LoggerServiceExportProvider : ExportProvider 
{ 
    private static readonly ILoggerService log = new Log4NetLoggerService(LogManager.GetLogger(typeof(LoggerServiceExportProvider))); 
    private readonly IDictionary&amp;lt;Type, ILoggerService&amp;gt; loggerServiceCache;

    public LoggerServiceExportProvider() 
    { 
        this.loggerServiceCache = new Dictionary&amp;lt;Type, ILoggerService&amp;gt;(); 
    }

    protected override IEnumerable&amp;lt;Export&amp;gt; GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition) 
    { 
        var contractName = definition.ContractName;

        log.Verbose(&amp;quot;Attempting to resolve contract name '{0}' to a log instance.&amp;quot;, contractName);

        if (string.IsNullOrEmpty(contractName)) 
        { 
            log.Verbose(&amp;quot;Contract name is null or empty - cannot resolve.&amp;quot;); 
            yield break; 
        }

        if (!string.Equals(typeof(ILoggerService).FullName, contractName, StringComparison.Ordinal)) 
        { 
            log.Verbose(&amp;quot;Incorrect contract - cannot resolve.&amp;quot;); 
            yield break; 
        }

        if (definition.Cardinality != ImportCardinality.ExactlyOne) 
        { 
            log.Verbose(&amp;quot;Cardinality is {0} - cannot resolve.&amp;quot;, definition.Cardinality); 
            yield break; 
        }

        // in order to get a log4net logger, we need the type importing the logger facade 
        Type ownerType = null;

        if (ReflectionModelServices.IsImportingParameter(definition)) 
        { 
            log.Verbose(&amp;quot;Parameter import detected.&amp;quot;);

            var importingParameter = ReflectionModelServices.GetImportingParameter(definition); 
            ownerType = importingParameter.Value.Member.DeclaringType; 
        } 
        else 
        { 
            log.Verbose(&amp;quot;Property import detected.&amp;quot;);

            var setAccessor = ReflectionModelServices 
                .GetImportingMember(definition) 
                .GetAccessors() 
                .Where(x =&amp;gt; x is MethodInfo) 
                .Select(x =&amp;gt; x as MethodInfo) 
                .FirstOrDefault(x =&amp;gt; (x.Attributes &amp;amp; MethodAttributes.SpecialName) == MethodAttributes.SpecialName &amp;amp;&amp;amp; x.Name.StartsWith(&amp;quot;set_&amp;quot;, StringComparison.Ordinal));

            if (setAccessor == null) 
            { 
                log.Verbose(&amp;quot;Set accessor for property not found - cannot resolve.&amp;quot;); 
                yield break; 
            }

            ownerType = setAccessor.DeclaringType; 
        }

        if (ownerType == null) 
        { 
            log.Verbose(&amp;quot;Owner type could not be determined - cannot resolve.&amp;quot;); 
            yield break; 
        }

        log.Verbose(&amp;quot;Owner type is '{0}'.&amp;quot;, ownerType.FullName);

        ILoggerService loggerService;

        if (!this.loggerServiceCache.TryGetValue(ownerType, out loggerService)) 
        { 
            log.Verbose(&amp;quot;Logger facade for owner type '{0}' is not yet cached - creating it.&amp;quot;, ownerType.FullName);

            var logInstance = LogManager.GetLogger(ownerType); 
            loggerService = new Log4NetLoggerService(logInstance); 
            this.loggerServiceCache[ownerType] = loggerService; 
        }

        var export = new Export(contractName, () =&amp;gt; loggerService); 
        yield return export; 
    } 
}&lt;/pre&gt;

&lt;p&gt;There are several things to note about this implementation:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Log service instances are cached. This means that if different instances of the same type import a logger service, they will (quickly) get the exact same instance. &lt;/li&gt;

  &lt;li&gt;Imports can be either via constructors or through properties. The export provider supports both. &lt;/li&gt;

  &lt;li&gt;The export provider itself includes logging statements, but it must do so with an explicitly created &lt;font face="Courier New"&gt;ILog&lt;/font&gt; instance. Obviously the export provider cannot import an &lt;font face="Courier New"&gt;ILoggerService&lt;/font&gt; itself or we'd have a chicken and egg problem! &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can tell MEF to use our custom &lt;font face="Courier New"&gt;ExportProvider&lt;/font&gt; in the usual fashion:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;var compositionContainer = new CompositionContainer(new LoggerServiceExportProvider());&lt;/pre&gt;

&lt;p&gt;With this infrastructure in place, we achieve our objectives entirely. The code I included right at the beginning of this post will work, and any log entries will include the details of the originating type. And it is ridiculously easy for us to imbue components created by MEF with logging statements. Simply add the import and then invoke the simple-to-use APIs.&lt;/p&gt;

&lt;p&gt;For a working example, click below. Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;iframe style="padding-bottom: 0px; background-color: #fcfcfc; padding-left: 0px; width: 98px; padding-right: 0px; height: 115px; padding-top: 0px" title="Preview" marginheight="0" src="https://skydrive.live.com/embedicon.aspx/Blog/LogExportProvider.zip?cid=328ba01b2a22de20&amp;amp;sc=documents" frameborder="0" marginwidth="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-2051145455643128550?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/2051145455643128550/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=2051145455643128550' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2051145455643128550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2051145455643128550'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/11/logexportprovider.html' title='LogExportProvider'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-2082576138001110249</id><published>2011-08-29T10:54:00.001+01:00</published><updated>2011-09-03T17:38:00.838+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><title type='text'>Using InheritanceBehavior to Aid Theme Development</title><content type='html'>&lt;p&gt;If you've ever put together a custom theme for WPF, you'll know the value of comparing your theme to the system theme. You can quickly spot things that you've missed, or compare and contrast behavior. However, if your theme targets controls by type rather than by key (and most themes should), how do you ensure your theme &lt;em&gt;isn't&lt;/em&gt; applied to a given control? That is, how do you ensure a given control inherits the system theme regardless of the application-defined themes?&lt;/p&gt;  &lt;p&gt;Suppose you're implementing a style for buttons. It looks like this:&lt;/p&gt;  &lt;pre class="brush:xml; toolbar: false"&gt;&amp;lt;Style TargetType=&amp;quot;Button&amp;quot;&amp;gt;
    &amp;lt;Setter Property=&amp;quot;Background&amp;quot;&amp;gt;
        &amp;lt;Setter.Value&amp;gt;
            &amp;lt;LinearGradientBrush StartPoint=&amp;quot;0,0&amp;quot; EndPoint=&amp;quot;0,1&amp;quot;&amp;gt;
                &amp;lt;GradientStop Offset=&amp;quot;0&amp;quot; Color=&amp;quot;#5f9ea0&amp;quot;/&amp;gt;
                &amp;lt;GradientStop Offset=&amp;quot;0.5&amp;quot; Color=&amp;quot;#3f7e80&amp;quot;/&amp;gt;
                &amp;lt;GradientStop Offset=&amp;quot;0.5&amp;quot; Color=&amp;quot;#7fbec0&amp;quot;/&amp;gt;
                &amp;lt;GradientStop Offset=&amp;quot;1&amp;quot; Color=&amp;quot;#1f5e80&amp;quot;/&amp;gt;
            &amp;lt;/LinearGradientBrush&amp;gt;
        &amp;lt;/Setter.Value&amp;gt;
    &amp;lt;/Setter&amp;gt;
    &amp;lt;Setter Property=&amp;quot;Foreground&amp;quot; Value=&amp;quot;White&amp;quot;/&amp;gt;
    &amp;lt;Setter Property=&amp;quot;FontFamily&amp;quot; Value=&amp;quot;Bauhaus 93&amp;quot;/&amp;gt;
    &amp;lt;Setter Property=&amp;quot;FontSize&amp;quot; Value=&amp;quot;12pt&amp;quot;/&amp;gt;
    &amp;lt;Setter Property=&amp;quot;FontWeight&amp;quot; Value=&amp;quot;Normal&amp;quot;/&amp;gt;
&amp;lt;/Style&amp;gt;&lt;/pre&gt;

&lt;p&gt;You want to put together a little test control that shows your themed &lt;font face="Courier New"&gt;Button&lt;/font&gt; against a system-themed &lt;font face="Courier New"&gt;Button&lt;/font&gt;:&lt;/p&gt;

&lt;pre class="brush:xml; toolbar: false"&gt;&amp;lt;StackPanel&amp;gt; 
    &amp;lt;Button&amp;gt;System Theme&amp;lt;/Button&amp;gt; 
    &amp;lt;Button&amp;gt;Application Theme&amp;lt;/Button&amp;gt; 
&amp;lt;/StackPanel&amp;gt;&lt;/pre&gt;

&lt;p&gt;But that won't work - both buttons will inherit your theme. In this case, you can simply tell the second &lt;font face="Courier New"&gt;Button&lt;/font&gt; not to apply your &lt;font face="Courier New"&gt;Style&lt;/font&gt;, thus ensuring it inherits the system-defined one:&lt;/p&gt;

&lt;pre class="brush:xml; toolbar: false"&gt;&amp;lt;Button Style=&amp;quot;{x:Null}&amp;quot;&amp;gt;System Theme&amp;lt;/Button&amp;gt;&lt;/pre&gt;

&lt;p&gt;But what if you're theming something far more complex, like the &lt;font face="Courier New"&gt;DataGrid&lt;/font&gt; control? It has child controls (&lt;font face="Courier New"&gt;DataGridCell&lt;/font&gt;, &lt;font face="Courier New"&gt;DataGridRow&lt;/font&gt;, &lt;font face="Courier New"&gt;DataGridColumnHeader&lt;/font&gt; etc), each with their own style. How can you stop all those child controls from inheriting the styles provided by your theme? Well, sometimes the parent control (&lt;font face="Courier New"&gt;DataGrid&lt;/font&gt; in this case) will expose properties that allow you to override the styles for child controls:&lt;/p&gt;

&lt;pre class="brush:xml; toolbar: false"&gt;&amp;lt;DataGrid Style=&amp;quot;{x:Null}&amp;quot; CellStyle=&amp;quot;{x:Null}&amp;quot; RowStyle=&amp;quot;{x:Null}&amp;quot; .../&amp;gt;&lt;/pre&gt;

&lt;p&gt;But this is tedious, error-prone, and not all controls will expose such properties. What, then, is the diligent WPF journeyman to do?&lt;/p&gt;

&lt;p&gt;The best way around this problem I've found is to make use of the little-known &lt;font face="Courier New"&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.inheritancebehavior.aspx"&gt;FrameworkElement.InheritanceBehavior&lt;/a&gt;&lt;/font&gt; property. This protected property specifies how resource and property inheritance lookups should behave from any &lt;font face="Courier New"&gt;FrameworkElement&lt;/font&gt;. We can define a simple control with an inheritance behavior to meet our needs as follows:&lt;/p&gt;

&lt;pre class="brush: csharp; toolbar: false"&gt;public sealed class UseSystemTheme : ContentControl 
{ 
    public UseSystemTheme() 
    { 
        this.InheritanceBehavior = System.Windows.InheritanceBehavior.SkipToThemeNow; 
    } 
}&lt;/pre&gt;

&lt;p&gt;Then, to prevent a control from inheriting our themed &lt;font face="Courier New"&gt;Style&lt;/font&gt;, we can simply wrap it in a &lt;font face="Courier New"&gt;UseSystemTheme&lt;/font&gt;. Going back to our &lt;font face="Courier New"&gt;Button&lt;/font&gt; example, it would look like:&lt;/p&gt;

&lt;pre class="brush:xml; toolbar: false"&gt;&amp;lt;StackPanel&amp;gt; 
    &amp;lt;local:UseSystemTheme&amp;gt; 
        &amp;lt;Button&amp;gt;System Theme&amp;lt;/Button&amp;gt; 
    &amp;lt;/local:UseSystemTheme&amp;gt; 
    &amp;lt;Button&amp;gt;Application Theme&amp;lt;/Button&amp;gt; 
&amp;lt;/StackPanel&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/-r-lyGZxQprU/Tlthu0rvopI/AAAAAAAABSM/i0BObOn81P0/s1600-h/image%25255B9%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" align="right" src="http://lh6.ggpht.com/-L4NCVq317ys/TlthvYJ5BaI/AAAAAAAABSQ/lczQzcxuRWE/image_thumb%25255B1%25255D.png?imgmax=800" width="286" height="61" /&gt;&lt;/a&gt;Now it's easy to ensure we're comparing the application theme against the system theme. Moreover, you can use the same approach regardless of how complex the contained elements are. So it’ll work whether you’re styling a &lt;font face="Courier New"&gt;Button&lt;/font&gt;, a &lt;font face="Courier New"&gt;DataGrid&lt;/font&gt;, or whatever.&lt;/p&gt;

&lt;p&gt;NOTE: I actually made my &lt;font face="Courier New"&gt;UseSystemTheme&lt;/font&gt; control a little more complex than presented here. I had it override its default &lt;font face="Courier New"&gt;Background&lt;/font&gt; value and set it to &lt;font face="Courier New"&gt;SystemColors.WindowBrush&lt;/font&gt;. Then I had to provide a template for it because, by default, a &lt;font face="Courier New"&gt;ContentControl &lt;/font&gt;does not honor its &lt;font face="Courier New"&gt;Background&lt;/font&gt; property. These changes ensure that every &lt;font face="Courier New"&gt;UseSystemTheme &lt;/font&gt;instance has the default brush as its background instead of inheriting whatever else you've set in your theme. It’s the &lt;em&gt;child &lt;/em&gt;of the &lt;font face="Courier New"&gt;UseSystemTheme &lt;/font&gt;instance whose resource lookup is affected by &lt;font face="Courier New"&gt;InheritanceBehavior&lt;/font&gt;, not the &lt;font face="Courier New"&gt;UseSystemTheme &lt;/font&gt;instance itself!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-2082576138001110249?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/2082576138001110249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=2082576138001110249' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2082576138001110249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2082576138001110249'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/08/using-inheritancebehavior-to-aid-theme.html' title='Using InheritanceBehavior to Aid Theme Development'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/-L4NCVq317ys/TlthvYJ5BaI/AAAAAAAABSQ/lczQzcxuRWE/s72-c/image_thumb%25255B1%25255D.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-2554069566159465037</id><published>2011-07-01T21:07:00.001+01:00</published><updated>2011-07-01T21:07:34.773+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Random Thoughts'/><category scheme='http://www.blogger.com/atom/ns#' term='Misc Technical'/><title type='text'>Call of Duty 2 Startup Error</title><content type='html'>&lt;p&gt;Kind of random, even for my blog, but I got this error when attempting to re-live the pure awesome that is Call of Duty 2:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;---------------------------     &lt;br /&gt;WIN_ERROR      &lt;br /&gt;---------------------------      &lt;br /&gt;Error during initialization:      &lt;br /&gt;Couldn't load default_localize.cfg.&amp;#160; Make sure Call of Duty is run from the correct folder.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;---------------------------     &lt;br /&gt;OK&amp;#160;&amp;#160; &lt;br /&gt;---------------------------&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;I couldn’t find any decent advice on this, so I fiddled around a bit and noticed that the shortcut did not specify a working directory. I tried setting it to the directory to which I’d installed (&lt;em&gt;D:\Program Files (x86)\Activision\Call of Duty 2\&lt;/em&gt;) and all was good. I’d imagine this happening in a couple of cases:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;If you install to anywhere other than &lt;em&gt;C:\&lt;/em&gt;&lt;/li&gt;    &lt;li&gt;If you’re installing on a 64 bit machine&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;These are just theories though – I really can’t be bothered validating this, as I’m too busy shooting nazis.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-2554069566159465037?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/2554069566159465037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=2554069566159465037' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2554069566159465037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2554069566159465037'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/07/call-of-duty-2-startup-error.html' title='Call of Duty 2 Startup Error'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-2801711387375624914</id><published>2011-04-09T14:04:00.001+01:00</published><updated>2011-04-09T14:04:04.872+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>RangeCollectionView</title><content type='html'>&lt;p&gt;WPF and Silverlight both support an abstraction called collection views, manifested by the &lt;a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionview.aspx"&gt;&lt;font face="Courier New"&gt;ICollectionView&lt;/font&gt;&lt;/a&gt; interface. Whenever you bind to a collection, you're actually binding to a collection view, whether you do so explicitly or not. The original collection is exposed via the &lt;a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionview.sourcecollection.aspx"&gt;&lt;font face="Courier New"&gt;ICollectionView.SourceCollection&lt;/font&gt;&lt;/a&gt; property, but is often referred to as the &amp;quot;underlying collection&amp;quot;.&lt;/p&gt;  &lt;p&gt;WPF/SL both ship with some commonly-used collection view implementations, but sometimes you need something a little different. In a &lt;a href="http://kentb.blogspot.com/2010/07/virtual-paging-in-silverlight.html"&gt;previous post&lt;/a&gt; I showed a custom collection view that can be used to implement virtual paging in Silverlight. In this post I'm going to show you a collection view that exposes a range of items in its underlying collection. This is useful, for example, when you have a larger data set that the user is able to &amp;quot;zoom into&amp;quot;. An obvious example is the Google finance charts:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_i_HIkiy_ogI/TaBZKbbineI/AAAAAAAABRk/UWLKVYW-dHA/s1600-h/image%5B8%5D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Google Finance Chart" border="0" alt="Google Finance Chart" src="http://lh3.ggpht.com/_i_HIkiy_ogI/TaBZKzyLJSI/AAAAAAAABRo/cfbxxIFYsqk/image_thumb%5B6%5D.png?imgmax=800" width="488" height="340" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Notice how the chart requires the full set of data in order to render the lower preview area, as well as a subset of data in order to render the upper zoomed area. It is this subset that we want to be able to easily expose via a custom collection view.&lt;/p&gt;  &lt;p&gt;My design for this collection view is quite straightforward. Here is the public API:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/TaBZLDnuOhI/AAAAAAAABRs/aErhsX4N8Ig/s1600-h/ClassDiagram%5B5%5D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Class Diagram" border="0" alt="Class Diagram" src="http://lh5.ggpht.com/_i_HIkiy_ogI/TaBZLvSimSI/AAAAAAAABRw/E581BJXbxyw/ClassDiagram_thumb%5B3%5D.png?imgmax=800" width="283" height="303" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;As you can see, I called the custom collection &lt;font face="Courier New"&gt;RangeCollectionView&lt;/font&gt;. It extends the built-in &lt;font face="Courier New"&gt;ListCollectionView&lt;/font&gt; and adds two important properties: &lt;font face="Courier New"&gt;StartIndex&lt;/font&gt; and &lt;font face="Courier New"&gt;EndIndex&lt;/font&gt;. These indexes demarcate the subset of the underlying collection that will be exposed by the range collection view. They are both inclusive.&lt;/p&gt;  &lt;p&gt;Suppose you have a list of month names in order (&amp;quot;January&amp;quot;...&amp;quot;December&amp;quot;). If you wrap that list in a range collection view and set &lt;font face="Courier New"&gt;StartIndex&lt;/font&gt; to &lt;font face="Courier New"&gt;5&lt;/font&gt; and &lt;font face="Courier New"&gt;EndIndex&lt;/font&gt; to &lt;font face="Courier New"&gt;9&lt;/font&gt;, that range collection view will expose only the following items:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;June&lt;/li&gt;    &lt;li&gt;July&lt;/li&gt;    &lt;li&gt;August&lt;/li&gt;    &lt;li&gt;September&lt;/li&gt;    &lt;li&gt;October&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Internally, &lt;font face="Courier New"&gt;RangeCollectionView&lt;/font&gt; uses the &lt;font face="Courier New"&gt;StartIndex&lt;/font&gt; and &lt;font face="Courier New"&gt;EndIndex&lt;/font&gt; properties to redefine the behaviour of various members defined by &lt;font face="Courier New"&gt;ListCollectionView&lt;/font&gt;. &lt;font face="Courier New"&gt;ListCollectionView&lt;/font&gt; is sufficiently flexible to allow this, which is a very good thing because it means we get certain features for &amp;quot;free&amp;quot;, like sorting and grouping.&lt;/p&gt;  &lt;p&gt;Going back to our chart example, consider that we can simply wrap our primary data set in a &lt;font face="Courier New"&gt;RangeCollectionView&lt;/font&gt; and then modify &lt;font face="Courier New"&gt;StartIndex&lt;/font&gt; and &lt;font face="Courier New"&gt;EndIndex&lt;/font&gt; according to the set of data the user has zoomed into. As the user zooms in, the start and end indexes move closer together. As the user zooms out, they widen.&lt;/p&gt;  &lt;p&gt;The attached solution provides the code for &lt;font face="Courier New"&gt;RangeCollectionView&lt;/font&gt;, related unit tests, and a working example of how &lt;font face="Courier New"&gt;RangeCollectionView&lt;/font&gt; can be used to achieve an experience similar to that on Google finance. Here is an example of it in action:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_i_HIkiy_ogI/TaBZOe1kU0I/AAAAAAAABR0/BPVtF31NgLw/s1600-h/capture-2%5B4%5D.gif"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Range Collection View Demo" border="0" alt="Range Collection View Demo" src="http://lh6.ggpht.com/_i_HIkiy_ogI/TaBZQwLq9vI/AAAAAAAABR4/0nJq3iAToK8/capture-2_thumb%5B2%5D.gif?imgmax=800" width="489" height="311" /&gt;&lt;/a&gt;&lt;/p&gt;        &lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/RangeCollectionViewDemo.zip"&gt;Download Sample&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-2801711387375624914?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/2801711387375624914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=2801711387375624914' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2801711387375624914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2801711387375624914'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/04/rangecollectionview.html' title='RangeCollectionView'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_i_HIkiy_ogI/TaBZKzyLJSI/AAAAAAAABRo/cfbxxIFYsqk/s72-c/image_thumb%5B6%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-3083908621440038047</id><published>2011-03-23T19:17:00.001Z</published><updated>2011-09-03T17:36:07.450+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><title type='text'>TieredVisualStateManager</title><content type='html'>&lt;p&gt;A &lt;a href="http://kentb.blogspot.com/2011/02/minimumtimevisualstatemanager.html"&gt;couple of posts ago&lt;/a&gt;, I discussed a custom visual state manager that allows you to impose a minimal amount of time for which a state must be active. In this post I'm going to push the visual state management infrastructure even further out of its comfort zone.&lt;/p&gt;  &lt;p&gt;Imagine you've just finished developing a kick-ass WPF application that has extracted &amp;quot;ooooh&amp;quot;s and &amp;quot;aaaah&amp;quot;s from all the stakeholders. You're at the pub when your boss calls you and asks why the application keeps hanging on his machine. &amp;quot;Hanging?&amp;quot;, you ask, reluctantly putting down the celebratory beer. &amp;quot;Yes, it stops and starts like a handsaw.&amp;quot;, he replies. &amp;quot;Oh, you mean stuttering.&amp;quot; &amp;quot;That's what I said - stuttering.&amp;quot;&lt;/p&gt;  &lt;p&gt;Intrigued, you head back into the office. Before your boss even fires up the application you notice the turbo button on his PC and your head drops into your hands. Predictably, your application takes a full minute to fire up and then renders at a frame rate of three Walt Disney animators.&lt;/p&gt;  &lt;p&gt;&amp;quot;It's your machine.&amp;quot;, you say dejectedly. &amp;quot;I don't care what it is - fix it. Today!&amp;quot;&lt;/p&gt;  &lt;p&gt;You drag your feet all the way back to your desk, pondering the state of the job market in your area. You sit down at your desk and crack open your solution, the solution that was your pride and joy a mere hour ago. You don't bother firing up a profiler because you had already profiled and tweaked the performance of the application prior to shipping - you know there's nothing significant left to squeeze out of it.&lt;/p&gt;  &lt;p&gt;At this point most of us would simply strip out animations, transitions, effects, and other non-critical niceties that are placing a strain on the frame rate. This has the advantage of getting your boss off your back (and you back at the pub), but the disadvantage of lowering the experience for users who have hardware dating post 1990. Not to mention the fact that you've likely had a UX designer put in significant amounts of thought and effort into producing the experience.&lt;/p&gt;  &lt;p&gt;I anticipate this exact problem with the application I'm currently developing - there is a varied user base with varied hardware capabilities. OK, none have a turbo button that I'm aware of, but it wouldn't surprise me.&lt;/p&gt;  &lt;p&gt;I decided to put some effort in to come up with a mechanism by which we could tier the experience in our application. That is, a mechanism by which the entire skin of the application can be scaled up or down based on some criteria. Whilst you could achieve this feat by maintaining multiple resource dictionaries - one for each tier in your scale - this results in a lot of duplication of work, since many tiers will include aspects present in other tiers. Another approach might involve some kind of global bindable property that determines the active tier, and then expecting XAML to trigger changes off that property. Again, this would work but would result in a mess of triggers in your templates and styles.&lt;/p&gt;  &lt;p&gt;A far better approach, I think, is to create a custom visual state manager. Doing so can allow us to avoid duplication of work, and can keep our XAML relatively clean. This visual state manager, which I've called &lt;font face="Courier New"&gt;TieredVisualStateManager&lt;/font&gt;, must provide the following:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;a global property tracking the tier that is currently active for the application &lt;/li&gt;    &lt;li&gt;the ability to assign visual states and transitions to specific tiers &lt;/li&gt;    &lt;li&gt;the ability to aggregate visual states and transitions together according to the tier to which they are assigned, and the active tier for the application &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;You can find a sample attached. In this sample, I've re-templated a &lt;font face="Courier New"&gt;CheckBox&lt;/font&gt; control as follows:&lt;a href="http://lh4.ggpht.com/_i_HIkiy_ogI/TYpHLfZsKlI/AAAAAAAABRY/BcqJSe_Gh-c/s1600-h/TieredVSM%5B5%5D.gif"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="TieredVSM" border="0" alt="TieredVSM" align="right" src="http://lh6.ggpht.com/_i_HIkiy_ogI/TYpHL3qU6yI/AAAAAAAABRc/QDRRCmLgG74/TieredVSM_thumb%5B3%5D.gif?imgmax=800" width="225" height="126" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;low tier: very simple graphic, no animations &lt;/li&gt;    &lt;li&gt;medium tier: more appealing graphics, animates checking/unchecking by fading &lt;/li&gt;    &lt;li&gt;high tier: same graphics as medium, same checking/unchecking transitions, but also adds another animation to shake the &lt;font face="Courier New"&gt;CheckBox&lt;/font&gt; up and down (when checking) or left and right (when unchecking). In addition, there is a non-stop glowing animation. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;For the full control template, check out the &lt;a href="http://www.users.on.net/~kentcb/TieredExperience.zip"&gt;attached sample&lt;/a&gt;. However, this outline gives you a taste for how things work:&lt;/p&gt;  &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;local:TieredVisualStateManager x:Key=&amp;quot;TieredVisualStateManager&amp;quot;/&amp;gt;
    
&amp;lt;Style TargetType=&amp;quot;CheckBox&amp;quot;&amp;gt;
    &amp;lt;Setter Property=&amp;quot;Template&amp;quot;&amp;gt;
        &amp;lt;Setter.Value&amp;gt;
            &amp;lt;ControlTemplate TargetType=&amp;quot;CheckBox&amp;quot;&amp;gt;
                &amp;lt;BulletDecorator VisualStateManager.CustomVisualStateManager=&amp;quot;{StaticResource TieredVisualStateManager}&amp;quot;&amp;gt;
                    &amp;lt;local:TieredVisualStateManager.TieredVisualStateGroups&amp;gt;
                        &amp;lt;local:TieredVisualStateGroupCollection&amp;gt;
                            &amp;lt;!--
                            CommonStates
                            --&amp;gt;
                            &amp;lt;local:TieredVisualStateGroup Name=&amp;quot;CommonStates&amp;quot; Tier=&amp;quot;Low&amp;quot;&amp;gt;
                                &amp;lt;local:TieredVisualState Name=&amp;quot;Normal&amp;quot;/&amp;gt;
                            &amp;lt;/local:TieredVisualStateGroup&amp;gt;
                            &amp;lt;local:TieredVisualStateGroup Name=&amp;quot;CommonStates&amp;quot; Tier=&amp;quot;Medium&amp;quot;&amp;gt;
                                &amp;lt;local:TieredVisualState Name=&amp;quot;Normal&amp;quot;&amp;gt;
                                    &amp;lt;!-- fancy brushes applied here --&amp;gt;
                                &amp;lt;/local:TieredVisualState&amp;gt;
                            &amp;lt;/local:TieredVisualStateGroup&amp;gt;
                                
                            &amp;lt;local:TieredVisualStateGroup Name=&amp;quot;CommonStates&amp;quot; Tier=&amp;quot;High&amp;quot;&amp;gt;
                                &amp;lt;local:TieredVisualState Name=&amp;quot;Normal&amp;quot;&amp;gt;
                                    &amp;lt;!-- glowing animation applied here --&amp;gt;
                                &amp;lt;/local:TieredVisualState&amp;gt;
                            &amp;lt;/local:TieredVisualStateGroup&amp;gt;
                            &amp;lt;!--
                            CheckStates
                            --&amp;gt;
                            &amp;lt;local:TieredVisualStateGroup Name=&amp;quot;CheckStates&amp;quot; Tier=&amp;quot;Low&amp;quot;&amp;gt;
                                &amp;lt;local:TieredVisualState Name=&amp;quot;Unchecked&amp;quot;/&amp;gt;
                                &amp;lt;local:TieredVisualState Name=&amp;quot;Checked&amp;quot;&amp;gt;
                                    &amp;lt;!-- display check mark here --&amp;gt;
                                &amp;lt;/local:TieredVisualState&amp;gt;
                            &amp;lt;/local:TieredVisualStateGroup&amp;gt;
                            &amp;lt;local:TieredVisualStateGroup Name=&amp;quot;CheckStates&amp;quot; Tier=&amp;quot;Medium&amp;quot;&amp;gt;
                                &amp;lt;local:TieredVisualStateGroup.Transitions&amp;gt;
                                    &amp;lt;VisualTransition From=&amp;quot;Unchecked&amp;quot; To=&amp;quot;Checked&amp;quot;&amp;gt;
                                        &amp;lt;!-- fade check mark in here --&amp;gt;
                                    &amp;lt;/VisualTransition&amp;gt;
                                    &amp;lt;VisualTransition From=&amp;quot;Checked&amp;quot; To=&amp;quot;Unchecked&amp;quot;&amp;gt;
                                        &amp;lt;!-- fade check mark out here --&amp;gt;
                                    &amp;lt;/VisualTransition&amp;gt;
                                &amp;lt;/local:TieredVisualStateGroup.Transitions&amp;gt;
                            &amp;lt;/local:TieredVisualStateGroup&amp;gt;
                                
                            &amp;lt;local:TieredVisualStateGroup Name=&amp;quot;CheckStates&amp;quot; Tier=&amp;quot;High&amp;quot;&amp;gt;
                                &amp;lt;VisualStateGroup.Transitions&amp;gt;
                                    &amp;lt;VisualTransition From=&amp;quot;Unchecked&amp;quot; To=&amp;quot;Checked&amp;quot;&amp;gt;
                                        &amp;lt;!-- shake the check box up and down here --&amp;gt;
                                    &amp;lt;/VisualTransition&amp;gt;
                                    &amp;lt;VisualTransition From=&amp;quot;Checked&amp;quot; To=&amp;quot;Unchecked&amp;quot;&amp;gt;
                                        &amp;lt;!-- shake the check box left and right here --&amp;gt;
                                    &amp;lt;/VisualTransition&amp;gt;
                                &amp;lt;/VisualStateGroup.Transitions&amp;gt;
                            &amp;lt;/local:TieredVisualStateGroup&amp;gt;
                        &amp;lt;/local:TieredVisualStateGroupCollection&amp;gt;
                    &amp;lt;/local:TieredVisualStateManager.TieredVisualStateGroups&amp;gt;
                    
                    ...
                &amp;lt;/BulletDecorator&amp;gt;
            &amp;lt;/ControlTemplate&amp;gt;
        &amp;lt;/Setter.Value&amp;gt;
    &amp;lt;/Setter&amp;gt;
&amp;lt;/Style&amp;gt;&lt;/pre&gt;
Importantly, notice how I have not repeated anything. For example, the transitions to fade the check mark in and out are defined in the medium tier, but they will also be present if the active tier is high. Similarly, the logic to turn on the check mark is defined in the low tier &lt;font face="Courier New"&gt;CheckStates&lt;/font&gt;, but is inherited by higher tiers. This aggregation is controlled by the &lt;font face="Courier New"&gt;TieredVisualStateManager.AggregateTiers&lt;/font&gt; property, which is &lt;font face="Courier New"&gt;true&lt;/font&gt; by default. Setting it to &lt;font face="Courier New"&gt;false&lt;/font&gt; may be useful in some scenarios, but it does mean you may need to repeat yourself.



&lt;p&gt;When used carefully, the &lt;font face="Courier New"&gt;TieredVisualStateManager&lt;/font&gt; allows you to segregate your application experience so that users with rubbish hardware do not impose on the experience of users with decent hardware. Or it may be that some users have great machines, but just dislike animations, and would rather save that little bit of time by turning them off.&lt;/p&gt;

&lt;p&gt;But the &lt;font face="Courier New"&gt;TieredVisualStateManager&lt;/font&gt; is not just about animations. You can control almost anything through this mechanism: turn effects on for high experiences, turn semi-transparency off for low experiences, remove parts of the visual tree for low experiences, etc. You can even change the tier structure to suit your needs - I just defined &lt;font face="Courier New"&gt;Low&lt;/font&gt;, &lt;font face="Courier New"&gt;Medium&lt;/font&gt;, and &lt;font face="Courier New"&gt;High&lt;/font&gt; because it makes sense for my scenario. Just make sure you define them in order from lowest to highest experience because the internal logic of &lt;font face="Courier New"&gt;TieredVisualStateManager&lt;/font&gt; depends on that order&lt;sup&gt;†&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;In order to actually set the active tier, you might use configuration, an options dialog, diagnostics of the user's machine, or some combination of both. I'm planning on just shipping with a high experience on, and exposing the setting somewhere in an options dialog.&lt;/p&gt;

&lt;p&gt;&amp;quot;What about the Blend experience?&amp;quot;, I hear you ask. Well, I personally don't use Blend the way in which it is purported to be used – I just don't think it works that well. I prefer using Blend for discrete tasks that are normally disconnected from my main solution. If I generate XAML with Blend, I always copy it manually and vet it for verbosity and other little pet hates of mine. Anyway, the fact is that we’ve taken the VSM sufficiently far enough out of its comfort zone that getting it to work in Blend is likely an impossibility. So I didn't put any effort into making the &lt;font face="Courier New"&gt;TieredVisualStateManager&lt;/font&gt; blendable. My plan is to obtain the high experience assets from the UX guy, and to &amp;quot;manually&amp;quot; apply tiering to them.&lt;/p&gt;

&lt;p&gt;It’s an unfortunate story for Silverlight, too. For whatever reason, &lt;font face="Courier New"&gt;VisualStateGroup&lt;/font&gt; and &lt;font face="Courier New"&gt;VisualState&lt;/font&gt; are both &lt;font face="Courier New"&gt;sealed&lt;/font&gt; in Silverlight, which obviously breaks the entire approach to this problem. Perhaps it’s possible to hack around it, but until I need it in Silverlight I don’t plan on putting myself through that pain.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/TieredExperience.zip"&gt;Download Sample&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;†&lt;/sup&gt;Yes, you &lt;em&gt;could &lt;/em&gt;abstract the definition of tiers out into a property on &lt;font face="Courier New"&gt;TieredVisualStateManager&lt;/font&gt;, thus yielding even more flexibility.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-3083908621440038047?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/3083908621440038047/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=3083908621440038047' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3083908621440038047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3083908621440038047'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/03/tieredvisualstatemanager.html' title='TieredVisualStateManager'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_i_HIkiy_ogI/TYpHL3qU6yI/AAAAAAAABRc/QDRRCmLgG74/s72-c/TieredVSM_thumb%5B3%5D.gif?imgmax=800' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-3756916770764348545</id><published>2011-02-26T09:42:00.001Z</published><updated>2011-09-03T17:40:27.248+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>BooleanToVisibilityConverter</title><content type='html'>&lt;p&gt;This is a small thing, really, but how often do you curse WPF's &lt;font face="Courier New"&gt;BooleanToVisibilityConverter&lt;/font&gt; (or Silverlight’s lack thereof) because it doesn't allow you to convert &lt;font face="Courier New"&gt;true &lt;/font&gt;to &lt;font face="Courier New"&gt;Visibility.Collapsed &lt;/font&gt;instead of &lt;font face="Courier New"&gt;Visibility.Visible&lt;/font&gt;? Or what about converting &lt;font face="Courier New"&gt;false &lt;/font&gt;to &lt;font face="Courier New"&gt;Visibility.Hidden &lt;/font&gt;instead of &lt;font face="Courier New"&gt;Visibility.Collapsed&lt;/font&gt;?&lt;/p&gt;  &lt;p&gt;Well, it happens to me in just about every non-trivial project, so I tend to use my own &lt;font face="Courier New"&gt;BooleanToVisibilityConverter &lt;/font&gt;that addresses these requirements. Here it is:&lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;public sealed class BooleanToVisibilityConverter : IValueConverter
{
    public bool IsReversed { get; set; }
    public bool UseHidden { get; set; }
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var val = System.Convert.ToBoolean(value, CultureInfo.InvariantCulture);
        if (this.IsReversed)
        {
            val = !val;
        }
        if (val)
        {
            return Visibility.Visible;
        }
        return this.UseHidden ? Visibility.Hidden : Visibility.Collapsed;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}&lt;/pre&gt;

&lt;p&gt;Now I can convert &lt;font face="Courier New"&gt;true&lt;/font&gt; to &lt;font face="Courier New"&gt;Visibility.Collapsed &lt;/font&gt;like this:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;local:BooleanToVisibilityConverter x:Key=&amp;quot;whatever&amp;quot; IsReversed=&amp;quot;true&amp;quot;/&amp;gt;
...
&amp;lt;Button Visibility=&amp;quot;{Binding IsChecked, ElementName=someCheckBox, Converter={StaticResource whatever}}&amp;quot;/&amp;gt;&lt;/pre&gt;

&lt;p&gt;Or I can convert &lt;font face="Courier New"&gt;false &lt;/font&gt;to &lt;font face="Courier New"&gt;Visibility.Hidden &lt;/font&gt;rather than &lt;font face="Courier New"&gt;Visibility.Collapsed &lt;/font&gt;like this:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;local:BooleanToVisibilityConverter x:Key=&amp;quot;whatever&amp;quot; UseHidden=&amp;quot;true&amp;quot;/&amp;gt;
...
&amp;lt;Button Visibility=&amp;quot;{Binding IsButtonEnabled, Converter={StaticResource whatever}}&amp;quot;/&amp;gt;&lt;/pre&gt;

&lt;p&gt;I can even convert &lt;font face="Courier New"&gt;true &lt;/font&gt;to &lt;font face="Courier New"&gt;Visibility.Hidden &lt;/font&gt;and &lt;font face="Courier New"&gt;false &lt;/font&gt;to &lt;font face="Courier New"&gt;Visibility.Visible &lt;/font&gt;like this:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;local:BooleanToVisibilityConverter x:Key=&amp;quot;whatever&amp;quot; IsReversed=&amp;quot;true&amp;quot; UseHidden=&amp;quot;true&amp;quot;/&amp;gt;
...
&amp;lt;Button Visibility=&amp;quot;{Binding IsButtonDisabled, Converter={StaticResource whatever}}&amp;quot;/&amp;gt;&lt;/pre&gt;

&lt;p&gt;Anyway, that's as much flexibility as I've needed when converting Boolean values to &lt;font face="Courier New"&gt;Visibility &lt;/font&gt;values.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-3756916770764348545?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/3756916770764348545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=3756916770764348545' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3756916770764348545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3756916770764348545'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/02/booleantovisibilityconverter.html' title='BooleanToVisibilityConverter'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-8111856440517392299</id><published>2011-02-19T12:41:00.001Z</published><updated>2011-09-03T17:43:19.522+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>MinimumTimeVisualStateManager</title><content type='html'>&lt;p&gt;A little while back I did some Silverlight work that was very focused on providing a fantastic user experience. As part of this work I developed a control that displayed a loading animation:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/TV-6cs6BibI/AAAAAAAABRI/EkLPQV42mpE/s1600-h/Loading-Animation2.gif"&gt;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" title="Loading Animation" alt="Loading Animation" src="http://lh5.ggpht.com/_i_HIkiy_ogI/TV-6cx-SzPI/AAAAAAAABRM/2bQK3OSWEm0/Loading-Animation_thumb.gif?imgmax=800" width="60" height="60" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I then had views that would display this loading control whilst they're in a &lt;em&gt;Loading&lt;/em&gt; state, and then hide it when they change to a &lt;em&gt;Loaded&lt;/em&gt; state. That all worked fine. The problem was that sometimes - if the load operation completed quickly enough - the loading animation would briefly flash up on the screen and then disappear. Instead of improving the user experience, it was worsening it.&lt;/p&gt;  &lt;p&gt;I could have applied a lengthy duration to the &lt;em&gt;Loading -&amp;gt; Loaded&lt;/em&gt; transition, but that would apply indiscriminately to both fast loads, and slow loads. In other words, if the data happened to load slowly, users would have to wait for the slow load, and then again for the slower transition. Hardly compelling from a UX perspective.&lt;/p&gt;  &lt;p&gt;What I really wanted to do was impose a minimum amount of time to spend in a particular state. That way I could say &amp;quot;the &lt;em&gt;Loading &lt;/em&gt;state must be active for at least 1 second&amp;quot; rather than &amp;quot;the &lt;em&gt;Loading &lt;/em&gt;state will be active for a minimum of 1 second&amp;quot;. If the load operation took half a second, the loading animation would still display for a full second. If the load operation took two seconds, the loading animation would only display for that two second period (plus whatever transition time I specified).&lt;/p&gt;  &lt;p&gt;Fortunately, the Visual State Manager infrastructure is extensible in that it allows custom a &lt;font face="Courier New"&gt;VisualStateManager&lt;/font&gt; instance to be associated with a given element. Such a custom manager might do something as simple as logging visual state changes, or something more complex. In my case, I wanted to enforce a minimum time for any state that desires one, which implies an attached property to set that minimum time and some logic to delay state changes when necessary.&lt;/p&gt;  &lt;p&gt;Enter, the &lt;font face="Courier New"&gt;MinimumTimeVisualStateManager&lt;/font&gt;:&lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MinimumTimeVisualStateManager : VisualStateManager
{
    public static readonly DependencyProperty MinimumTimeProperty = DependencyProperty.RegisterAttached(&amp;quot;MinimumTime&amp;quot;,
        typeof(TimeSpan),
        typeof(MinimumTimeVisualStateManager),
        new PropertyMetadata(TimeSpan.Zero));

    private static readonly DependencyProperty StateChangeMinimumTimeProperty = DependencyProperty.RegisterAttached(&amp;quot;StateChangeMinimumTime&amp;quot;,
        typeof(DateTime),
        typeof(MinimumTimeVisualStateManager),
        new PropertyMetadata(DateTime.MinValue));

    public static TimeSpan GetMinimumTime(VisualState visualState)
    {
        if (visualState == null)
        {
            throw new ArgumentNullException(&amp;quot;visualState&amp;quot;);
        }

        return (TimeSpan)visualState.GetValue(MinimumTimeProperty);
    }

    public static void SetMinimumTime(VisualState visualState, TimeSpan minimumTime)
    {
        if (visualState == null)
        {
            throw new ArgumentNullException(&amp;quot;visualState&amp;quot;);
        }

        visualState.SetValue(MinimumTimeProperty, minimumTime);
    }

    private static DateTime GetStateChangeMinimumTime(DependencyObject dependencyObject)
    {
        Debug.Assert(dependencyObject != null);
        return (DateTime)dependencyObject.GetValue(StateChangeMinimumTimeProperty);
    }

    private static void SetStateChangeMinimumTime(DependencyObject dependencyObject, DateTime stateChangeMinimumTime)
    {
        Debug.Assert(dependencyObject != null);
        dependencyObject.SetValue(StateChangeMinimumTimeProperty, stateChangeMinimumTime);
    }

    protected override bool GoToStateCore(FrameworkElement control, FrameworkElement stateGroupsRoot, string stateName, VisualStateGroup group, VisualState state, bool useTransitions)
    {
        Debug.Assert(group != null &amp;amp;&amp;amp; state != null &amp;amp;&amp;amp; stateGroupsRoot != null, &amp;quot;Group, state, or stateGroupsRoot is null for state name '&amp;quot; + stateName + &amp;quot;'. Be sure you've declared the state in the XAML.&amp;quot;);
        var minimumTimeToStateChange = GetStateChangeMinimumTime(stateGroupsRoot);

        if (DateTime.UtcNow &amp;lt; minimumTimeToStateChange)
        {
            // can't transition yet so reschedule for later
            var dispatcherTimer = new DispatcherTimer();
            dispatcherTimer.Interval = minimumTimeToStateChange - DateTime.UtcNow;
            dispatcherTimer.Tick += delegate
            {
                dispatcherTimer.Stop();
                this.DoStateChange(control, stateGroupsRoot, stateName, group, state, useTransitions);
            };
            dispatcherTimer.Start();

            return false;
        }

        return this.DoStateChange(control, stateGroupsRoot, stateName, group, state, useTransitions);
    }

    private bool DoStateChange(FrameworkElement control, FrameworkElement stateGroupsRoot, string stateName, VisualStateGroup group, VisualState state, bool useTransitions)
    {
        var succeeded = base.GoToStateCore(control, stateGroupsRoot, stateName, group, state, useTransitions);

        if (succeeded)
        {
            SetStateChangeMinimumTime(stateGroupsRoot, DateTime.MinValue);
            var minimumTimeInState = GetMinimumTime(state);

            if (minimumTimeInState &amp;gt; TimeSpan.Zero)
            {
                SetStateChangeMinimumTime(stateGroupsRoot, DateTime.UtcNow + minimumTimeInState);
            }
        }

        return succeeded;
    }
}&lt;/pre&gt;

&lt;p&gt;By way of explanation, the &lt;font face="Courier New"&gt;MinimumTimeVisualStateManager&lt;/font&gt; uses an attached property called &lt;font face="Courier New"&gt;MinimumTime&lt;/font&gt; which can be set on &lt;font face="Courier New"&gt;VisualState &lt;/font&gt;instances. When set, any calls to &lt;font face="Courier New"&gt;GoToStateCore &lt;/font&gt;will ensure that the required minimum time has been surpassed. If so, the state change succeeds as per normal. If not, a &lt;font face="Courier New"&gt;DispatcherTimer &lt;/font&gt;is used to switch states at an appropriate point later in time.&lt;/p&gt;

&lt;p&gt;With this custom visual state manager, we can impose minimum times for states like this:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;Grid x:Name=&amp;quot;root&amp;quot;&amp;gt;
    &amp;lt;VisualStateManager.CustomVisualStateManager&amp;gt;
        &amp;lt;kb:MinimumTimeVisualStateManager/&amp;gt;
    &amp;lt;/VisualStateManager.CustomVisualStateManager&amp;gt;
    
    &amp;lt;VisualStateManager.VisualStateGroups&amp;gt;
        &amp;lt;VisualStateGroup Name=&amp;quot;LoadStates&amp;quot;&amp;gt;
            &amp;lt;VisualState Name=&amp;quot;Loading&amp;quot; kb:MinimumTimeVisualStateManager.MinimumTime=&amp;quot;00:00:01&amp;quot;&amp;gt;
            ...&lt;/pre&gt;

&lt;p&gt;In the above example, we ensure that the &lt;em&gt;Loading &lt;/em&gt;state is active for at least 1 second.&lt;/p&gt;

&lt;p&gt;By the way, this works equally well with Silverlight / WPF. You can download a sample WPF project showing this in action &lt;a href="http://www.users.on.net/~kentcb/MinimumTimeVisualStateManagerExample.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-8111856440517392299?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/8111856440517392299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=8111856440517392299' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/8111856440517392299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/8111856440517392299'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/02/minimumtimevisualstatemanager.html' title='MinimumTimeVisualStateManager'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_i_HIkiy_ogI/TV-6cx-SzPI/AAAAAAAABRM/2bQK3OSWEm0/s72-c/Loading-Animation_thumb.gif?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-1704493095582029075</id><published>2011-01-31T21:04:00.003Z</published><updated>2011-09-03T17:44:40.719+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Build'/><category scheme='http://www.blogger.com/atom/ns#' term='MSBuild'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Analysis'/><title type='text'>Code Analysis without Visual Studio 2010</title><content type='html'>&lt;p&gt;This post provides step-by-step instructions on how to integrate Visual Studio 2010's code analysis into your build. If you've not yet done so, please read my &lt;a href="http://kentb.blogspot.com/2011/01/code-analysis-without-visual-studio.html"&gt;first post&lt;/a&gt; for an overview of what will be achieved. If you'd prefer, you can integrate Visual Studio 2008's code analysis by following the instructions in my &lt;a href="http://kentb.blogspot.com/2011/01/code-analysis-without-visual-studio_31.html"&gt;previous post&lt;/a&gt;. Whilst you will need a machine with Visual Studio 2010 installed, this won't be a requirement for building your project once it's set up correctly. I assume Visual Studio is installed in the default location - adjust paths as necessary.&lt;/p&gt;  &lt;p&gt;Assume we are starting with the following directory structure:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;Project      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Lib       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Src&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 1: Copy Code Analysis Tooling&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Copy the entire contents of &lt;em&gt;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop &lt;/em&gt;to &lt;em&gt;Lib\Code Analysis&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;Copy the entire contents of &lt;em&gt;C:\Program Files\MSBuild\Microsoft\VisualStudio\v10.0\CodeAnalysis &lt;/em&gt;to &lt;em&gt;Lib\Code Analysis&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;Copy the following files to &lt;em&gt;Lib\Code Analysis&lt;/em&gt;:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;em&gt;C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.VisualC\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualC.Dll&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.VisualStudio.CodeAnalysis.Sdk\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.CodeAnalysis.Sdk.dll&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;C:\Program Files\Microsoft Visual Studio 10.0\DIA SDK\bin\msdia100.dll&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;C:\Program Files\Microsoft Visual Studio 10.0\VC\redist\x86\Microsoft.VC100.CRT\msvcp100.dll&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;C:\Program Files\Microsoft Visual Studio 10.0\VC\redist\x86\Microsoft.VC100.CRT\msvcr100.dll&lt;/em&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;Step 2: Create Code Analysis Targets File&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Create a file called &lt;em&gt;CodeAnalysis.targets &lt;/em&gt;and put it in your &lt;em&gt;Src &lt;/em&gt;directory. Here is a starting point for the contents of this file. You should tweak as necessary for your needs:&lt;/p&gt;  &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;Project ToolsVersion=&amp;quot;4.0&amp;quot; xmlns=&amp;quot;http://schemas.microsoft.com/developer/msbuild/2003&amp;quot;&amp;gt;
    &amp;lt;PropertyGroup&amp;gt;
        &amp;lt;!--
        Inject our own target before the code analysis runs.
        --&amp;gt;
        &amp;lt;RunCodeAnalysisDependsOn&amp;gt;
            ConfigureCodeAnalysis;
            $(RunCodeAnalysisDependsOn);
        &amp;lt;/RunCodeAnalysisDependsOn&amp;gt;
        
        &amp;lt;!--
        Ensure code analysis is run
        --&amp;gt;
        &amp;lt;RunCodeAnalysis&amp;gt;True&amp;lt;/RunCodeAnalysis&amp;gt;
        
        &amp;lt;!--
        Set this to false if you don't want all code analysis violations to be treated as errors.
        --&amp;gt;
        &amp;lt;CodeAnalysisTreatWarningsAsErrors&amp;gt;True&amp;lt;/CodeAnalysisTreatWarningsAsErrors&amp;gt;
        &amp;lt;!--
        This should be set to resolve to the Lib directory, which must contain the code analysis tooling.
        --&amp;gt;
        &amp;lt;PathToLib&amp;gt;$(MSBuildProjectDirectory)\..\..\Lib\&amp;lt;/PathToLib&amp;gt;
        &amp;lt;!--
        This should be set to resolve to the directory containing this targets file.
        --&amp;gt;
        &amp;lt;PathToTargets&amp;gt;$(MSBuildProjectDirectory)\..\&amp;lt;/PathToTargets&amp;gt;
        
        &amp;lt;!--
        Setting these properties is required in order for the code analysis targets to execute correctly.
        Without setting these, it will look for the tooling under default installation directories instead
        --&amp;gt;
        &amp;lt;CodeAnalysisTargets&amp;gt;$(PathToLib)\Code Analysis\Microsoft.CodeAnalysis.Targets&amp;lt;/CodeAnalysisTargets&amp;gt;
        &amp;lt;CodeAnalysisPath&amp;gt;$(PathToLib)\Code Analysis&amp;lt;/CodeAnalysisPath&amp;gt;
        &amp;lt;!--
        Assign default code analysis rules
        --&amp;gt;
        &amp;lt;CodeAnalysisRuleSet&amp;gt;$(PathToTargets)CodeAnalysis.Default.ruleset&amp;lt;/CodeAnalysisRuleSet&amp;gt;
    &amp;lt;/PropertyGroup&amp;gt;
    &amp;lt;UsingTask AssemblyFile=&amp;quot;$(PathToLib)\MSBuildSdcTasks\Microsoft.Sdc.Tasks.dll&amp;quot; TaskName=&amp;quot;StringComparison&amp;quot;/&amp;gt;
    &amp;lt;Target Name=&amp;quot;ConfigureCodeAnalysis&amp;quot;&amp;gt;
        &amp;lt;!--
        Assume that any projects with &amp;quot;.Tests&amp;quot; in their names are test projects
        --&amp;gt;
        &amp;lt;StringComparison Comparison=&amp;quot;Contains&amp;quot; Param1=&amp;quot;$(AssemblyName)&amp;quot; Param2=&amp;quot;.Tests&amp;quot;&amp;gt;
            &amp;lt;Output TaskParameter=&amp;quot;Result&amp;quot; PropertyName=&amp;quot;IsTestProject&amp;quot;/&amp;gt;
        &amp;lt;/StringComparison&amp;gt;
        &amp;lt;!--
        Assign different rules for test projects (more relaxed)
        --&amp;gt;
        &amp;lt;CreateProperty Condition=&amp;quot;$(IsTestProject)&amp;quot; Value=&amp;quot;$(PathToTargets)CodeAnalysis.Tests.ruleset&amp;quot;&amp;gt;
            &amp;lt;Output TaskParameter=&amp;quot;Value&amp;quot; PropertyName=&amp;quot;CodeAnalysisRuleSet&amp;quot;/&amp;gt;
        &amp;lt;/CreateProperty&amp;gt;
    &amp;lt;/Target&amp;gt;
&amp;lt;/Project&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Create Rule Sets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create files called &lt;em&gt;CodeAnalysis.Default.ruleset &lt;/em&gt;and &lt;em&gt;CodeAnalysis.Tests.ruleset &lt;/em&gt;in your &lt;em&gt;Src &lt;/em&gt;directory. You can create these files with Visual Studio 2010 by choosing &lt;em&gt;File / New / File / Code Analysis Rule Set&lt;/em&gt;. Alternatively, you can just copy the files from the example in the download.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Enable Code Analysis for Relevant Projects&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For every project that requires code analysis, open the &lt;em&gt;.csproj &lt;/em&gt;file and insert the following before the import of &lt;em&gt;Microsoft.CSharp.targets&lt;/em&gt;:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;Import Project=&amp;quot;..\CodeAnalysis.targets&amp;quot; /&amp;gt;&lt;/pre&gt;

&lt;p&gt;NOTE: it's very important that this be inserted &lt;em&gt;before &lt;/em&gt;the import of &lt;em&gt;Microsoft.CSharp.targets&lt;/em&gt;, not after.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Tweak as Necessary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You may wish to tweak the &lt;em&gt;CodeAnalysis.targets&lt;/em&gt;, &lt;em&gt;CodeAnalysis.Default.ruleset&lt;/em&gt;, and &lt;em&gt;CodeAnalysis.Tests.ruleset &lt;/em&gt;files in order to alter the rules that are enabled, the conditions in which sets of rules are used, etc. As mentioned above, you can use VS2010 to create and edit &lt;em&gt;.ruleset &lt;/em&gt;files.&lt;/p&gt;

&lt;p&gt;Code analysis is now integrated with your projects. Where you're building from is irrelevant - whether it's Visual Studio, the command line, or your build server. In all cases code analysis will execute for your project. You can download an example solution showing all this in action &lt;a href="http://www.users.on.net/~kentcb/code_analysis/CodeAnalysisIntegrationExample.zip"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Troubleshooting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;If you get &lt;em&gt;CA0001 Phx.FatalError&lt;/em&gt;, you likely need to register the &lt;em&gt;msdia100.dll&lt;/em&gt; on the build machine:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;regsvr32 msdia100.dll&lt;/pre&gt;


You could possibly incorporate this into your build script, too, if your build user has sufficient rights.



&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/code_analysis/CodeAnalysisIntegrationExample.zip"&gt;Download Example&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-1704493095582029075?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/1704493095582029075/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=1704493095582029075' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/1704493095582029075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/1704493095582029075'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/01/code-analysis-without-visual-studio_6701.html' title='Code Analysis without Visual Studio 2010'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-6893608536028594318</id><published>2011-01-31T21:04:00.001Z</published><updated>2011-09-03T17:46:07.895+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Build'/><category scheme='http://www.blogger.com/atom/ns#' term='MSBuild'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Analysis'/><title type='text'>Code Analysis without Visual Studio 2008</title><content type='html'>&lt;p&gt;This post provides step-by-step instructions on how to integrate Visual Studio 2008's code analysis into your build. If you've not yet done so, please read my &lt;a href="http://kentb.blogspot.com/2011/01/code-analysis-without-visual-studio.html"&gt;first post&lt;/a&gt; for an overview of what will be achieved. If you'd prefer, you can integrate Visual Studio 2010's code analysis by following the instructions in my &lt;a href="http://kentb.blogspot.com/2011/01/code-analysis-without-visual-studio_6701.html"&gt;next post&lt;/a&gt;. Whilst you will need a machine with Visual Studio 2008 installed, this won't be a requirement for building your project once it's set up correctly. I assume Visual Studio Team Edition is installed in the standard location - adjust paths as necessary.&lt;/p&gt;  &lt;p&gt;Assume we are starting with the following directory structure:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;Project      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Lib       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Src&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 1: Copy Code Analysis Tooling&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Copy the entire contents of &lt;em&gt;C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Static Analysis Tools\FxCop&lt;/em&gt; to &lt;em&gt;Lib\Code Analysis&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;Copy the entire contents of &lt;em&gt;C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\CodeAnalysis &lt;/em&gt;to &lt;em&gt;Lib\Code Analysis&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 2: Create Code Analysis Targets File&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Create a file called &lt;em&gt;CodeAnalysis.targets &lt;/em&gt;and put it in your &lt;em&gt;Src &lt;/em&gt;directory. Here is a starting point for the contents of this file. You should tweak as necessary for your needs:&lt;/p&gt;  &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;

&amp;lt;Project xmlns=&amp;quot;http://schemas.microsoft.com/developer/msbuild/2003&amp;quot;&amp;gt;
    &amp;lt;PropertyGroup&amp;gt;
        &amp;lt;!--
        Inject our own target before the build.
        --&amp;gt;
        &amp;lt;BuildDependsOn&amp;gt;
            ConfigureCodeAnalysis;
            $(BuildDependsOn);
        &amp;lt;/BuildDependsOn&amp;gt;

        &amp;lt;RunCodeAnalysis&amp;gt;True&amp;lt;/RunCodeAnalysis&amp;gt;
        
        &amp;lt;!--
        Set this to false if you don't want all code analysis violations to be treated as errors.
        --&amp;gt;
        &amp;lt;CodeAnalysisTreatWarningsAsErrors&amp;gt;True&amp;lt;/CodeAnalysisTreatWarningsAsErrors&amp;gt;

        &amp;lt;!--
        These are the default code analysis rules that will be applied to any project importing this targets file.
        Note that the lack of $(CodeAnalysisRules) in the definition of CodeAnalysisRules means that individual
        projects cannot override these settings. This is intentional.
        --&amp;gt;
        &amp;lt;DefaultCodeAnalysisRules&amp;gt;+!Microsoft.Design#CA1012;-!Microsoft.Design#CA2210&amp;lt;/DefaultCodeAnalysisRules&amp;gt;

        &amp;lt;!--
        These are the code analysis rules that will be applied to any tests project importing this targets file.
        Test projects are identified by having &amp;quot;.Tests&amp;quot; in their name.
        --&amp;gt;
        &amp;lt;TestsCodeAnalysisRules&amp;gt;+!Microsoft.Design#CA1012;-!Microsoft.Design#CA2210&amp;lt;/TestsCodeAnalysisRules&amp;gt;

        &amp;lt;!--
        This should be set to resolve to the Lib directory, which must contain the code analysis tooling.
        --&amp;gt;
        &amp;lt;PathToLib&amp;gt;$(MSBuildProjectDirectory)\..\..\Lib&amp;lt;/PathToLib&amp;gt;

        &amp;lt;!--
        Setting these properties is required in order for the code analysis targets to execute correctly.
        Without setting these, it will look for the tooling under default installation directories instead, which probably
        won't (and shouldn't) be present on the build server.
        --&amp;gt;
        &amp;lt;CodeAnalysisPath&amp;gt;$(PathToLib)\Code Analysis&amp;lt;/CodeAnalysisPath&amp;gt;

        &amp;lt;CodeAnalysisRules&amp;gt;$(DefaultCodeAnalysisRules)&amp;lt;/CodeAnalysisRules&amp;gt;
    &amp;lt;/PropertyGroup&amp;gt;

    &amp;lt;UsingTask AssemblyFile=&amp;quot;$(PathToLib)\MSBuildSdcTasks\Microsoft.Sdc.Tasks.dll&amp;quot; TaskName=&amp;quot;StringComparison&amp;quot;/&amp;gt;

    &amp;lt;Target Name=&amp;quot;ConfigureCodeAnalysis&amp;quot;&amp;gt;
        &amp;lt;!--
        Assume that any projects with &amp;quot;.Tests&amp;quot; in their names are test projects
        --&amp;gt;
        &amp;lt;StringComparison Comparison=&amp;quot;Contains&amp;quot; Param1=&amp;quot;$(AssemblyName)&amp;quot; Param2=&amp;quot;.Tests&amp;quot;&amp;gt;
            &amp;lt;Output TaskParameter=&amp;quot;Result&amp;quot; PropertyName=&amp;quot;IsTestProject&amp;quot;/&amp;gt;
        &amp;lt;/StringComparison&amp;gt;

        &amp;lt;!--
        Assign different rules for test projects (more relaxed)
        --&amp;gt;
        &amp;lt;CreateProperty Condition=&amp;quot;$(IsTestProject)&amp;quot; Value=&amp;quot;$(TestsCodeAnalysisRules)&amp;quot;&amp;gt;
            &amp;lt;Output TaskParameter=&amp;quot;Value&amp;quot; PropertyName=&amp;quot;CodeAnalysisRules&amp;quot;/&amp;gt;
        &amp;lt;/CreateProperty&amp;gt;
    &amp;lt;/Target&amp;gt;
    
    &amp;lt;Import Project=&amp;quot;..\Lib\Code Analysis\Microsoft.CodeAnalysis.targets&amp;quot; /&amp;gt;
&amp;lt;/Project&amp;gt;&lt;/pre&gt;

&lt;p&gt;NOTE: For the sake of brevity, I have only included a couple of rule definitions in the above snippet. Please download the example solution to obtain a more comprehensive list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Enable Code Analysis for Relevant Projects&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For every project that requires code analysis, open the &lt;em&gt;.csproj&lt;/em&gt; file and insert the following after the import of &lt;em&gt;Microsoft.CSharp.targets&lt;/em&gt;:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;Import Project=&amp;quot;..\CodeAnalysis.targets&amp;quot; /&amp;gt;&lt;/pre&gt;

&lt;p&gt;NOTE: it's very important that this be inserted &lt;em&gt;after &lt;/em&gt;the import of &lt;em&gt;Microsoft.CSharp.targets&lt;/em&gt;, not before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Tweak as Necessary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You may wish to tweak the &lt;em&gt;CodeAnalysis.targets &lt;/em&gt;file in order to alter the rules that are enabled, the conditions in which sets of rules are used, etc. The file is pretty self-explanatory but includes comments as well.&lt;/p&gt;

&lt;p&gt;Code analysis is now integrated with your projects. Where you're building from is irrelevant - whether it's Visual Studio, the command line, or your build server. In all cases code analysis will execute for your project. You can download an example solution showing all this in action &lt;a href="http://www.users.on.net/~kentcb/code_analysis/CodeAnalysisIntegrationExample.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/code_analysis/CodeAnalysisIntegrationExample.zip"&gt;Download Example&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-6893608536028594318?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/6893608536028594318/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=6893608536028594318' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/6893608536028594318'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/6893608536028594318'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/01/code-analysis-without-visual-studio_31.html' title='Code Analysis without Visual Studio 2008'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-3897182683291201356</id><published>2011-01-31T20:52:00.001Z</published><updated>2011-05-11T10:28:30.572+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Build'/><category scheme='http://www.blogger.com/atom/ns#' term='MSBuild'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Analysis'/><title type='text'>Code Analysis without Visual Studio</title><content type='html'>&lt;p&gt;The code analysis tool included in Visual Studio is like a code review, only it's super-fast and doesn't require the twisting of any arms. It checks your .NET binaries for common mistakes in various areas such as design, performance, and security. You can instruct it to treat specific issues as errors so that your project fails to build until problems are rectified. You can even write custom rules and plug them in, or just download some rules provided by &lt;a href="http://www.codeplex.com/site/search?query=fxcop&amp;amp;sortBy=Relevance&amp;amp;devStatus=4&amp;amp;advSearch=true&amp;amp;licenses=|"&gt;the community&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Because it's fast and automated, it is feasible to have code analysis run *every time you build*. This is ideal because identifying these problems early can save you a bunch of time in the long run. Relying on developers running the tooling &amp;quot;when they get a chance&amp;quot; is bound to result in non-conformance to the rules. Violations will compound as time goes by and developers will end up not bothering to run the tooling because of the sheer number of violations present.&lt;/p&gt;  &lt;p&gt;Visual Studio makes it easy to configure code analysis to run for individual projects on every build, but only when building within Visual Studio itself. What happens when you build outside of Visual Studio? What happens when you want the same set of rules configured for your projects to execute during command line builds, or on your continuous integration server?&lt;/p&gt;  &lt;p&gt;The answer is that you need to do a little more work to get this going. There seems to be a fair amount of misinformation out there on this subject. And Microsoft don't seem to be advertising the fact that it's possible, instead preferring to &lt;a href="http://msdn.microsoft.com/en-us/library/ms252483(v=vs.90).aspx"&gt;recommend installing VS&lt;/a&gt; on your build server. Not only is that expensive financially, it's expensive in terms of time taken to set up and maintain your build servers. &lt;/p&gt;  &lt;p&gt;In the following two posts I will provide step-by-step instructions for enabling code analysis within your 2008/2010 solution with the following properties:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The tooling is shared and self-contained. No need for developers to install anything, nor for you to install anything on your build servers. &lt;/li&gt;    &lt;li&gt;The tooling is executed whether building in Visual Studio, the command line, or on your build server. &lt;/li&gt;    &lt;li&gt;All the heavy lifting is encapsulated in a separate targets file, which can simply be imported by projects for which code analysis will be executed. &lt;/li&gt;    &lt;li&gt;The rules executed can be customized based on the assembly under test. For example, you might relax rules for unit test projects. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The &lt;a href="http://kentb.blogspot.com/2011/01/code-analysis-without-visual-studio_31.html"&gt;next post&lt;/a&gt; will describe how to enable code analysis integration for Visual Studio 2008, and &lt;a href="http://kentb.blogspot.com/2011/01/code-analysis-without-visual-studio_6701.html"&gt;the one following that&lt;/a&gt; will cover the same topic for Visual Studio 2010. The steps are slightly different because code analysis underwent some changes in 2010.&lt;/p&gt;  &lt;p&gt;By the way, if you're wondering &amp;quot;why not just download FxCop and integrate that?&amp;quot; then the answer is that FxCop has fewer rules and has a slower engine than code analysis (in 2010 at least). In general, you can consider FxCop the outdated predecessor to code analysis.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-3897182683291201356?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/3897182683291201356/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=3897182683291201356' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3897182683291201356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3897182683291201356'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2011/01/code-analysis-without-visual-studio.html' title='Code Analysis without Visual Studio'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-5292639109457133794</id><published>2010-10-23T15:36:00.001+01:00</published><updated>2011-09-03T17:47:26.333+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MEF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>MEF Filtered Catalog</title><content type='html'>&lt;p&gt;Another piece of MEF code Glenn prompted me to share is a filtered catalog. Here it is in its entirety:&lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;private abstract class FilteredCatalog : ComposablePartCatalog
{
    private readonly ComposablePartCatalog catalogToFilter;

    public FilteredCatalog(ComposablePartCatalog catalogToFilter)
    {
        this.catalogToFilter = catalogToFilter;
    }

    public override IQueryable&amp;lt;ComposablePartDefinition&amp;gt; Parts
    {
        get
        {
            return from part in this.catalogToFilter.Parts
                   from exportDefinition in part.ExportDefinitions
                   where this.IsMatch(part) &amp;amp;&amp;amp; this.IsMatch(exportDefinition)
                   select part;
        }
    }

    public override IEnumerable&amp;lt;Tuple&amp;lt;ComposablePartDefinition, ExportDefinition&amp;gt;&amp;gt; GetExports(ImportDefinition definition)
    {
        return from export in base.GetExports(definition)
               where this.IsMatch(export.Item1) &amp;amp;&amp;amp; this.IsMatch(export.Item2)
               select export;
    }

    protected virtual bool IsMatch(ComposablePartDefinition composablePartDefinition)
    {
        return true;
    }

    protected virtual bool IsMatch(ExportDefinition exportDefinition)
    {
        return true;
    }
}&lt;/pre&gt;

&lt;p&gt;The idea of this abstract class is to make it easy for you to provide filtering logic to pick and choose the parts that are of interest to you. For example, suppose you want a catalog to filter out all services:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;private sealed class NonServiceCatalog : FilteredCatalog
{
    public NonServiceCatalog(ComposablePartCatalog catalogToFilter)
        : base(catalogToFilter)
    {
    }

    protected override bool IsMatch(ExportDefinition exportDefinition)
    {
        // in this case, services are identified via some metadata
        return !exportDefinition.Metadata.ContainsKey(&amp;quot;Mode&amp;quot;);
    }
}&lt;/pre&gt;

&lt;p&gt;It is entirely possible that you could alter &lt;font face="courier new"&gt;FilteredCatalog&lt;/font&gt; such that it is concrete and takes lambdas to filter out parts. However, I prefer the explicit approach because it results in clear code such as:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;rootCatalog.Catalogs.Add(new NonServiceCatalog(catalog));&lt;/pre&gt;

&lt;p&gt;Well, that’s it really. A simple, but effective way of filtering your MEF parts.&lt;/p&gt;





&lt;p&gt;Enjoy!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-5292639109457133794?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/5292639109457133794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=5292639109457133794' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/5292639109457133794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/5292639109457133794'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2010/10/mef-filtered-catalog.html' title='MEF Filtered Catalog'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-1599410949105889245</id><published>2010-09-20T20:21:00.001+01:00</published><updated>2011-09-03T17:48:20.169+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MEF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Failing Early with MEF</title><content type='html'>&lt;p&gt;Several weeks back I had the pleasure of having &lt;a href="http://blogs.msdn.com/b/gblock/"&gt;Glenn Block&lt;/a&gt; over for dinner and discourse. I showed him a project I've been working on, and naturally our conversation centred around my use of MEF and REST. Glenn asked that I do a couple of posts on some of the MEF stuff I had done, so this is the first one.&lt;/p&gt;  &lt;p&gt;One of the things I frequently found happening when using MEF was:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Make a few simple changes &lt;/li&gt;    &lt;li&gt;Run the application &lt;/li&gt;    &lt;li&gt;Get a runtime exception &lt;/li&gt;    &lt;li&gt;Trawl through the hierarchy of exceptions, only to find that it was a simple composition problem &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;More often than not, I had just forgotten to add the appropriate metadata to my types. Since this is something that can be caught early, I felt compelled to do exactly that. However, I also wanted to ensure that this verification did not result in a bloated release deployment. I just wanted something to aid the developer whilst building the application.&lt;/p&gt;  &lt;p&gt;I came up with this:&lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;private static void VerifyComposition()
{
#if DEBUG
    var compositionInfo = new CompositionInfo(rootCatalog, container);
    
    using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture))
    {
        CompositionInfoTextFormatter.Write(compositionInfo, stringWriter);
        var compositionDetail = stringWriter.ToString();
        var errorDetected = compositionDetail.Contains(&amp;quot;[Primary Rejection]&amp;quot;);
        
        if (errorDetected)
        {
            Debugger.Break();
            Debug.Assert(false, &amp;quot;Composition error detected:&amp;quot; + Environment.NewLine + Environment.NewLine + compositionDetail);
        }
    }
#endif
}&lt;/pre&gt;



&lt;p&gt;This uses the &lt;font face="courier new"&gt;CompositionInfo&lt;/font&gt; type, which is included in the &lt;font face="courier new"&gt;Microsoft.ComponentModel.Composition.Diagnostics&lt;/font&gt; assembly. As an aside, I had to &lt;a href="http://mef.codeplex.com/Thread/View.aspx?ThreadId=217035"&gt;build my own&lt;/a&gt; version of this assembly for use with Silverlight since there is none provided out of the box.&lt;/p&gt;

&lt;p&gt;The &lt;font face="courier new"&gt;CompositionInfo&lt;/font&gt; class is used to dump detailed diagnostics of composition into a string. The string is then examined for any issues by searching for &amp;quot;[Primary Rejection]&amp;quot;. If any error is detected, I break into the debugger so the developer can examine the composition dump. This means the workflow above is replaced with this one (same number of steps, but &lt;em&gt;far &lt;/em&gt;less time-consuming):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Make a few simple changes &lt;/li&gt;

  &lt;li&gt;Run the application &lt;/li&gt;

  &lt;li&gt;Debugger breaks letting me know there is a composition problem &lt;/li&gt;

  &lt;li&gt;Examine &lt;font face="courier new"&gt;compositionDetails&lt;/font&gt; in the debugger to get the details of the composition error &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As Glenn pointed out, it may be that you want to tweak the string search according to your particular project. In my case, I want &lt;em&gt;any&lt;/em&gt; composition problem at all to be detected ASAP and to bail out.&lt;/p&gt;

&lt;p&gt;Notice also that this whole affair is wrapped in a &lt;font face="courier new"&gt;#if DEBUG&lt;/font&gt; block. Not only does this prevent this code itself from appearing in a release build, it also prevents the &lt;em&gt;Microsoft.ComponentModel.Composition.Diagnostics &lt;/em&gt;assembly from appearing in your release output (assuming you don't use it elsewhere). This was particularly important for me because it's a Silverlight app, and I wanted the download size to be as small as possible.&lt;/p&gt;

&lt;p&gt;I hope this is of some use.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-1599410949105889245?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/1599410949105889245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=1599410949105889245' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/1599410949105889245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/1599410949105889245'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2010/09/failing-early-with-mef.html' title='Failing Early with MEF'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-1360481184214454198</id><published>2010-07-29T18:30:00.001+01:00</published><updated>2011-09-03T17:49:18.314+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Virtual Paging in Silverlight</title><content type='html'>&lt;p&gt;Silverlight 3 added the &lt;a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.ipagedcollectionview%28VS.95%29.aspx"&gt;&lt;font face="courier new"&gt;IPagedCollectionView&lt;/font&gt;&lt;/a&gt; interface (and concrete implementation &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.data.pagedcollectionview%28VS.95%29.aspx"&gt;&lt;font face="courier new"&gt;PagedCollectionView&lt;/font&gt;&lt;/a&gt;) to support paging through a large result set. The &lt;font face="courier new"&gt;DataPager&lt;/font&gt; control can work with an implementation of &lt;font face="courier new"&gt;IPagedCollectionView&lt;/font&gt; to allow users to page through the large data set by clicking on a page number. It typically looks like this:&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_i_HIkiy_ogI/TFG6xRCqtpI/AAAAAAAABQU/jIaMQK9U5_k/image%5B9%5D.png?imgmax=800" width="260" height="25" /&gt; &lt;/p&gt;  &lt;p&gt;Unfortunately (you knew it was coming), these new types don't offer support for virtual paging. Virtual paging is where you're paging data behind the scenes, but the user isn't explicitly changing pages as they do with the &lt;font face="courier new"&gt;DataPager&lt;/font&gt; control. To them, the data just appears in a big ol' list. As they scroll around the list, data is paged in as necessary. If they move slowly down the list, they would quite possibly never know that data is being paged.&lt;/p&gt;  &lt;p&gt;In the WPF world, it is possible to achieve virtual paging by implementing a collection view that simply retrieves data lazily if and when it is requested. This works because WPF's binding infrastructure will only request items in your source collection if it needs them. Alas, this is not the case in Silverlight. Silverlight will aggressively iterate over all items in your underlying collection regardless of whether they're visible. Thus, if you attempt the WPF trick of lazily loading data on request, you'll end up paging in all the data as soon as the binding kicks in. How annoying.&lt;/p&gt;  &lt;p&gt;I tried a few things to make sure that Silverlight really was that dumb. For example, I tried providing an &lt;font face="courier new"&gt;IList&amp;lt;T&amp;gt;&lt;/font&gt; implementation to see whether it would use the &lt;font face="courier new"&gt;Count&lt;/font&gt; property to avoid the iteration over all the data, figuring perhaps it just needed to know how many items were in the data source in order to calculate the scrollable extent. No dice. I tried a few other things, but all attempts at thwarting Silverlight's aggressive iteration over the data source came up empty-handed.&lt;/p&gt;  &lt;p&gt;But the thing is, I feel really strongly about the usability benefits of virtual paging versus manual paging. The former is far more intuitive and simple to use. I was simply not prepared to forgo this feature in my app, so I pressed on.&lt;/p&gt;  &lt;p&gt;I came up with something of a compromise that goes like this: fine then, Miss Silverlight, if you &lt;em&gt;insist &lt;/em&gt;then you may iterate over my entire source, but I'll just be giving you handles to the data. Those handles won't result in data being loaded - that will only happen when the handle's value is de-referenced. The value will only be de-referenced by bound UI components. And by virtue of UI virtualization, that will only happen when the user scrolls to within the region of that data.&lt;/p&gt;  &lt;p&gt;So what do the handles look like? Initially I experimented with using &lt;font face="courier new"&gt;Lazy&amp;lt;T&amp;gt;&lt;/font&gt; since it's built-in and seemed apropos. It actually worked fine when used synchronously. But loading the data on the UI thread would be really bad, effectively causing the UI to hang when the user scrolls through the data. When I attempted to extend &lt;font face="courier new"&gt;Lazy&amp;lt;T&amp;gt;&lt;/font&gt; and add asynchronous support, things got ugly. Therefore, I scrapped it altogether and instead wrote my own &lt;font face="courier new"&gt;AsyncLazy&amp;lt;T&amp;gt;&lt;/font&gt; class. On the surface, it looks a lot like &lt;font face="courier new"&gt;Lazy&amp;lt;T&amp;gt;&lt;/font&gt;:&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_i_HIkiy_ogI/TFG6x_57F9I/AAAAAAAABQY/ABiP6mEPqkw/image%5B8%5D.png?imgmax=800" width="200" height="243" /&gt; &lt;/p&gt;  &lt;p&gt;But is has some key differences in both behavior and API. Firstly, accessing &lt;font face="courier new"&gt;Value&lt;/font&gt; when the value is yet to be loaded will instantly return &lt;font face="courier new"&gt;null&lt;/font&gt;. But it will also start resolving the value on a background thread, after which the &lt;font face="courier new"&gt;Value&lt;/font&gt; property is updated with the result. The &lt;font face="courier new"&gt;IsValueCreated&lt;/font&gt; property will not return true until the background thread has done its thing and &lt;font face="courier new"&gt;Value&lt;/font&gt; is set. Crucially, &lt;font face="courier new"&gt;AsyncLazy&amp;lt;T&amp;gt;&lt;/font&gt; implements &lt;font face="courier new"&gt;INotifyPropertyChanged&lt;/font&gt; so that any UI elements bound to Value or &lt;font face="courier new"&gt;IsValueCreated&lt;/font&gt; will refresh accordingly as values load.&lt;/p&gt;  &lt;p&gt;I then have a collection view called &lt;font face="courier new"&gt;LazyAsyncCollectionView&amp;lt;T&amp;gt;&lt;/font&gt;. This is an abstraction over the large underlying data set that will be consumed by your view components. You tell it the total number of items in the collection, the size of each page, and give it a lambda with which it can load a specific page. It then takes care of ensuring that pages are loaded as and when they are required. Importantly, it's actually an &lt;font face="courier new"&gt;IEnumerable&amp;lt;AsyncLazy&amp;lt;T&amp;gt;&amp;gt;&lt;/font&gt; rather than &lt;font face="courier new"&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/font&gt;. This means that Silverlight can iterate over the entire view without us needing to load all the data. The data will only be loaded if the &lt;font face="courier new"&gt;Value&lt;/font&gt; property is de-referenced, which is instigated by bindings in the view.&lt;/p&gt;  &lt;p&gt;The view needs to be aware of the fact that it's bound to an &lt;font face="courier new"&gt;AsyncLazy&amp;lt;T&amp;gt;&lt;/font&gt; rather than a &lt;font face="courier new"&gt;T&lt;/font&gt;. Ergo, bindings look like this:&lt;/p&gt;  &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;TextBlock Text=&amp;quot;{Binding Value.Property}&amp;quot;/&amp;gt;&lt;/pre&gt;



&lt;p&gt;where &lt;font face="courier new"&gt;Value&lt;/font&gt; is the aforementioned property on &lt;font face="courier new"&gt;AsyncLazy&amp;lt;T&amp;gt;&lt;/font&gt;. If you have a lot of properties and you don't like dereferencing &lt;font face="courier new"&gt;Value&lt;/font&gt; all the time, you could bind a container's &lt;font face="courier new"&gt;DataContext&lt;/font&gt; like this:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;StackPanel DataContext=&amp;quot;{Binding Value}&amp;quot;&amp;gt;
    &amp;lt;TextBlock Text=&amp;quot;{Binding SomeProperty}&amp;quot;/&amp;gt;
    &amp;lt;TextBlock Text=&amp;quot;{Binding SomeOtherProperty}&amp;quot;/&amp;gt;
&amp;lt;/StackPanel&amp;gt;

 &lt;/pre&gt;



&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="image" border="0" alt="image" align="right" src="http://lh6.ggpht.com/_i_HIkiy_ogI/TFG67nSiBnI/AAAAAAAABQc/EBvXDVOrMwI/image%5B30%5D.png?imgmax=800" width="248" height="275" /&gt; The demo I put together uses all this stuff to display a list of people, the specifics of which you control (being a demo). As pages are being loaded, it displays a simple animation as a placeholder for the data. See the screenshot to the right to see what I mean. &lt;/p&gt;

&lt;p&gt;I mentioned that this whole thing was a compromise. Here are the primary weaknesses of the approach:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the need for an intermediary type is regrettable, but – as explained above – necessary given the current limitations of Silverlight’s binding infrastructure. &lt;/li&gt;

  &lt;li&gt;it is not a true virtualization solution in the sense that it will not unload data. So if the user views the entire result set, all data will be loaded into memory. It is likely possible to alter the code so that it keeps a maximum number of pages in memory and intelligently unloads data where possible. I may well do that when I integrate this into my project. &lt;/li&gt;

  &lt;li&gt;there is still the possibility that a very large number of &lt;font face="courier new"&gt;AsyncLazy&amp;lt;T&amp;gt;&lt;/font&gt; instances will be created, thereby draining memory and CPU cycles. If there is potential for your underlying list to surpass a certain threshold (say, 100,000 entries), it would be prudent to set an upper bound on how many records you will display. After all, is it really that useful to allow users access to all that data? Personally, I will be setting an upper limit of 10,000 and including a message to the effect of &amp;quot;please refine your search&amp;quot; if the server reports more than that number of entries in the data set. &lt;/li&gt;

  &lt;li&gt;as discussed above, the UI needs to bind indirectly to the underlying data via the &lt;font face="courier new"&gt;Value&lt;/font&gt; property on &lt;font face="courier new"&gt;AsyncLazy&amp;lt;T&amp;gt;&lt;/font&gt;. Whilst not ideal, this is a price I am willing to pay in order to get this feature. It's possible you could implement &lt;font face="courier new"&gt;AsyncLazy&amp;lt;T&amp;gt;&lt;/font&gt; as a &lt;font face="courier new"&gt;DynamicObject&lt;/font&gt; that forwards property accesses onto the underlying data item. However, this could result in significant overhead and I haven't experimented with it yet. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's also incomplete. I'm literally blogging about this before I use it in anger, mostly because I'm just so excited I actually got it to work. However, my scenario may be simpler than yours. Here are some things that are missing/incomplete:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;error handling. What happens if the page fails to load? Currently, it just catches the exception and continuously retries until it succeeds. I will definitely be enhancing this, possibly to report errors via the &lt;font face="courier new"&gt;AsyncLazy&amp;lt;T&amp;gt;&lt;/font&gt; class. That way, the UI could respond accordingly, perhaps by displaying a failure message and retry link. &lt;/li&gt;

  &lt;li&gt;selection handling. It so happens that I do not need to support selection. I'm just displaying a large list of non-editable data (search results, if you're wondering). If you need selection support (e.g. if you use this with a &lt;font face="courier new"&gt;ListBox&lt;/font&gt;), then you'll want to implement the pertinent members of &lt;font face="courier new"&gt;ICollectionView&lt;/font&gt;, such as &lt;font face="courier new"&gt;CurrentItem&lt;/font&gt; and &lt;font face="courier new"&gt;CurrentPosition&lt;/font&gt;. I shouldn't imagine it would be too difficult. &lt;/li&gt;

  &lt;li&gt;grouping/sorting/filtering. If these were implemented, they would need to delegate back to the consumer of &lt;font face="courier new"&gt;LazyAsyncCollectionView&amp;lt;T&amp;gt;&lt;/font&gt;. It doesn't make sense for these operations to occur on the client because all data would need to be loaded before it could be grouped, sorted, or filtered. However, if the server-side function supported these mechanisms, then it would make sense to delegate. I think I'll be adding sorting support for my own purposes, since my server-side function does support it. I need to think more about how I'm going to achieve this cleanly. &lt;/li&gt;

  &lt;li&gt;the &lt;font face="courier new"&gt;AsyncLazy&amp;lt;T&amp;gt;&lt;/font&gt; class assumes &lt;font face="courier new"&gt;null&lt;/font&gt; is not a valid value for a data item. This is fine for my purposes, but may not be for you. If necessary, you could add a &lt;font face="courier new"&gt;bool&lt;/font&gt; to track whether the value has been loaded rather than checking for &lt;font face="courier new"&gt;null&lt;/font&gt;. Given the sheer number of &lt;font face="courier new"&gt;AsyncLazy&amp;lt;T&amp;gt;&lt;/font&gt; instances that could be created, I was being careful to minimize the memory footprint of each instance. 1 &lt;font face="courier new"&gt;bool&lt;/font&gt; is insignificant, but 1 million? &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/virtual_paging/VirtualPaging.zip"&gt;Download Project&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-1360481184214454198?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/1360481184214454198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=1360481184214454198' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/1360481184214454198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/1360481184214454198'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2010/07/virtual-paging-in-silverlight.html' title='Virtual Paging in Silverlight'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_i_HIkiy_ogI/TFG6xRCqtpI/AAAAAAAABQU/jIaMQK9U5_k/s72-c/image%5B9%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-7446870742211070942</id><published>2010-07-14T16:44:00.001+01:00</published><updated>2011-09-03T17:49:46.113+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Popup.StaysOpen in Silverlight</title><content type='html'>&lt;p&gt;Continuing on with the theme of restoring some WPF goodness to Silverlight, here is an attached behavior that gives Silverlight’s &lt;font face="courier new"&gt;Popup&lt;/font&gt; control a handy &lt;font face="courier new"&gt;StaysOpen&lt;/font&gt; property. It builds on top of the placement behavior I presented in &lt;a href="http://kentb.blogspot.com/2010/07/silverlight-popup-with-target-placement.html"&gt;my last post&lt;/a&gt;, so I’ve just supplemented the demo I did for that post. Call me lazy.&lt;/p&gt;  &lt;p&gt;Usage looks like this:&lt;/p&gt;  &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;Popup b:Popup.StaysOpen=&amp;quot;False&amp;quot;&amp;gt;
    &amp;lt;TextBlock&amp;gt;Popup contents&amp;lt;/TextBlock&amp;gt;
&amp;lt;/Popup&amp;gt;&lt;/pre&gt;

&lt;p&gt;The only limitations I know of are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The &lt;font face="courier new"&gt;Popup&lt;/font&gt; in question must be closed when you set the &lt;font face="courier new"&gt;StaysOpen&lt;/font&gt; property. If, for example, your &lt;font face="courier new"&gt;Popup&lt;/font&gt; is already open when your application first starts, events won’t hook up correctly. &lt;/li&gt;

  &lt;li&gt;The &lt;font face="courier new"&gt;Popup&lt;/font&gt;’s parent is used to determine whether the user has clicked outside the bounds of the &lt;font face="courier new"&gt;Popup&lt;/font&gt;, and therefore whether the &lt;font face="courier new"&gt;Popup&lt;/font&gt; should be closed. So you should host the &lt;font face="courier new"&gt;Popup&lt;/font&gt; as far up in your visual tree as appropriate, or you could add another dependency property with which you can explicitly specify the parent. I haven’t needed the latter idea yet, so haven’t bothered to add it – maybe I’ll need it later. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/popup_placement/PopupTest.zip"&gt;Download Project&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-7446870742211070942?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/7446870742211070942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=7446870742211070942' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7446870742211070942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7446870742211070942'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2010/07/popupstaysopen-in-silverlight.html' title='Popup.StaysOpen in Silverlight'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-250704434380180366</id><published>2010-07-08T15:53:00.001+01:00</published><updated>2011-09-03T17:50:15.192+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Silverlight Popup with Target Placement</title><content type='html'>&lt;p&gt;Silverlight, eh? It takes everything you knew and turns it into a confusing mish-mash of falsities, half-truths, and – just occasionally - truths. &lt;/p&gt;  &lt;p&gt;One such falsity would be in the placement of &lt;font face="Courier new"&gt;Popup&lt;/font&gt; controls relative to another control. You can just set a &lt;font face="Courier new"&gt;PlacementTarget&lt;/font&gt; like in WPF, right? Nope. All you've got to work with are the &lt;font face="Courier new"&gt;HorizontalOffset&lt;/font&gt; and &lt;font face="Courier new"&gt;VerticalOffset&lt;/font&gt; properties, which specify an offset relative to the &lt;font face="Courier new"&gt;Popup&lt;/font&gt;'s parent. Not much help on their own, really.&lt;/p&gt;  &lt;p&gt;To imbue Silverlight with the WPF goodness that is relative &lt;font face="courier new"&gt;Popup&lt;/font&gt; placement, I've written an attached behavior that positions a &lt;font face="Courier new"&gt;Popup&lt;/font&gt; according to: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;a placement target &lt;/li&gt;    &lt;li&gt;any number of preferred orientations, which state how you’d like the &lt;font face="courier new"&gt;Popup&lt;/font&gt; to be positioned with respect to the placement target &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Usage looks like this: &lt;/p&gt;  &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;Popup b:PopupPlacement.PlacementTarget=&amp;quot;{Binding ElementName=someElement}&amp;quot;&amp;gt;
    &amp;lt;b:Popup.PreferredOrientations&amp;gt;
        &amp;lt;b:PopupOrientationCollection&amp;gt;
            &amp;lt;b:PopupOrientation Placement=&amp;quot;Top&amp;quot; HorizontalAlignment=&amp;quot;Center&amp;quot;/&amp;gt;
            &amp;lt;b:PopupOrientation Placement=&amp;quot;Bottom&amp;quot; HorizontalAlignment=&amp;quot;Center&amp;quot;/&amp;gt;
            &amp;lt;b:PopupOrientation Placement=&amp;quot;Right&amp;quot; VerticalAlignment=&amp;quot;Center&amp;quot;/&amp;gt;
            &amp;lt;b:PopupOrientation Placement=&amp;quot;Right&amp;quot; VerticalAlignment=&amp;quot;TopCenter&amp;quot;/&amp;gt;
        &amp;lt;/b:PopupOrientationCollection&amp;gt;
    &amp;lt;/b:Popup.PreferredOrientations&amp;gt;

    &amp;lt;TextBlock&amp;gt;My popup's contents&amp;lt;/TextBlock&amp;gt;
&amp;lt;/Popup&amp;gt; &lt;/pre&gt;







&lt;p&gt;The above will attempt to position the &lt;font face="Courier new"&gt;Popup&lt;/font&gt; centred above &lt;font face="Courier new"&gt;someElement&lt;/font&gt;. Failing that, it will attempt to place it centered below &lt;font face="Courier new"&gt;someElement&lt;/font&gt;. Failing that, it will attempt to place it with its top centred to the right of &lt;font face="Courier new"&gt;someElement&lt;/font&gt;. Failing that, it will cycle through all other possible permutations of orientations and choose the first one that fits. Failing that, it will resort to just displaying the &lt;font face="Courier new"&gt;Popup&lt;/font&gt; with your most desired orientation, even though the &lt;font face="Courier new"&gt;Popup&lt;/font&gt; doesn’t fit.&lt;/p&gt;



&lt;p&gt;Notice how the horizontal alignment is only relevant if the &lt;font face="Courier new"&gt;Popup&lt;/font&gt; is positioned above or below the placement target, and the vertical alignment is only relevant if the &lt;font face="Courier new"&gt;Popup&lt;/font&gt; is positioned to the left or right of the placement target. Nothing stops you from specifying an irrelevant alignment, but it will be ignored.&lt;/p&gt;

&lt;p&gt;The actual orientation chosen is exposed via the &lt;font face="Courier new"&gt;ActualOrientation&lt;/font&gt; property. You might use this (as I have in my own project – though not in the attached demo) to alter the appearance of the &lt;font face="Courier new"&gt;Popup&lt;/font&gt;’s contents.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/TDXmTcwQHvI/AAAAAAAABQI/Jv3GJWG-tJk/s1600-h/image%5B10%5D.png"&gt;&lt;img style="border-right-width: 0px; margin: 0px 0px 0px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="right" src="http://lh5.ggpht.com/_i_HIkiy_ogI/TDXmTqBhmZI/AAAAAAAABQM/ywU7_ViSqR4/image_thumb%5B8%5D.png?imgmax=800" width="240" height="92" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The attached download includes all the code (it's only 300 lines or so) and a demo (see screenshot). The demo specifies only one preferred orientation, but it puts you in control of what the values are for the orientation. You can resize the space available to the &lt;font face="Courier new"&gt;Popup&lt;/font&gt; by using the grid splitters. The actual orientation chosen for is shown at the bottom. Thus, you can play with different orientations and see how the behavior differs when it has insufficient space in which to fit the &lt;font face="Courier new"&gt;Popup&lt;/font&gt;.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/popup_placement/PopupTest.zip"&gt;Download Project&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-250704434380180366?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/250704434380180366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=250704434380180366' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/250704434380180366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/250704434380180366'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2010/07/silverlight-popup-with-target-placement.html' title='Silverlight Popup with Target Placement'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_i_HIkiy_ogI/TDXmTqBhmZI/AAAAAAAABQM/ywU7_ViSqR4/s72-c/image_thumb%5B8%5D.png?imgmax=800' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-7977585963449700664</id><published>2010-05-24T13:23:00.001+01:00</published><updated>2010-05-24T20:37:49.540+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PS3'/><category scheme='http://www.blogger.com/atom/ns#' term='Misc Technical'/><title type='text'>Adjusting the Aggressiveness of your PS3 Fan</title><content type='html'>&lt;p&gt;Most people know that the PS3 has different speeds at which its fan can spin, resulting in varying levels of noise, from &amp;quot;is that thing even on?&amp;quot; to &amp;quot;omg, the house is taking off!&amp;quot; A lesser known fact is that you can adjust how aggressive the PS3 is with its fan. That is, what temperatures trigger different fan speeds. &lt;/p&gt;  &lt;p&gt;If you're like me then, well, I'm sorry to hear that - but if you are, you use your PS3 more as a media device than as a gaming one. Consequently, you'd much prefer a quieter PS3 so that you can actually &lt;em&gt;hear &lt;/em&gt;Rose whisper “I love you” to Jack (well over an hour after “the only part you want to watch again”, but you’re still watching, aren’t you? &lt;em&gt;Aren’t you!?&lt;/em&gt;). To that end, you may need to ensure your PS3 has a less aggressive cooling policy. &lt;/p&gt;  &lt;p&gt;Or maybe you freak out at the very thought of your PS3's electronic innards being ruthlessly tortured by scorching temperatures, while the fan watches on cruelly, doling out only just enough relief to keep its victim alive. Whether you’re into rubbish movies or personifying inanimate objects, this guide may well be for you.&lt;/p&gt;  &lt;p&gt;First, some caveats:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Your warranty will be voided. &lt;/li&gt;    &lt;li&gt;I won't be held responsible for any damage you do to your PS3, either in the process of making the adjustment, or as a consequence of any adjustments made.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Secondly, here's what you'll need to make the adjustments:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;A star screwdriver or attachment (size T10, whatever that means).&lt;/li&gt;    &lt;li&gt;A phillips head screwdriver or attachment (#2).&lt;/li&gt;    &lt;li&gt;Long fingernails, a flat-head screwdriver, or some other implement to pry the hard drive cover free.&lt;/li&gt;    &lt;li&gt;Patience. It can take a number of iterations to get it just right.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Now then, to the guide . . .&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 1: Remove the top cover &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Remove the warranty sticker from the side of the unit, and then pry out the little rubber plug. After doing so, you'll you'll see the head of a star screw. Use your star screwdriver or attachment to unscrew and remove it. Then slide the top cover out and lift it off.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_i_HIkiy_ogI/S_rVcHaGlgI/AAAAAAAABPc/n5wBqN6t3eQ/s1600-h/Step%201%5B11%5D.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Step 1" border="0" alt="Step 1" src="http://lh6.ggpht.com/_i_HIkiy_ogI/S_rVczuMrdI/AAAAAAAABPg/p2PLf5mb-YE/Step%201_thumb%5B9%5D.jpg?imgmax=800" width="642" height="186" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 2: Remove the inner casing &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Using your phillips head screwdriver or attachment, remove all 7 screws holding the inner casing. One is shorter than the rest, and is marked by an “S” on the casing. With all screws removed, press in the tab at the back of the unit and then lift it off. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_i_HIkiy_ogI/S_rVdrazqtI/AAAAAAAABPk/saydqcWyoMM/s1600-h/Step%202%5B2%5D.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Step 2" border="0" alt="Step 2" src="http://lh5.ggpht.com/_i_HIkiy_ogI/S_rVeb8ZlnI/AAAAAAAABPo/fGr6Y5rw64k/Step%202_thumb.jpg?imgmax=800" width="642" height="180" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 3: Remove the loose component &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This step may not be entirely necessary, but I found it much easier to remove the bottom casing if the component on the left of the unit (when looking at it from the rear) is first removed because it is loose and prone to moving about, especially in the next step. &lt;/p&gt;  &lt;p&gt;To remove it, lift it and unplug the wire from its right hand side. Then carefully lift up the plastic latch holding the flat cord down. It is now detached and can be moved to one side. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_i_HIkiy_ogI/S_rVffNiutI/AAAAAAAABPs/vIXZb6wpHCY/s1600-h/Step%203%5B2%5D.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Step 3" border="0" alt="Step 3" src="http://lh4.ggpht.com/_i_HIkiy_ogI/S_rVf68GMRI/AAAAAAAABPw/xO1Jji5jXQE/Step%203_thumb.jpg?imgmax=800" width="642" height="152" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Note: If you apply too much pressure to the latch it can come apart, so be careful. If it does, don't panic unless you damaged it (at which point, feel free to panic). If it's still undamaged, you can reattach it quite easily once you know how it fits together. Study the form of both parts carefully and you'll see it only goes together one way - the detached part kind of slides into and under the fixed part. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 4: Remove the bottom casing &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Using your phillips head screwdriver or attachment, remove all 7 screws holding the bottom casing. Then remove the hard drive cover using a flat head screwdriver or other appropriate implement. Now, flip the entire unit over, being very careful to hold its innards as you do so - they will fall out if you don't. The bottom casing then lifts straight off. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/S_rVg0st72I/AAAAAAAABP0/k2ZAIahuBKo/s1600-h/Step%204%5B2%5D.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Step 4" border="0" alt="Step 4" src="http://lh5.ggpht.com/_i_HIkiy_ogI/S_rVhVR14QI/AAAAAAAABP4/-pdgco51KWs/Step%204_thumb.jpg?imgmax=800" width="642" height="183" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Step 5: Adjust the fan &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Near the rear of the fan and off to the side is a little plastic casing with a tiny screw on top. It's not a normal screw in the sense that it never stops turning. You can turn it in either direction all day long without it tightening or coming loose. Tightening it (turning it clockwise) will increase the aggressiveness of the fan, whereas loosening it (turning it anti-clockwise) will decrease the aggressiveness of the fan. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_i_HIkiy_ogI/S_rVikDoK3I/AAAAAAAABP8/cCn1lVYLlY0/s1600-h/IMG_1094%5B5%5D.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="IMG_1094" border="0" alt="IMG_1094" src="http://lh4.ggpht.com/_i_HIkiy_ogI/S_rVjCmhJoI/AAAAAAAABQA/xPwfbTZ4e9k/IMG_1094_thumb%5B1%5D.jpg?imgmax=800" width="642" height="443" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;If you keep tightening it you will eventually hear a faint clicking sound on every revolution. That means it's as aggressive as it will go. If you leave it in this position, your PS3 will always run its fan at full speed. Useful if you lack a hair-dryer in your household. &lt;/p&gt;  &lt;p&gt;If you loosen it too much, your PS3 won't turn its fan on at all and will overheat within minutes. Note that the PS3 firmware has a fail-safe such that your machine will display an error message and automatically shut itself down if it becomes too hot (and it will, trust me). &lt;/p&gt;  &lt;p&gt;What you need to find is that happy middle-ground where the fan isn't so aggressive that it is impractical as a media extender, but where it is aggressive enough to keep your unit sufficiently cooled whilst playing &lt;em&gt;Call of Duty Modern Warfare 18&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;For me, it was 5¾ rotations back from the most aggressive setting. Your mileage may vary. Small adjustments really are significant - that final quarter of a turn tweak is what perfected it for me. &lt;/p&gt;  &lt;p&gt;What's frustrating is that there's no easy way to test your adjustments. You have to put everything back together again and give it a whirl. I did this literally ten times before I got it just right. I skipped as many screws as I felt comfortable skipping, but always ensured that all cases were in place. I did this partly for safety reasons, but also because I didn't want extra airflow biasing my tests.&lt;/p&gt;  &lt;p&gt;Putting everything back together is just the reverse procedure to the above steps.&lt;/p&gt;  &lt;p&gt;Enjoy!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-7977585963449700664?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/7977585963449700664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=7977585963449700664' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7977585963449700664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7977585963449700664'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2010/05/adjusting-aggressiveness-of-your-ps3.html' title='Adjusting the Aggressiveness of your PS3 Fan'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_i_HIkiy_ogI/S_rVczuMrdI/AAAAAAAABPg/p2PLf5mb-YE/s72-c/Step%201_thumb%5B9%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-4628253125024137587</id><published>2010-02-08T15:21:00.000Z</published><updated>2011-10-08T18:34:19.501+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MEF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Automatic Configuration Exposure with MEF</title><content type='html'>&lt;p&gt;Glenn Block’s &lt;a href="http://blogs.msdn.com/gblock/archive/2010/01/27/how-do-i-expose-configuration-information-through-mef.aspx"&gt;recent post&lt;/a&gt; on exposing configuration information through MEF intrigued me. What I found myself wondering was whether there was a way to make the exports &lt;em&gt;automatic&lt;/em&gt;. That is, having a newly-added configuration setting in your settings file automatically made available to importers, without any extraneous code to do so.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;A Failed Solution&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;My initial attempt to solve this problem involved the use of a &lt;a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.customtypedescriptor.aspx"&gt;&lt;font face="Courier New"&gt;CustomTypeDescriptor&lt;/font&gt;&lt;/a&gt; with dynamic properties for each configuration value present in the &lt;em&gt;App.config &lt;/em&gt;file. After Glenn helpfully – and gracefully - pointed out typos in my &lt;strike&gt;aspiring constants&lt;/strike&gt; magic strings, I still wasn’t able to get this approach to work.&lt;/p&gt;  &lt;p&gt;It appears as though MEF does not use &lt;a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.getproperties.aspx"&gt;&lt;font face="Courier New"&gt;TypeDescriptor.GetProperties&lt;/font&gt;&lt;/a&gt; to get the properties of a part, so my approach was doomed to failure from the get-go.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;A Successful Solution&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Never mind though, because Glenn also pointed me towards MEF’s &lt;a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.hosting.exportprovider%28VS.100%29.aspx"&gt;&lt;font face="Courier New"&gt;ExportProvider&lt;/font&gt;&lt;/a&gt; abstraction. An export provider can surface exported values to MEF. Thus, we can take values from configuration and ensure they are available to parts that want to import those values.&lt;/p&gt;  &lt;p&gt;The export provider abstraction made things much simpler, but there were some complications:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;I wanted to allow parts to import specific values from the &lt;font face="Courier New"&gt;&amp;lt;appSettings/&amp;gt;&lt;/font&gt; section, or import an entire custom configuration section. &lt;/li&gt;    &lt;li&gt;I wanted parts to be able to declare imports with their intended types, and have strings in the &lt;font face="Courier New"&gt;&amp;lt;appSettings/&amp;gt;&lt;/font&gt; section automatically converted to that type. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The first complication was trivial to work around by comparing the imported contract name against both the app settings and custom configuration sections, in that order. If either is found, it is assumed to be the desired value. This does mean that custom sections with the same name as an app setting will not be resolvable, but that’d be fairly easy to work around by scoping the names (eg. “appSettings.MySetting”). I’ll leave that as an exercise for the name-clash-apprehensive reader.&lt;/p&gt;  &lt;p&gt;The second complication was harder to deal with. MEF doesn’t really give us the type of the property that is being satisfied (UPDATE: yes it does – keep reading below). Suppose, for example, you have a configuration setting to determine the number of allowed failed logons:&lt;/p&gt;  &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;appSettings&amp;gt; 
    &amp;lt;add key=&amp;quot;maxRetryAttempts&amp;quot; value=&amp;quot;3&amp;quot;/&amp;gt; 
&amp;lt;/appSettings&amp;gt;&lt;/pre&gt;

&lt;p&gt;You would typically want to import this as an &lt;font face="Courier New"&gt;Int32&lt;/font&gt;, not as a &lt;font face="Courier New"&gt;String&lt;/font&gt;:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;[Import(&amp;quot;maxRetryAttempts&amp;quot;)] 
public int MaxRetryAttempts 
{ 
    get; 
    set; 
}&lt;/pre&gt;

&lt;p&gt;However, MEF does not do any type conversions for us, and ignores any &lt;font face="Courier New"&gt;TypeConverterAttribute&lt;/font&gt;s applied to the property. Hence, MEF will just throw an exception unless we do type conversion on its behalf.&lt;/p&gt;

&lt;p&gt;To that end, I searched for a way to determine the type of the importing property. Alas, MEF does not appear to surface this information, for reasons that aren’t entirely obvious to me. It doesn’t seem like a bad thing for the export provider to be given some information about the type of the importing property, but maybe I’m missing something.&lt;/p&gt;

&lt;p&gt;Anyways, what I &lt;em&gt;was &lt;/em&gt;able to do is interrogate the import definition to see whether it is satisfied by various different export types (via MEF’s “ExportTypeIdentity” metadata). So I have a dictionary mapping the export type identity values to the logic necessary to convert a string to that type:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;this.appSettingConverters = new Dictionary&amp;lt;string, Func&amp;lt;string, object&amp;gt;&amp;gt;() 
{ 
    { &amp;quot;System.String&amp;quot;, v =&amp;gt; v }, 
    { &amp;quot;System.Int32&amp;quot;,    v =&amp;gt; int.Parse(v, NumberStyles.Any, CultureInfo.InvariantCulture) }, 
    { &amp;quot;System.Double&amp;quot;,   v =&amp;gt; double.Parse(v, NumberStyles.Any, CultureInfo.InvariantCulture) }, 
    { &amp;quot;System.Single&amp;quot;,   v =&amp;gt; float.Parse(v, NumberStyles.Any, CultureInfo.InvariantCulture) }, 
    { &amp;quot;System.DateTime&amp;quot;, v =&amp;gt; DateTime.Parse(v, CultureInfo.InvariantCulture, DateTimeStyles.None) } 
}&lt;/pre&gt;

&lt;p&gt;If there are other types you want to support in your &lt;font face="Courier New"&gt;&amp;lt;appSettings/&amp;gt;&lt;/font&gt; section, then just add the appropriate mapping to this dictionary.&lt;/p&gt;

&lt;p&gt;Note that this assumes that you don’t specify a custom contract type on the setting import, since that will alter the value in the “ExportTypeIdentity” metadata.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE: An Even Better Solution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As pointed out by Glenn in the comments, MEF &lt;em&gt;does &lt;/em&gt;allow import metadata to be retrieved via its &lt;font face="Courier New"&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.reflectionmodel.reflectionmodelservices%28VS.100%29.aspx"&gt;ReflectionModelServices&lt;/a&gt;&lt;/font&gt; APIs. This means we can get rid of the ugly mapping from export type identities to conversion logic and instead lean on &lt;font face="Courier New"&gt;Convert.ChangeType&lt;/font&gt;, passing it the actual CLR type of the importing property. Nice!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Is Used&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At the end of the day, using this infrastructure requires that you first make the export provider known to the container:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;var container = new CompositionContainer(catalog, new ConfigurationExportProvider(new FileConfigurationSource()))&lt;/pre&gt;

&lt;p&gt;Here I’m passing a &lt;font face="Courier New"&gt;FileConfigurationSource&lt;/font&gt; to the &lt;font face="Courier New"&gt;ConfigurationExportProvider&lt;/font&gt;. The &lt;font face="Courier New"&gt;FileConfigurationSource&lt;/font&gt; just uses the &lt;em&gt;App.config &lt;/em&gt;file to get settings. You could conceivably use other sources, too. It’s the &lt;font face="Courier New"&gt;ConfigurationExportProvider&lt;/font&gt; that actually surfaces those configuration settings to MEF.&lt;/p&gt;

&lt;p&gt;Once the container knows about the export provider, you can add your settings to your configuration file. These settings can be simple app settings or custom configuration sections:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;configSections&amp;gt; 
    &amp;lt;section name=&amp;quot;customSection&amp;quot; type=&amp;quot;AutoPropertyExporter.Configuration.CustomConfigurationSection, AutoPropertyExporter&amp;quot;/&amp;gt; 
&amp;lt;/configSections&amp;gt; 

&amp;lt;appSettings&amp;gt; 
    &amp;lt;add key=&amp;quot;Some.Setting&amp;quot; value=&amp;quot;Hello&amp;quot;/&amp;gt; 
    &amp;lt;add key=&amp;quot;Some.Int.Setting&amp;quot; value=&amp;quot;321&amp;quot;/&amp;gt; 
&amp;lt;/appSettings&amp;gt; 

&amp;lt;customSection customProperty=&amp;quot;hello from custom config section&amp;quot;/&amp;gt;&lt;/pre&gt;

&lt;p&gt;Then you just need to import these settings in the consuming parts. As stated above, note that the &lt;font face="Courier New"&gt;Import&lt;/font&gt; attributes do not specify a custom contract type because that will break the export provider.&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;[Import(&amp;quot;Some.Setting&amp;quot;)] 
public string SomeProperty 
{ 
    get; 
    set; 
} 

[Import(&amp;quot;Some.Int.Setting&amp;quot;)] 
public int SomeIntSetting 
{ 
    get; 
    set; 
}  

[Import(&amp;quot;customSection&amp;quot;)] 
public CustomConfigurationSection CustomConfigurationSection 
{ 
    get; 
    set; 
} &lt;/pre&gt;

&lt;p&gt;And that’s it! MEF will take care of the rest.&lt;/p&gt;

&lt;p&gt;There is a running sample application available for download &lt;a href="http://www.users.on.net/~kentcb/autopropertyexporter/AutoPropertyExporter.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE 2&lt;/strong&gt;: I’ve just uploaded a version using VS2010 project format and builds against .NET 4. It also adds support for importing configuration values into importing constructors.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-4628253125024137587?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/4628253125024137587/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=4628253125024137587' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4628253125024137587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4628253125024137587'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2010/02/automatic-configuration-exposure-with.html' title='Automatic Configuration Exposure with MEF'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-4332006527905508919</id><published>2010-01-09T12:33:00.001Z</published><updated>2011-09-03T17:51:49.416+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dependency Injection'/><category scheme='http://www.blogger.com/atom/ns#' term='WCF'/><title type='text'>WCF Channels, Faulting, and Dependency Injection</title><content type='html'>&lt;p&gt;The combination of WCF channel faulting behaviour and dependency injection (DI) makes for an interesting problem.&lt;/p&gt;  &lt;p&gt;Suppose you have a simple service with contract &lt;font face="Courier New"&gt;ISimpleService&lt;/font&gt;. If you’re using DI, you’d like to be able to just declare your dependency as follows:&lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MyClass
{
    private readonly ISimpleService _simpleService;
    
    public MyClass(ISimpleService simpleService)
    {
        _simpleService = simpleService;
    }
}&lt;/pre&gt;

&lt;p&gt;You could then register your WPF channel instance with your DI container against the &lt;font face="Courier New"&gt;ISimpleService&lt;/font&gt; interface. Any dependency on the &lt;font face="Courier New"&gt;ISimpleService&lt;/font&gt; interface will be satisfied with that single WCF channel instance. Generally you want to share the channel throughout your application for performance reasons, but if you don’t want singleton semantics, most any DI container will support a means of returning a new instance of the channel for each resolution against the container.&lt;/p&gt;

&lt;p&gt;However, A WCF channel transitions to a faulted state when a called service throws an exception that isn’t declared as part of its contract, or when a general communication error occurs (like the server goes down momentarily). Once faulted, a channel stays faulted and must be thrown away and recreated.&lt;/p&gt;

&lt;p&gt;Consider what this means for our DI scenario. &lt;font face="Courier New"&gt;MyClass&lt;/font&gt; has a reference directly to a WCF channel. If that channel ever faults, it is unrecoverable. &lt;font face="Courier New"&gt;MyClass&lt;/font&gt; has no obvious means of recreating the channel. And if you’re using singleton semantics, even re-resolving the dependency won’t help you because you’ll get the same faulted channel back.&lt;/p&gt;

&lt;p&gt;You can get around this problem to a certain extent by using a feature such as Unity’s static factory configuration. This allows you to provide logic that is called every time a dependency is resolved. Thus, your logic can cache channels until they fault and then replace them on the fly if and when they do.&lt;/p&gt;

&lt;p&gt;But this relies on the dependency being re-resolved by the client code. This may be acceptable for web applications, where each request lives in its own little world, but it isn’t really a solution for desktop applications. In the above example, it would require &lt;font face="Courier New"&gt;MyClass&lt;/font&gt; to have a reference to its DI container, and to re-resolve the channel each time it requires it. That is error-prone, will spread virally throughout your code base, and forgoes much of the benefit of using DI in the first place.&lt;/p&gt;

&lt;p&gt;So what, then, is the solution?&lt;/p&gt;

&lt;p&gt;I believe the cleanest solution to this problem is to register a proxy onto the channel rather than the channel itself. This proxy is responsible for:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;forwarding messages onto the WCF channel &lt;/li&gt;

  &lt;li&gt;detecting faulted channels and replacing it with a fresh one in as thread-safe manner as possible &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I call it &lt;font face="Courier New"&gt;ChannelResurrectingProxy&amp;lt;T&amp;gt;&lt;/font&gt;, where &lt;font face="Courier New"&gt;T&lt;/font&gt; is the WCF service contract type. It is given a channel factory for &lt;font face="Courier New"&gt;T&lt;/font&gt;. Whenever it receives a message, it will first ensure that it has a channel and that it is not faulted. It will use the channel factory to resurrect the channel where necessary. It then forwards the message onto the channel and returns the result.&lt;/p&gt;

&lt;p&gt;The attached project shows &lt;font face="Courier New"&gt;ChannelResurrectingProxy&amp;lt;T&amp;gt;&lt;/font&gt; in action. It demonstrates what happens when:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A service is called successfully &lt;/li&gt;

  &lt;li&gt;A service that throws an exception declared in its contract is called &lt;/li&gt;

  &lt;li&gt;A service that throws an exception &lt;em&gt;not &lt;/em&gt;declared in its contract is called &lt;/li&gt;

  &lt;li&gt;A service that has out arguments is called &lt;/li&gt;

  &lt;li&gt;All services are called when there is no service host running (ie. the server is down) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these operations take place without re-resolving the dependency from the DI container. Thus, client code is blissfully unaware of the automatic resurrection of the channel. Of course, client code still needs to handle faults; it just doesn’t need to concern itself with the channel lifecycle anymore.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/wcfproxytest/WcfProxyTest.zip"&gt;Download Example Project&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-4332006527905508919?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/4332006527905508919/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=4332006527905508919' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4332006527905508919'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4332006527905508919'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2010/01/wcf-channels-faulting-and-dependency.html' title='WCF Channels, Faulting, and Dependency Injection'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-7225975883716987303</id><published>2009-10-15T20:22:00.001+01:00</published><updated>2009-10-25T10:23:06.516Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='StyleCop'/><title type='text'>Let StyleCop Emancipate you from Source Code Micromanagement</title><content type='html'>&lt;p&gt;My current project has stringent requirements across the board, including that of a highly consistent coding style. This is completely understandable because the client will be taking over maintenance and long-term support sometime after we’ve shipped. As such, they want to feel comfortable that their developers won’t be handed a steaming pile of code poo to polish.&lt;/p&gt;  &lt;p&gt;One of the tools I thought might help us with this problem is &lt;a href="http://code.msdn.microsoft.com/sourceanalysis"&gt;StyleCop&lt;/a&gt;. This tool can analyze your code and flag any issues related to style. My initial suspicion was that StyleCop would annoy the heck out of me in about 10 seconds flat. It would whinge about missing file headers, the number of blank lines between code blocks, and even missing API documentation on private members. And it did do just that.&lt;/p&gt;  &lt;p&gt;But something strange happened after a while: &lt;em&gt;I stopped caring&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;But not in a bad way. I just let the tool make these micro-decisions for me and instead concentrated on more important things like – you know – making the product actually&lt;i&gt; work&lt;/i&gt;. If it told me I needed a blank line between my property getter and setter, I just did it – no questions asked. There was no nagging worry that I would do it differently elsewhere, or that some future developer on the project would, because the tool simply wouldn’t allow you to.&lt;/p&gt;  &lt;p&gt;I’ve been able to get StyleCop integrated to an extent that I am very happy with: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;It runs every time I build, whether it’s on my machine or the build machine. And it does not need to be installed on the developer’s machine (or the build server) &lt;/li&gt;    &lt;li&gt;Any problems StyleCop reports prevent the build from succeeding (i.e. any problems are errors, not warnings) &lt;/li&gt;    &lt;li&gt;Less important projects are excluded from StyleCop altogether, or have relaxed rules (such as for unit test projects, which don’t need API documentation) &lt;/li&gt;    &lt;li&gt;Modifications to StyleCop settings are stored in central settings files and shared across projects. For example, I have a&lt;i&gt; TestProjectSettings.StyleCop&lt;/i&gt; file, which contains settings for unit and integration test projects. If I disable a rule for one test project, it is disabled for all of them &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The intent of this post is&lt;i&gt; not&lt;/i&gt; to help you set StyleCop up with MSBuild. There are &lt;a href="http://blogs.msdn.com/sourceanalysis/pages/source-analysis-msbuild-integration.aspx"&gt;other resources&lt;/a&gt; out there that show you how to do that. I’m more interested in encouraging people to try this tool out. The more people that use it, the more it will be improved. And there is plenty of scope for improvement, as I’ll discuss shortly. If you’ve held off trying out this tool because you had bad experiences with it earlier in its short history, or because you think it has little to offer, perhaps it’s time to rethink.&lt;/p&gt;  &lt;p&gt;So, what are the problems I’ve had using StyleCop? The biggest problem is that it’s lazy. It will happily report style problems to you any day of the week – even Sunday – but it refuses to lift a finger when it comes to rectifying said problems. This can be very irritating at first, but over time I have found myself preemptively and reflexively avoiding StyleCop’s wrath by writing code that conforms more and more to the default rule set.&lt;/p&gt;  &lt;p&gt;The next problem is that of the default rule set. In adopting StyleCop I made it quite clear to my client that doing so implies either accepting the default rules, or spending a significant amount of time writing custom ones (time I don’t have). I can almost guarantee you won’t like all the default rules. Some of them will make you cringe, whilst others may make you downright furious. Of course, you can disable or tweak those rules that really get your goat.&lt;/p&gt;  &lt;p&gt;Finally, StyleCop is particularly frustrating when you’re just wanting to try out a piece of code quickly in your project. There’s no built-in mechanism to demarcate a block of code as temporary and exempt it from style checks. Undef’ing the CODE_ANALYSIS symbol seems to do nothing, and &lt;a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.codeanalysis.suppressmessageattribute.aspx"&gt;SuppressMessage&lt;/a&gt; does not have any wildcard support. Therefore, you either need to move your scratch code into a temporary project, or waste time placating StyleCop.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: As noted by &lt;strong&gt;wekempf &lt;/strong&gt;in the comment below, you can wrap experimental code in a region with “generated code” in its name. This works even when you have the disallow all regions StyleCop rule enabled!&lt;/p&gt;  &lt;p&gt;But for all its warts, I still feel somewhat liberated by StyleCop. No longer do I worry about whether I have the correct spacing, line breaks, or bracket placement in my source. I let the tool worry about that for me. And I feel as though spending the extra brain cycles on more important concerns is a win for both myself and my client.&lt;/p&gt;  &lt;p&gt;Note that I am the only .NET developer on my project at the moment, so I can’t really comment on how well this would work with a team. I can’t really see it being an issue if everyone agrees that no rules should be disabled or suppressed without due justification and discussion. Some developers are sure to balk at the idea of having to conform to a particular style, but that’s only because it’s not &lt;em&gt;their &lt;/em&gt;style. Heck, I was hesitant at first to make dramatic changes to my style (I prefer tabs, for example), but I quickly adjusted when I saw the benefits of the tool.&lt;/p&gt;  &lt;p&gt;So next time you’re embarking on a new project, consider integrating StyleCop right from the get-go. The short term may be painful, but I think you’ll appreciate the decision in the long term.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-7225975883716987303?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/7225975883716987303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=7225975883716987303' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7225975883716987303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7225975883716987303'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/10/let-stylecop-emancipate-you-from-source.html' title='Let StyleCop Emancipate you from Source Code Micromanagement'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-5654787098736770454</id><published>2009-09-22T10:39:00.001+01:00</published><updated>2009-09-22T10:39:15.109+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc Technical'/><title type='text'>VM Keyboard Rate Limited by Host</title><content type='html'>&lt;p&gt;Seems obvious when you think about it, but I thought it worth pointing out all the same. If you’re trying to up the ante on your keyboard settings inside a VM, be aware that their effect will be limited by the the keyboard settings on the host.&lt;/p&gt;  &lt;p&gt;So if you set your VM’s keyboard to repeat crazy fast:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_i_HIkiy_ogI/SribMC8VBoI/AAAAAAAABPI/7QMal0PNhXo/s1600-h/image%5B6%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_i_HIkiy_ogI/SribMUP4PQI/AAAAAAAABPM/twlMlhQUO18/image_thumb%5B2%5D.png?imgmax=800" width="216" height="240" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;But your host is set to crazy slow:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_i_HIkiy_ogI/SribM8s4bPI/AAAAAAAABPQ/hcHY4vsbJ88/s1600-h/image%5B7%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SribNEEiGPI/AAAAAAAABPU/rA7jUtiPWD4/image_thumb%5B3%5D.png?imgmax=800" width="216" height="240" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The effective result in your VM is crazy slow. That’s because the host will only be passing on keyboard events to the VM in crazy slow mode, so the keyboard settings in the VM are essentially moot.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-5654787098736770454?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/5654787098736770454/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=5654787098736770454' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/5654787098736770454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/5654787098736770454'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/09/vm-keyboard-rate-limited-by-host.html' title='VM Keyboard Rate Limited by Host'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_i_HIkiy_ogI/SribMUP4PQI/AAAAAAAABPM/twlMlhQUO18/s72-c/image_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-635632578768346138</id><published>2009-08-24T18:00:00.001+01:00</published><updated>2009-09-04T21:28:26.523+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SSH'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu, SSH, and Remote Support</title><content type='html'>&lt;p&gt;Having a job in IT can sometimes be a curse. To mere mortals, the whole world of &lt;em&gt;things that go beep &lt;/em&gt;is lumped together in a box labelled “voodoo”. Any issue even &lt;em&gt;remotely&lt;/em&gt; related to computers can be directed your way. The typical geek probably finds themselves having to deal with document formatting problems, faulty mobile phones, and friends who can’t remember their email address. Can you imagine asking a cardiologist to examine your foot? No? Me neither.&lt;/p&gt;  &lt;p&gt;My Mum – who runs Ubuntu – asked me for some help with her webcam the other day and I felt compelled to help her because:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;She’s my Mum. &lt;/li&gt;    &lt;li&gt;I got her onto Ubuntu in the first place and set it all up for her. &lt;/li&gt;    &lt;li&gt;She’s my Mum. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The problem is that she lives in the sleepy town of Adelaide whilst I live in London, some 16,000 kilometres away.&lt;/p&gt;  &lt;p&gt;Now, if we were using Windows I’d have used a service like &lt;a href="http://www.crossloop.com/"&gt;CrossLoop&lt;/a&gt; to remote onto her machine&lt;sup&gt;†&lt;/sup&gt;. I’ve used it in the past to help my sister with her machine, and it was very good. Basically, CrossLoop works by acting as a middle-man between the two machines, so instead of connecting directly to each other, they connect to a CrossLoop server. This helps get around all the issues with firewalls and ports that the average computer user shouldn’t have to understand. Of course, it implies that you trust CrossLoop not to snoop on any data exchanged between the machines.&lt;/p&gt;  &lt;p&gt;Alas, CrossLoop is Windows and Mac only&lt;sup&gt;‡&lt;/sup&gt; – no love for the world of Linux. Moreover, I &lt;a href="http://ubuntuforums.org/showthread.php?t=1172096"&gt;couldn’t find&lt;/a&gt; an alternative service &lt;em&gt;at all &lt;/em&gt;for Ubuntu. To that end, I set about looking for something that would allow me to help my Mum. My requirements were simple enough:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Must be secure. &lt;/li&gt;    &lt;li&gt;Must require no effort by my Mum except running a script. And when I say “no effort” I really mean that. Requiring &lt;em&gt;any&lt;/em&gt; kind of router configuration or software configuration, for example, would be a deal-breaker. If I asked my Mum to open a port, she’d tell me it was too early in the day to drink (yes, even if it was 9PM). &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;After some reading and testing on my end, I settled on a solution using the most excellent &lt;a href="http://en.wikipedia.org/wiki/Secure_Shell"&gt;SSH protocol&lt;/a&gt;. The key for me was SSH’s ability to set up a reverse connection. This allowed &lt;em&gt;me &lt;/em&gt;to set up the SSH server and configure &lt;em&gt;my &lt;/em&gt;router to do the port forwarding. Then I provided my Mum with a script that simply:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Kills any resident VNC session. &lt;/li&gt;    &lt;li&gt;Starts up a new VNC session. &lt;/li&gt;    &lt;li&gt;Sets up a reverse SSH tunnel to my machine, forwarding traffic on my port 9999 to the relevant VNC port on her side (5901). Having your own DNS entry helps here, but isn’t strictly required if you don’t mind validating the port in the script every time you use it (again, not an option for my Mum). &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Once she runs that script, I can run a VNC client and connect to port 9999 on my local machine. By virtue of the SSH tunnel, I’m actually connecting to port 5901 on her machine, which is the VNC session. Magic!&lt;/p&gt;  &lt;p&gt;The whole setup can be depicted graphically as follows (click to enlarge):&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_i_HIkiy_ogI/SpLHRN1KSEI/AAAAAAAABPA/krzY_m-HiVY/s1600-h/image9.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_i_HIkiy_ogI/SpLHSBza2HI/AAAAAAAABPE/670vg-7L9LA/image_thumb5.png?imgmax=800" width="400" height="253" /&gt;&lt;/a&gt;So there you have it. When my Mum has issues, she double-clicks a file on her desktop, enters a password (although you can use keys instead), and I can then connect to her desktop and hopefully sort it out. Now you, too, can provide remote support for your Mum’s Ubuntu installation.&lt;/p&gt;  &lt;p&gt;Now all I have to do is fix her foot – I mean, webcam!&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;sup&gt;†&lt;/sup&gt; OK, OK, Linux haters – perhaps if my Mum was using Windows the webcam would be working just fine and this whole post would be moot. Instead I might be posting about how I had to rescue her machine from the clutches of malware.&lt;/p&gt;  &lt;p&gt;&lt;sup&gt;‡&lt;/sup&gt; OK, OK, Linux and Windows haters – perhaps if my Mum was using a Mac I’d be able to use CrossLoop and this whole post would be moot. Instead I might be posting about how I had to loan my Mum some money so she could buy milk and bread.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Addendum&lt;/strong&gt;: I had an issue with the keyboard mappings with VNC. Basically, I would type “abcd” and would get “asdf” on the remote machine. Turns out this is a known issue and I found &lt;a href="http://blog.yclian.com/2007/12/3-solutions-to-gnomevnc-keyboard.html"&gt;this blog post&lt;/a&gt; on the subject. It was a comment by &lt;strong&gt;dcatdemon&lt;/strong&gt; on that post that helped me:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Edit your $HOME/.vnc/xstartup&lt;/li&gt;    &lt;li&gt;Put the line &amp;quot;export XKL_XMODMAP_DISABLE=1&amp;quot; before your gnome-session&lt;/li&gt;    &lt;li&gt;Restart vncserver&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;strong&gt;Note to Self&lt;/strong&gt;: regarding the actual webcam, I had to recompile and reinstall the driver. When I set up Ubuntu originally for Mum I had to manually compile the driver because there was no built-in support for her webcam. Presumably, the latest kernel update had somehow broken backwards compatibility and the driver was no longer successfully being loaded. So I removed the old &lt;em&gt;.ko &lt;/em&gt;driver binary from &lt;em&gt;/lib/modules/kernel*/drivers/media/video/usbvideo/ &lt;/em&gt;and then recompiled and reinstalled according to &lt;a href="https://groups.google.com/group/microdia/web/testing-microdia-driver-draft?pli=1"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;I suppose this may happen after future kernel updates, too. Lucky I have that support script all set up!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-635632578768346138?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/635632578768346138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=635632578768346138' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/635632578768346138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/635632578768346138'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/08/ubuntu-ssh-and-remote-support.html' title='Ubuntu, SSH, and Remote Support'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_i_HIkiy_ogI/SpLHSBza2HI/AAAAAAAABPE/670vg-7L9LA/s72-c/image_thumb5.png?imgmax=800' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-2995375361654066874</id><published>2009-06-20T13:48:00.001+01:00</published><updated>2011-09-03T17:52:22.065+01:00</updated><title type='text'>Truss V1.0.0.0 Released</title><content type='html'>&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_i_HIkiy_ogI/Sjzagjsi0hI/AAAAAAAABO4/smtpi-051xM/s1600-h/Abstract%20Bindings.Single%20Source%20Bindings%5B8%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="Abstract Bindings.Single Source Bindings" border="0" alt="Abstract Bindings.Single Source Bindings" align="right" src="http://lh3.ggpht.com/_i_HIkiy_ogI/Sjzaih_giNI/AAAAAAAABO8/UvEpjAOCKws/Abstract%20Bindings.Single%20Source%20Bindings_thumb%5B6%5D.png?imgmax=800" width="250" height="327" /&gt;&lt;/a&gt; I have just released version 1 of &lt;a href="http://truss.codeplex.com"&gt;Truss&lt;/a&gt;, a binding framework for POCOs. Truss allows you to bind together arbitrary .NET objects regardless of your choice of UI platform, or in the absence of a UI altogether.&lt;/p&gt;  &lt;p&gt;Amongst its features, it provides support for bindings that use “magic strings” to specify property paths, as well as lambda expressions for compile-time checked bindings. Here’s a very simple example to whet your appetite:&lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;var parent = new Person();
var child = new Person();
var bm = new BindingManager();

//bind the parent's savings to the child's inheritance
bm.Bindings.Add(new TypedBinding&amp;lt;Person, Person&amp;gt;(parent, p =&amp;gt; p.Savings, child, c =&amp;gt; c.Inheritance));&lt;/pre&gt;





&lt;p&gt;There are a number of scenarios I intend Truss to address, both now and with future enhancements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Keeping related view models POCOs in sync with each other &lt;/li&gt;

  &lt;li&gt;Keeping related business objects in sync with each other &lt;/li&gt;

  &lt;li&gt;Provide a strong alternative to the limited binding support in Winforms, thus facilitating clean MVVM development in Winforms &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can download Truss source, binaries, and comprehensive documentation from &lt;a href="http://truss.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=29039#ReleaseFiles"&gt;here&lt;/a&gt;. Please direct any feedback my way.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-2995375361654066874?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/2995375361654066874/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=2995375361654066874' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2995375361654066874'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2995375361654066874'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/06/truss-v1000-released.html' title='Truss V1.0.0.0 Released'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_i_HIkiy_ogI/Sjzaih_giNI/AAAAAAAABO8/UvEpjAOCKws/s72-c/Abstract%20Bindings.Single%20Source%20Bindings_thumb%5B6%5D.png?imgmax=800' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-1668449819251952012</id><published>2009-06-11T19:32:00.001+01:00</published><updated>2009-06-11T19:32:21.690+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Search and Highlight Text in an Arbitrary Visual Tree</title><content type='html'>&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/SearchVisualTree/SearchVisualTree.zip"&gt;Download Example Project&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_i_HIkiy_ogI/SjFNqn4YxrI/AAAAAAAABOo/XR_tO1gzPcM/s1600-h/image11.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="image" border="0" alt="image" align="right" src="http://lh5.ggpht.com/_i_HIkiy_ogI/SjFNrCTD7hI/AAAAAAAABOs/gnraDDrNxLk/image_thumb6.png?imgmax=800" width="149" height="73" /&gt;&lt;/a&gt; A while back I answered &lt;a href="http://stackoverflow.com/questions/798579/wpf-listbox-highlight-part-of-listboxitem-element"&gt;this question&lt;/a&gt; on stackoverflow and have been meaning to elaborate on my answer ever since with a more comprehensive blog post. The question is about how to highlight some text in the UI when the user enters some search text. I thought I’d extend the concept into a clean, generic solution as far as I could and share it here.&lt;/p&gt;  &lt;p&gt;My requirements are pretty straightforward:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Provide a search box in which the user can enter some text. &lt;/li&gt;    &lt;li&gt;Highlight all matching text in the window, regardless of where it appears in the visual tree. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_i_HIkiy_ogI/SjFNsQgnHRI/AAAAAAAABOw/alcFOWI95QA/s1600-h/image12.png"&gt;&lt;img style="border-right-width: 0px; margin: 0px 10px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="left" src="http://lh5.ggpht.com/_i_HIkiy_ogI/SjFNs3-M4KI/AAAAAAAABO0/-AsZvDxnk7s/image_thumb7.png?imgmax=800" width="240" height="142" /&gt;&lt;/a&gt;I was able to pull this off to an extent I am satisfied with. See the screenshot to the left. The user can enter some text in the top-right search text box, and then hit enter (or click the magnifying glass). Then all matching text is highlighted anywhere in the visual tree.&lt;/p&gt;  &lt;p&gt;After an initial approach that relied on reflection in order to highlight content elements (&lt;em&gt;ugh!&lt;/em&gt;), &lt;a href="http://marlongrech.wordpress.com/"&gt;Marlon Grech&lt;/a&gt; kindly passed my question about how to do this more cleanly onto &lt;a href="http://drwpf.com/blog/"&gt;Dr. WPF&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/jaimer/"&gt;Jamie Rodriguez&lt;/a&gt;, who pointed me in the right direction (thanks guys!).&lt;/p&gt;  &lt;p&gt;The basic approach I ended up using is:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Traverse the visual tree recursively, looking for &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.icontenthost.aspx"&gt;&lt;font face="Courier New"&gt;IContentHost&lt;/font&gt;&lt;/a&gt;s and &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.documentviewerbase.aspx"&gt;&lt;font face="Courier New"&gt;DocumentViewerBase&lt;/font&gt;&lt;/a&gt;s. For &lt;font face="Courier New"&gt;DocumentViewerBase&lt;/font&gt;s, extract the &lt;font face="Courier New"&gt;IContentHost&lt;/font&gt;s corresponding to each page. &lt;/li&gt;    &lt;li&gt;For each &lt;font face="Courier New"&gt;IContentHost&lt;/font&gt;, search through its &lt;font face="Courier New"&gt;HostedElements&lt;/font&gt; collection to find any &lt;font face="Courier New"&gt;Run&lt;/font&gt;s. &lt;/li&gt;    &lt;li&gt;For each &lt;font face="Courier New"&gt;Run&lt;/font&gt;, inspect its &lt;font face="Courier New"&gt;Text&lt;/font&gt; to determine whether the search term matches. &lt;/li&gt;    &lt;li&gt;If the search term matches, use some &lt;font face="Courier New"&gt;TextPointer&lt;/font&gt; trickery to determine the bounding rectangle of the text. &lt;/li&gt;    &lt;li&gt;Use a &lt;font face="Courier New"&gt;Canvas&lt;/font&gt; to lay out all semi-transparent rectangles on top of the application window, thus highlighting the matches. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;There are a few problems that I’m aware of:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;If the matching text spans multiple lines, the bounding rectangle isn’t correctly calculated. You could use &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.icontenthost.getrectangles.aspx"&gt;&lt;font face="Courier New"&gt;IContentHost.GetRectangles&lt;/font&gt;&lt;/a&gt; to calculate all bounding rectangles correctly, but I just haven’t bothered to do so for the purposes of this post.&lt;/li&gt;    &lt;li&gt;It doesn’t work for all content element hosts, such as &lt;font face="Courier New"&gt;FlowDocumentScrollViewer&lt;/font&gt;, because they don’t inherit from &lt;font face="Courier New"&gt;DocumentViewerBase&lt;/font&gt;. I suspect it’s probably not too hard to add support for them, but again I haven’t bothered to do so for this example. &lt;/li&gt;    &lt;li&gt;It’s quite slow when the search term is short and frequently matched (as an example, try searching for “a”). &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;So the approach isn’t perfect, but this was an experiment more than anything else. I think a real application would want search support more intrinsic rather than relying on a generic mechanism like this. That said, there are bound to be some practical applications of the general technique used here.&lt;/p&gt;  &lt;p&gt;PS. You may have noticed a lack of TMNT-related material in my sample this post. Unfortunately, my Windows Home Server recently died, which has prevented me from continuing to watch the series and has let my obsession waver somewhat. A replacement server is due next week, so expect more green reptile-based content soon!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/SearchVisualTree/SearchVisualTree.zip"&gt;Download Example Project&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-1668449819251952012?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/1668449819251952012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=1668449819251952012' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/1668449819251952012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/1668449819251952012'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/06/search-and-highlight-text-in-arbitrary.html' title='Search and Highlight Text in an Arbitrary Visual Tree'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_i_HIkiy_ogI/SjFNrCTD7hI/AAAAAAAABOs/gnraDDrNxLk/s72-c/image_thumb6.png?imgmax=800' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-6927358009100472048</id><published>2009-05-07T13:03:00.001+01:00</published><updated>2009-05-07T13:03:19.269+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVVM'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><title type='text'>MVVM Infrastructure: ActiveAwareCommand</title><content type='html'>&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/mvvm/ActiveAwareCommandExample.zip"&gt;Download Example Project&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;This post is part of a short series I am doing on MVVM infrastructure. In this series, I will share some thinking and code that has helped to produce cleaner, simpler MVVM code in my applications.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Related posts:&lt;/em&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/03/view-models-pocos-versus.html"&gt;POCOs versus DependencyObjects&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/04/mvvm-infrastructure-viewmodel.html"&gt;ViewModel&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/04/mvvm-infrastructure-delegatecommand.html"&gt;DelegateCommand&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;strong&gt;ActiveAwareCommand&lt;/strong&gt;&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;In my last post I discussed the &lt;code&gt;DelegateCommand&lt;/code&gt;, which allows you to associate a WPF command directly with logic in your view model. In this post I am going to talk about the &lt;code&gt;ActiveAwareCommand&lt;/code&gt;, which does exactly the same thing, but it enables you to widen the scope from which the command is used.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 0px 10px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="" border="0" alt="" align="right" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SgLNodLvEOI/AAAAAAAABOQ/ps-wFfgRQkI/image6.png?imgmax=800" width="300" height="139" /&gt; The &lt;code&gt;DelegateCommand&lt;/code&gt; works great when the command source (such as a &lt;code&gt;Button&lt;/code&gt;) has a one-to-one relationship with the view model. For example, recall the customers example from the previous post (see right). The &lt;strong&gt;Add&lt;/strong&gt; and &lt;strong&gt;Delete &lt;/strong&gt;buttons are defined in the &lt;code&gt;CustomersView&lt;/code&gt;. Since the &lt;code&gt;CustomersView&lt;/code&gt; has a one-to-one relationship with the &lt;code&gt;CustomersViewModel&lt;/code&gt;, the &lt;code&gt;Button&lt;/code&gt;s also have a one-to-one relationship.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 10px 10px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="" border="0" alt="" align="left" src="http://lh5.ggpht.com/_i_HIkiy_ogI/SgLNo7NfzEI/AAAAAAAABOU/oEiNDuVi5-g/image159.png?imgmax=800" width="126" height="137" /&gt; But suppose we wanted to change the &lt;strong&gt;Add &lt;/strong&gt;and &lt;strong&gt;Delete &lt;/strong&gt;buttons to &lt;code&gt;MenuItem&lt;/code&gt;s, and re-use those &lt;code&gt;MenuItem&lt;/code&gt;s across multiple views. Essentially, we want to change the one-to-one relationship between command source and view model to a one-to-many relationship. With &lt;code&gt;DelegateCommand&lt;/code&gt;s, the &lt;code&gt;MenuItem&lt;/code&gt;s would be intimately tied to a particular view. Therefore, the best effort would result with multiple &lt;strong&gt;Add &lt;/strong&gt;and &lt;strong&gt;Delete &lt;/strong&gt;entries in the &lt;code&gt;Menu&lt;/code&gt; – one for each view that supports adding and deleting items. We’d have to distinguish the &lt;code&gt;MenuItem&lt;/code&gt;s with unique headers, such as “Add Customer” and “Add Order”. Obviously, that would result in a horrible user experience.&lt;/p&gt;  &lt;p&gt;&lt;code&gt;ActiveAwareCommand&lt;/code&gt; provides a solution to this little dilemma by maintaining a list of &lt;em&gt;potential targets &lt;/em&gt;for the command, and only interacting with the &lt;em&gt;active target &lt;/em&gt;(if there is one). Each potential target is an implementation of &lt;code&gt;IActiveAware&lt;/code&gt;&lt;sup&gt;†&lt;/sup&gt;, and the &lt;code&gt;ActiveAwareCommand&lt;/code&gt; uses the &lt;code&gt;IsActiveChanged&lt;/code&gt; event on this interface to track the active target. The &lt;code&gt;ActiveAwareCommand&lt;/code&gt; belongs to a single view model but maps to any number of command sources, thus fulfilling the one-to-many relationship we seek.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/SgLNvg7arNI/AAAAAAAABOY/utgPtkteqDo/s1600-h/ClassDiagram15.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="" border="0" alt="" src="http://lh4.ggpht.com/_i_HIkiy_ogI/SgLN2Gs9qDI/AAAAAAAABOc/2dt8MoSGd24/ClassDiagram1_thumb3.png?imgmax=800" width="538" height="480" /&gt;&lt;/a&gt; The &lt;code&gt;IActiveAware&lt;/code&gt; interface gives you the freedom to use whatever logic you like to determine whether the potential target is active. However, it is likely that you will most often use focus to activate an item. To that end, the &lt;code&gt;FocusActiveAwareAdapter&lt;/code&gt; wraps a &lt;code&gt;FrameworkElement&lt;/code&gt; and gives you an implementation of &lt;code&gt;IActiveAware&lt;/code&gt; whose &lt;code&gt;IsActive&lt;/code&gt; property is changed to &lt;code&gt;true&lt;/code&gt; when the &lt;code&gt;FrameworkElement&lt;/code&gt; gets focus, and &lt;code&gt;false&lt;/code&gt; when it loses focus.&lt;/p&gt;  &lt;p&gt;Generally speaking, the steps for using an &lt;code&gt;ActiveAwareCommand&lt;/code&gt; are:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Construct an instance of &lt;code&gt;ActiveAwareCommand&lt;/code&gt;, usually as a &lt;code&gt;public static readonly &lt;/code&gt;member of a view model class. &lt;/li&gt;    &lt;li&gt;In your view model class, expose a property that allows the view to provide an &lt;code&gt;IActiveAware&lt;/code&gt; implementation to monitor. This property should register and unregister the &lt;code&gt;IActiveAware&lt;/code&gt; implementation with the &lt;code&gt;ActiveAwareCommand&lt;/code&gt;. &lt;/li&gt;    &lt;li&gt;In your view, pass an implementation of &lt;code&gt;IActiveAware&lt;/code&gt; to the view model when the view loads. Usually this will involve constructing an instance of &lt;code&gt;FocusActiveAwareAdapter&lt;/code&gt; that wraps the view. &lt;/li&gt;    &lt;li&gt;Bind to the &lt;code&gt;ActiveAwareCommand&lt;/code&gt; from a shared piece of screen real estate, such as the main menu or application ribbon. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_i_HIkiy_ogI/SgLN8A3KGkI/AAAAAAAABOg/bagBrP8FbBc/s1600-h/image18.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="" border="0" alt="" align="right" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SgLOBTfDPFI/AAAAAAAABOk/jia-fcNMflM/image_thumb3.png?imgmax=800" width="400" height="223" /&gt;&lt;/a&gt; To demonstrate the use of &lt;code&gt;ActiveAwareCommand&lt;/code&gt;, I put together another TMNT-related sample project (I’m totally scoping the 2003 era series, like, start to finish at the moment, dudes). In it, the user is able to edit the details of any number of characters in separate tabs. Each character can be saved independently of the others from both the main menu and a tool bar button. Since an &lt;code&gt;ActiveAwareCommand&lt;/code&gt; is used for the save functionality, the command is correctly routed to the active tab without any need for manual redirection by the views.&lt;/p&gt;  &lt;p&gt;I may have gone a bit overboard with the sample project. I initially started out writing a simpler example, but I found myself wanting something a bit more substantial and real-world. Anyway, feel free to ignore most of the code and just concentrate on the parts pertinent to this post.&lt;/p&gt;  &lt;p&gt;I think that about wraps up my series on MVVM infrastructure – for now at least. I hope it has been of some use. I’ve got some other things in mind that I want to blog about, but I’m on leave in Australia through to June. Until then…&lt;/p&gt;  &lt;p&gt;† Prism has a similar interface, but it is used for different purposes. Same goes for Prism’s &lt;code&gt;CompositeCommand&lt;/code&gt;, which is used to broadcast a command to multiple handlers, as opposed to unicasting only to the active handler.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/mvvm/ActiveAwareCommandExample.zip"&gt;Download Example Project&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-6927358009100472048?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/6927358009100472048/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=6927358009100472048' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/6927358009100472048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/6927358009100472048'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/05/mvvm-infrastructure-activeawarecommand.html' title='MVVM Infrastructure: ActiveAwareCommand'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_i_HIkiy_ogI/SgLNodLvEOI/AAAAAAAABOQ/ps-wFfgRQkI/s72-c/image6.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-201017256634925030</id><published>2009-04-19T17:40:00.001+01:00</published><updated>2011-09-03T17:53:20.557+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVVM'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><title type='text'>MVVM Infrastructure: DelegateCommand</title><content type='html'>&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/mvvm/Command.cs"&gt;Download Command.cs&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://www.users.on.net/~kentcb/mvvm/DelegateCommand.cs"&gt;Download DelegateCommand.cs&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://www.users.on.net/~kentcb/mvvm/DelegateCommandExample.zip"&gt;Download DelegateCommandExample.zip&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;This post is part of a short series I am doing on MVVM infrastructure. In this series, I will share some thinking and code that has helped to produce cleaner, simpler MVVM code in my applications.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Related posts:&lt;/em&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/03/view-models-pocos-versus.html"&gt;POCOs versus DependencyObjects&lt;/a&gt;&lt;/em&gt;&lt;strong&gt; &lt;/strong&gt;&lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/04/mvvm-infrastructure-viewmodel.html"&gt;ViewModel&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;em&gt;DelegateCommand&lt;/em&gt;&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/05/mvvm-infrastructure-activeawarecommand.html"&gt;ActiveAwareCommand&lt;/a&gt;&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;In my &lt;a href="http://kentb.blogspot.com/2009/04/mvvm-infrastructure-viewmodel.html"&gt;last post&lt;/a&gt; I discussed my &lt;code&gt;ViewModel&lt;/code&gt; base class. In this post I’m going to start showing you some infrastructure around commanding. &lt;/p&gt;  &lt;p&gt;WPF's commanding support enables you to hook up UI interactions with code without tightly coupling the two. User actions are abstracted into implementations of WPF’s &lt;code&gt;ICommand&lt;/code&gt; interface, which are then associated with controls that implement &lt;code&gt;ICommandSource&lt;/code&gt;. Essentially, it's a layer of indirection. The controls in the UI aren't intimately aware of the command logic they are connected with, and the command logic isn't aware of the controls it will be associated with. &lt;/p&gt;  &lt;p&gt;When starting out with WPF commanding, you will soon come across the &lt;code&gt;RoutedCommand&lt;/code&gt; class. This particular command is yet another layer of indirection, in that its execution logic involves finding something to execute and calling that! Starting with the focused element, it searches up the visual tree for an element that has a matching &lt;code&gt;CommandBinding&lt;/code&gt; in its &lt;code&gt;CommandBindings&lt;/code&gt; collection. If the &lt;code&gt;RoutedCommand&lt;/code&gt; finds a matching &lt;code&gt;CommandBinding&lt;/code&gt;, it executes that &lt;code&gt;CommandBinding&lt;/code&gt;'s &lt;code&gt;Executed&lt;/code&gt; delegate. &lt;/p&gt;  &lt;p&gt;Routed commands work great in certain scenarios, and are prevalent in WPF. Indeed, the only concrete &lt;code&gt;ICommand&lt;/code&gt; implementation that comes with WPF is the &lt;code&gt;RoutedCommand&lt;/code&gt; (and its subclass, &lt;code&gt;RoutedUICommand&lt;/code&gt;). Unfortunately, this has caused WPF commanding to become somewhat synonymous with &lt;code&gt;RoutedCommand&lt;/code&gt;s, which is not at all accurate. &lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 0px 10px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="right" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SetUFTBCK9I/AAAAAAAABNc/0vBZRySz49I/image%5B14%5D.png?imgmax=800" width="300" height="138" /&gt; The thing is, routed commands are &lt;em&gt;not always &lt;/em&gt;a great fit for MVVM development. Typically the logic for your command execution belongs in the view model. For example, suppose you have a &lt;code&gt;CustomersViewModel&lt;/code&gt; that maintains a list of &lt;code&gt;CustomerViewModel&lt;/code&gt;s, and you want to expose a command that deletes the selected customer. The logic for that command &lt;em&gt;should &lt;/em&gt;reside in the &lt;code&gt;CustomersViewModel&lt;/code&gt;, since it knows best what to do when a deletion is requested. &lt;/p&gt;  &lt;p&gt;If you were to use a &lt;code&gt;RoutedCommand&lt;/code&gt;, you would then need a &lt;code&gt;CommandBinding&lt;/code&gt; somewhere in the UI in order to connect a visual element to the &lt;code&gt;DeleteCustomerCommand&lt;/code&gt;. In our example, we would likely stick a &lt;code&gt;CommandBinding&lt;/code&gt; in the &lt;code&gt;CustomersView&lt;/code&gt; and associate it with the deletion command and methods on the view model. Without the &lt;code&gt;CommandBinding&lt;/code&gt;, the &lt;code&gt;RoutedCommand&lt;/code&gt; won't find a handler for the command and the &lt;strong&gt;Delete &lt;/strong&gt;button will be forever disabled.&lt;/p&gt;  &lt;p&gt;Using routed commands with MVVM ends up being messy, sub-optimal, and requires the view be more tightly coupled to the view model. And in some scenarios, it’s not even possible (I’ll discuss such a scenario in my next post). But the good news is, we don't have to use routed commands. All we need is an appropriate implementation of &lt;font face="Courier New"&gt;ICommand&lt;/font&gt; – one that is more conducive to MVVM development. &lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 10px 10px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="left" src="http://lh6.ggpht.com/_i_HIkiy_ogI/SetUF9trxzI/AAAAAAAABNg/_jguWWEHySw/image%5B7%5D.png?imgmax=800" width="300" height="139" /&gt;If you think about it, all we &lt;em&gt;really &lt;/em&gt;want to do is have a command that – when executed – invokes a method in our view model. And when the command is queried for its executable status, it executes a different method in the view model. To continue our customer example, that command might be associated with a &lt;code&gt;Button&lt;/code&gt; in our &lt;code&gt;CustomersView&lt;/code&gt;. The availability of the command would be dependent upon the user first selecting a customer (you can't delete a customer if you don't know which customer to delete). The execution of the command might execute a &lt;code&gt;DeleteCustomer&lt;/code&gt; method on the &lt;code&gt;CustomersViewModel&lt;/code&gt;. &lt;/p&gt;  &lt;p&gt;Sound simple? That's because it is! Far simpler than attempting to use routed commands for this scenario.&lt;/p&gt;  &lt;p&gt;The command implementation I use is called &lt;code&gt;DelegateCommand&lt;/code&gt;, simply because it invokes delegates when executing and querying executable status. Other people have different names for this type of command, the most common of which seems to be &lt;code&gt;RelayCommand&lt;/code&gt;. That's fine - call it what you will. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://prism.codeplex.com/"&gt;Prism&lt;/a&gt; has a &lt;code&gt;DelegateCommand&lt;/code&gt; too, which is almost exactly the same as this one. However, the reason I have my own is simply because we don't use Prism in our project&lt;sup&gt;†&lt;/sup&gt;, and it would be a large overhead to pull it in just for the sake of a class or two. Besides, if you're doing a non-composite WPF app, Prism may not be a good fit. &lt;/p&gt;  &lt;p&gt;To create a &lt;code&gt;DelegateCommand&lt;/code&gt;, you simply give it one or two delegates to use. If you give it only one delegate, the command is assumed to be always available. That is, &lt;code&gt;ICommand.CanExecute()&lt;/code&gt; will always return &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;  &lt;p&gt;In our &lt;code&gt;CustomersViewModel&lt;/code&gt;, we create the &lt;code&gt;DelegateCommand&lt;/code&gt; as follows:&lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;_deleteCustomerCommand = new DelegateCommand(DeleteCustomer, CanDeleteCustomer);&lt;/pre&gt;









&lt;p&gt;We then expose the command from a property in our view model:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public ICommand DeleteCustomersCommand
{
    get { return _deleteCustomerCommand; }
}&lt;/pre&gt;









&lt;p&gt;And bind to it in the view:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;Button Command=&amp;quot;{Binding DeleteCustomersCommand}&amp;quot;&amp;gt;Delete&amp;lt;/Button&amp;gt;&lt;/pre&gt;









&lt;p&gt;It’s as simple as that. The delegates supplied to the &lt;code&gt;DelegateCommand&lt;/code&gt; will be invoked at the appropriate times and our &lt;strong&gt;Delete&lt;/strong&gt; button will only be enabled when a customer is selected. You can see all this and more in the download.&lt;/p&gt;

&lt;p&gt;Incidentally, &lt;code&gt;DelegateCommand&lt;/code&gt; inherits from a base &lt;code&gt;Command&lt;/code&gt; class. That’s just to keep the code DRY with respect to other command classes I have, such as the &lt;code&gt;ActiveAwareCommand&lt;/code&gt;. I’ll talk about that one in the next post.&lt;/p&gt;

&lt;p&gt;† The application in question was built before Prism shipped, elsewise we would be.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/mvvm/Command.cs"&gt;Download Command.cs&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://www.users.on.net/~kentcb/mvvm/DelegateCommand.cs"&gt;Download DelegateCommand.cs&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://www.users.on.net/~kentcb/mvvm/DelegateCommandExample.zip"&gt;Download DelegateCommandExample.zip&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-201017256634925030?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/201017256634925030/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=201017256634925030' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/201017256634925030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/201017256634925030'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/04/mvvm-infrastructure-delegatecommand.html' title='MVVM Infrastructure: DelegateCommand'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_i_HIkiy_ogI/SetUFTBCK9I/AAAAAAAABNc/0vBZRySz49I/s72-c/image%5B14%5D.png?imgmax=800' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-4724298644881153391</id><published>2009-04-07T18:41:00.001+01:00</published><updated>2011-09-03T17:54:01.215+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVVM'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><title type='text'>MVVM Infrastructure: ViewModel</title><content type='html'>&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/mvvm/ViewModel.cs"&gt;Download ViewModel.cs&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;This post is part of a short series I am doing on MVVM infrastructure. In this series, I will share some thinking and code that has helped to produce cleaner, simpler MVVM code in my applications.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Related posts:&lt;/em&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/03/view-models-pocos-versus.html"&gt;POCOs versus DependencyObjects&lt;/a&gt;&lt;/em&gt;&lt;strong&gt; &lt;/strong&gt;&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;&lt;em&gt;ViewModel&lt;/em&gt; &lt;/strong&gt;&lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/04/mvvm-infrastructure-delegatecommand.html"&gt;DelegateCommand&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/05/mvvm-infrastructure-activeawarecommand.html"&gt;ActiveAwareCommand&lt;/a&gt;&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;In this post, I'm going to show you a base class for view models I have imaginatively named &lt;font face="courier new"&gt;ViewModel&lt;/font&gt;. This is by no means a complex class, but it's a fantastic time-saver when doing MVVM. &lt;/p&gt;  &lt;p&gt;I had a few concerns at the fore-front of my mind when designing this class. Firstly, I wanted it to be extremely simple to use. When inheriting from it, I didn't want to have to worry about implementing specific constructors in my subclass or providing implementations of abstract members. It should be brain-dead simple to extend the &lt;font face="courier new"&gt;ViewModel&lt;/font&gt; class. &lt;/p&gt;  &lt;p&gt;Secondly, I was concerned about having too many members on the base class. Doing so could make it harder to discern those members of interest when working on subclasses. Essentially, I didn't want a lot of noise in the APIs, because that adds just that little bit of friction that can accumulate into a ball of pain. &lt;/p&gt;  &lt;p&gt;Thirdly, I didn't want the class to impose too much on subclasses. They should be granted as much freedom of implementation as possible whilst still providing them with value. For example, subclasses should have the ability to provide their own implementation of equality. &lt;/p&gt;  &lt;p&gt;Finally, I wanted to minimize the performance impact of leveraging this base class. I didn't want consumers to have to choose between a good view model design and performance. Ideally, they could have their cake and eat it, too. Of course, I'm not saying you can design your view models as fine-grained as you like without a thought for performance. I'm just saying I wanted to mitigate the risk. &lt;/p&gt;  &lt;p&gt;As you'll see from the code, I think it's fair to say these goals have all been satisfied. The attached file includes API documentation, but the small size of the class means I can include it here, sans documentation: &lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;public abstract class ViewModel : INotifyPropertyChanged 
{ 
    private readonly Dispatcher _dispatcher; 
    
    protected ViewModel() 
    { 
        if (Application.Current != null) 
        { 
            _dispatcher = Application.Current.Dispatcher; 
        } 
        else 
        { 
            //this is useful for unit tests where there is no application running 
            _dispatcher = Dispatcher.CurrentDispatcher; 
        } 

    } 

    [field:NonSerialized]
    public event PropertyChangedEventHandler PropertyChanged; 

    protected Dispatcher Dispatcher 
    { 
        get { return _dispatcher; } 
    } 

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
        PropertyChanged.Raise(this, e); 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 
    } 
} &lt;/pre&gt;





&lt;p&gt;There are really only two responsibilities taken on by this class: &lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Implement &lt;font face="courier new"&gt;INotifyPropertyChanged&lt;/font&gt;. &lt;/li&gt;

  &lt;li&gt;Provide access to a &lt;font face="courier new"&gt;Dispatcher&lt;/font&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;font face="courier new"&gt;OnPropertyChanged&lt;/font&gt; overrides allow subclasses to easily raise the &lt;font face="courier new"&gt;PropertyChanged&lt;/font&gt; event (incidentally, that call to &lt;font face="courier new"&gt;PropertyChanged.Raise&lt;/font&gt; is by virtue of my library &lt;a href="http://thehelpertrinity.codeplex.com/"&gt;The Helper Trinity&lt;/a&gt;). For example, a subclass might do so like this: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public string Name 
{ 
    get { return _name; } 
    set 
    { 
        if (_name != value) 
        { 
            _name = value; 
            OnPropertyChanged(&amp;quot;Name&amp;quot;); 
        } 
    } 
}&lt;/pre&gt;





&lt;p&gt;The &lt;font face="courier new"&gt;Dispatcher&lt;/font&gt; property allows subclasses to gain access to the current &lt;font face="courier new"&gt;Dispatcher&lt;/font&gt;, which makes it much easier to perform work to a background thread and then synchronize the results with the UI. Importantly, a new &lt;font face="courier new"&gt;Dispatcher&lt;/font&gt; for the current thread is assigned if no WPF application is running. This makes unit testing much easier as there will always be a &lt;font face="courier new"&gt;Dispatcher&lt;/font&gt; available via this property.&lt;/p&gt;

&lt;p&gt;So that's it really. Nothing much to it, and that's the way I like it. Next up in this series, we'll start looking at the infrastructure I have around commanding.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/mvvm/ViewModel.cs"&gt;Download ViewModel.cs&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-4724298644881153391?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/4724298644881153391/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=4724298644881153391' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4724298644881153391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4724298644881153391'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/04/mvvm-infrastructure-viewmodel.html' title='MVVM Infrastructure: ViewModel'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-876169085408890146</id><published>2009-04-03T21:03:00.001+01:00</published><updated>2009-04-04T11:53:37.113+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVP'/><title type='text'>MVP</title><content type='html'>&lt;p&gt;&lt;a href="https://mvp.support.microsoft.com/profile=0824A9A8-07F3-4B7D-9A48-8F6FF2EA6AA1"&gt;&lt;img title="MVPLogo" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 0px 0px 10px; border-right-width: 0px" height="157" alt="MVPLogo" src="http://lh4.ggpht.com/_i_HIkiy_ogI/SdZsDJxp2OI/AAAAAAAABNY/mwKrM7Lc3Vc/MVPLogo_thumb%5B2%5D.gif?imgmax=800" width="100" align="right" border="0" /&gt;&lt;/a&gt; I'm very pleased to announce that I have been awarded MVP for 2009 in &lt;em&gt;Client Application Development&lt;/em&gt;. This is the first MVP award I have received. Being notified on the 1st of April was a little disconcerting, but against all odds it was not a hoax.&lt;/p&gt;  &lt;p&gt;I look forward to continued involvement in the developer community over the coming years.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-876169085408890146?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/876169085408890146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=876169085408890146' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/876169085408890146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/876169085408890146'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/04/mvp.html' title='MVP'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_i_HIkiy_ogI/SdZsDJxp2OI/AAAAAAAABNY/mwKrM7Lc3Vc/s72-c/MVPLogo_thumb%5B2%5D.gif?imgmax=800' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-2190959590874409090</id><published>2009-04-02T20:40:00.001+01:00</published><updated>2009-04-02T20:40:27.726+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVVM'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='LOB'/><title type='text'>WPF for LOB</title><content type='html'>&lt;p&gt;Here’s some great news for anyone doing WPF in LOB applications. &lt;a href="http://karlshifflett.wordpress.com/"&gt;Karl Shifflet&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/jaimer/"&gt;Jaime Rodriguez&lt;/a&gt; are travelling the World (well OK, &lt;em&gt;parts &lt;/em&gt;of the World) to present a training course on WPF and MVVM in real-world applications.&lt;/p&gt;  &lt;p&gt;This is an awesome opportunity and I wish I could be there. As luck would have it, I will be on leave in Australia precisely when they’re presenting in the UK&amp;#160; :(&lt;/p&gt;  &lt;p&gt;Oh, and did I mention it’s &lt;strong&gt;FREE&lt;/strong&gt;!?&lt;/p&gt;  &lt;p&gt;Get the full details &lt;a href="http://blogs.msdn.com/jaimer/archive/2009/04/01/announcing-the-using-wpf-to-build-lob-applications-training-tour.aspx"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-2190959590874409090?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/2190959590874409090/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=2190959590874409090' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2190959590874409090'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2190959590874409090'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/04/wpf-for-lob.html' title='WPF for LOB'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-4779420413066866600</id><published>2009-03-26T18:40:00.001Z</published><updated>2011-09-03T17:55:29.656+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVVM'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>View Models: POCOs versus DependencyObjects</title><content type='html'>&lt;p&gt;&lt;em&gt;This post is part of a short series I am doing on MVVM infrastructure. In this series, I will share some thinking and code that has helped to produce cleaner, simpler MVVM code in my applications.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Related posts:&lt;/em&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;&lt;em&gt;POCOs versus DependencyObjects&lt;/em&gt; &lt;/strong&gt;&lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/04/mvvm-infrastructure-viewmodel.html"&gt;ViewModel&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/04/mvvm-infrastructure-delegatecommand.html"&gt;DelegateCommand&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;&lt;a href="http://kentb.blogspot.com/2009/05/mvvm-infrastructure-activeawarecommand.html"&gt;ActiveAwareCommand&lt;/a&gt;&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;If you're leveraging the MVVM pattern in your WPF/Silverlight development, you will quickly be faced with a decision regarding the implementation of your view models: should they be &lt;code&gt;DependencyObject&lt;/code&gt;s, or POCOs (Plain Old CLR Objects)? I've seen and worked with applications that use both of these options.&lt;/p&gt;  &lt;p&gt;This post is intended to discuss these two options. It certainly won't touch on all issues and nuances of either option, but it will cover the main ones I have found to be problematic. I will order them from least significant to most. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Performance &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I was hesitant to even mention this one because I haven't done any measuring and haven’t found it to be a problem at all. There is a theoretical performance benefit to using &lt;code&gt;DependencyObject&lt;/code&gt;s for view models for a couple of reasons:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Lower memory usage. &lt;/li&gt;    &lt;li&gt;Faster binding performance. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The former assumes your view models have a lot of properties, and that those properties tend to take on their default values. WPF’s dependency object system is optimised for this case. Your typical WPF control has dozens or even hundreds of properties, most of which are set to their default value. Extra memory is only used by properties if they take on a non-default value. If your view models follow a similar pattern then you might get some memory usage benefits from using &lt;code&gt;DependencyObject&lt;/code&gt;s. But I'd also be questioning your view model design if that was the case. &lt;/p&gt;  &lt;p&gt;The second point is more relevant, since the primary job of a view model is to provide properties to which the view can bind. WPF's binding system supposedly performs better when binding to &lt;code&gt;DependencyObject&lt;/code&gt;s than to CLR properties. That may well be the case (again, I haven't measured), but the difference must be negligible because this has not proven to be a problem for me thus far. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Property Change Notification in a Related View Model &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Suppose you have two view models that are related. For example, a &lt;code&gt;ParentViewModel&lt;/code&gt; and &lt;code&gt;ChildViewModel&lt;/code&gt;. Let’s say that the &lt;code&gt;ChildViewModel&lt;/code&gt; has a reference to a &lt;code&gt;ParentViewModel&lt;/code&gt;. When the &lt;code&gt;Savings&lt;/code&gt; property on the &lt;code&gt;ParentViewModel&lt;/code&gt; changes, we want to update the &lt;code&gt;Inheritance&lt;/code&gt; property on the &lt;code&gt;ChildViewModel&lt;/code&gt;. Using &lt;code&gt;DependencyObject&lt;/code&gt;s as view models, we can simply use data binding to achieve this: &lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;//this code is in the ChildViewModel constructor
var binding = new Binding(&amp;quot;Savings&amp;quot;) { Source = parent};
BindingOperations.SetBinding(this, ChildViewModel.InheritanceProperty, binding);Using POCOs we need to do a little more work. Typically your POCO view models will implement INotifyPropertyChanged, so the code would look more like this: 

//this code is in the ChildViewModel constructor
parent.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == &amp;quot;Savings&amp;quot;)
    {
        Inheritance = parent.Savings;
    }
};&lt;/pre&gt;

&lt;p&gt;Neither of these options is particularly appealing to me, but the binding approach with &lt;code&gt;DependencyObject&lt;/code&gt;s is more flexible and less typing. Both suffer from magic strings (&amp;quot;Savings&amp;quot;, in this case).&lt;/p&gt;

&lt;p&gt;I recognised this as a problem with POCO view models a while back and have been busy working on a library that solves it. To whet your appetite, using my library would allow you to do this with any POCOs:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;//this code is in the ChildViewModel constructor
var binding = new TypedBinding&amp;lt;ParentViewModel, ChildViewModel&amp;gt;(parent, x =&amp;gt; x.Savings, this, x =&amp;gt; x.Inheritance);
bindingManager.Bindings.Add(binding);&lt;/pre&gt;

&lt;p&gt;Note the strongly-typed binding using lambda expressions. Note also that I'm planning an even terser, fluent interface. Something like: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;bindingManager.Bind(parent).Property(x =&amp;gt; x.Savings).To(this).Property(x =&amp;gt; x.Inheritance);&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Serialization of View Models&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes you will want to serialize your view model. For example, you might want to implement the &lt;code&gt;IEditableObject&lt;/code&gt; interface so that changes to your view model can be rolled back. An easy way to do this is to serialize a snapshot of your view model and then roll back if necessary: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;[Serializable]
public class MyViewModel : IEditableObject
{
    [NonSerialized]
    private object[] _copy; 

    public MyViewModel()
    {
        Name = string.Empty;
    } 

    public int Age { get; set; } 

    public string Name { get; set; } 

    public void BeginEdit()
    {
        //take a copy of current state
        var members = FormatterServices.GetSerializableMembers(GetType());
        _copy = FormatterServices.GetObjectData(this, members);
    } 

    public void CancelEdit()
    {
        //roll back to copy
        var members = FormatterServices.GetSerializableMembers(GetType());
        FormatterServices.PopulateObjectMembers(this, members, _copy);
    } 

    public void EndEdit()
    {
        //discard copy
        _copy = null;
    }
}&lt;/pre&gt;

&lt;p&gt;This works fine for POCO view models, but not so for &lt;code&gt;DependencyObject&lt;/code&gt;s. Recall that for an object to be serializable (and I'm talking strictly about &lt;code&gt;IFormatter&lt;/code&gt;-based serialization here), it and all its subclasses must be marked with the &lt;code&gt;Serializable&lt;/code&gt; attribute. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;DependencyObject&lt;/code&gt;s are not marked as serializable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Incidentally, you might instead follow the pattern where you wrap your data inside a serializable &lt;code&gt;struct&lt;/code&gt; and just serialize/restore that &lt;code&gt;struct&lt;/code&gt; instead of the view model itself. That works great for POCOs, but – yet again – you will run into headaches if you use &lt;code&gt;DependencyObject&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;And there are other reasons you might want to serialize your view model. Perhaps you want to clone it. Or perhaps you want to save certain view model objects over application restarts. &lt;code&gt;DependencyObject&lt;/code&gt;-based view models will cause you grief when this need arises. Basically, your only option is to implement serialization surrogates, or use a non-&lt;code&gt;IFormatter&lt;/code&gt;-based serialization mechanism.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Equality and Hashing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is often useful to compare view models for equality, or stick them in a dictionary. For example, suppose you have a &lt;code&gt;ReportsViewModel&lt;/code&gt; that is responsible for managing and exposing a set of &lt;code&gt;ReportViewModel&lt;/code&gt;s (note the plural versus singular in those names). Each &lt;code&gt;ReportViewModel&lt;/code&gt; contains the name of the report, the parameters to the report, and the results of its execution: &lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ReportsClassDiagram" border="0" alt="ReportsClassDiagram" src="http://lh3.ggpht.com/_i_HIkiy_ogI/ScvMMbkKGZI/AAAAAAAABNQ/mHZ_2ncARZ8/ReportsClassDiagram%5B5%5D.png?imgmax=800" width="595" height="301" /&gt; &lt;/p&gt;

&lt;p&gt;Now suppose you'd like to cache report executions. If the user runs the same report with the same parameters, you'd like to just give them the existing results. To achieve this, you'd naturally attempt to override the &lt;code&gt;Equals()&lt;/code&gt; and &lt;code&gt;GetHashCode()&lt;/code&gt; methods in the &lt;code&gt;ReportViewModel&lt;/code&gt; class (and implement &lt;code&gt;IEquatable&amp;lt;&lt;code&gt;ReportViewModel&lt;/code&gt;&amp;gt;&lt;/code&gt; if you're thorough). But if the &lt;code&gt;ReportViewModel&lt;/code&gt; class inherits from &lt;code&gt;DependencyObject&lt;/code&gt;, you'll find that you can't. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;The &lt;code&gt;DependencyObject&lt;/code&gt; class overrides and seals both the &lt;code&gt;Equals()&lt;/code&gt; and &lt;code&gt;GetHashCode()&lt;/code&gt; methods.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This inability to redefine equality in your view models is both annoying and limiting in certain scenarios. There may be ways around the problem. For example, you could implement a class that implements &lt;code&gt;IEqualityComparer&amp;lt;ReportViewModel&amp;gt; &lt;/code&gt;and use it where appropriate. However, this can quickly lead to a mess and anti-DRY code base. &lt;/p&gt;

&lt;p&gt;Of course, if your view model is a POCO, it won't suffer from this problem. You'd just provide the most appropriate implementation of equality inside your view model class. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thread Affinity of View Models&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the responsibilities your view models will typically take on is that of doing heavy work on a background thread. For example, suppose you have a refresh button in your UI that causes a heap of widget data to be loaded from the database and displayed in a list. You'd hardly want the UI to hang while the database access is taking place, so you decide to put the work in a background thread: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MyViewModel
{
    //this gets called when the user clicks the refresh button - we'll worry about how that happens in a later post
    public void LoadWidgets()
    {
        //do the heavy lifting in a BG thread
        ThreadPool.QueueUserWorkItem(delegate
        {
            var widgets = new List&amp;lt;Widget&amp;gt;();
            //pretend I execute a database query here, would you kindly?
            var dataReader = command.ExecuteReader(); 

            while (dataReader.Read())
            {
                widgets.Add(new WidgetViewModel(dataReader[&amp;quot;Name&amp;quot;]));
            } 

            //now we have all our widgets read from the DB, so assign to the collection that the UI is bound to
            Dispatcher.Invoke(delegate
            {
                Widgets.Clear();
                Widgets.AddRange(widgets);
            });
        });
    }
}&lt;/pre&gt;

&lt;p&gt;All we're doing here is doing as much work on a background thread as we can. Only at the last step do we switch to the UI thread to update the collection that the UI thread is bound to (and with the right infrastructure, even that would be optional). &lt;/p&gt;

&lt;p&gt;Again, this is great for POCO view models, but falls flat on its face for &lt;code&gt;DependencyObject&lt;/code&gt;s. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;A &lt;code&gt;DependencyObject&lt;/code&gt; has thread affinity - it can only be accessed on the thread on which it was created.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since we're creating a bunch of &lt;code&gt;WidgetViewModel&lt;/code&gt;s on a background thread, those view models will only be accessible on that thread. Therefore, as soon as the UI thread tries to access them (via bindings) an exception will be thrown&lt;sup&gt;†&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;The only option here is to construct and populate each view model on the UI thread. This is ugly, error-prone, and can negate much of the benefit of doing the work on a background thread in the first place. If we need to create many view models, suddenly the UI thread spends much of its time constructing and initialising those view models. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Readability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You'll notice that all of these problems can be worked around, and I don't dispute that. However, all those workarounds result in an incomprehensible mess of code. One of the most important qualities of code is its readability. Using &lt;code&gt;DependencyObject&lt;/code&gt;s as view models causes an explosion of supporting code and workarounds that obscure the intent of the code. What's more, all these workarounds gain you . . . nothing. &lt;/p&gt;

&lt;p&gt;To me, this is the final nail in the coffin for &lt;code&gt;DependencyObject&lt;/code&gt;s as view models. I want my view models to be as readable and maintainable as the XAML I get from using MVVM in the first place. Rather than sweep &lt;em&gt;The Ugly&lt;/em&gt; from the view to the view model, I'd much prefer to banish it entirely. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I think the advantages of POCO view models over &lt;code&gt;DependencyObject&lt;/code&gt; view models are clear and convincing. Moreover, the disadvantages of using POCOs are practically zero. As such, I always use the POCO option in my projects. That said, all the problems I mentioned can be worked around, and you may have a convincing argument to do so (please let me know in the comments if you do). But, for the here and now, I will be sticking with POCOs for my view models. &lt;/p&gt;

&lt;p&gt;In the next two or three posts, I will be sharing some infrastructure I have put together for MVVM applications, starting with a base &lt;code&gt;ViewModel&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;† Note that WPF does do some auto-marshalling for us with simple properties. However, it cannot automatically marshal changes to collections, so you will inevitably end up wanting to create non-trivial &lt;code&gt;DispatcherObject&lt;/code&gt;s on the UI thread.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-4779420413066866600?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/4779420413066866600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=4779420413066866600' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4779420413066866600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4779420413066866600'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/03/view-models-pocos-versus.html' title='View Models: POCOs versus DependencyObjects'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_i_HIkiy_ogI/ScvMMbkKGZI/AAAAAAAABNQ/mHZ_2ncARZ8/s72-c/ReportsClassDiagram%5B5%5D.png?imgmax=800' height='72' width='72'/><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-3487297025649919287</id><published>2009-03-16T19:30:00.001Z</published><updated>2011-09-03T17:56:51.516+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><title type='text'>MultiKeyGesture</title><content type='html'>&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/multikeygesture/MultiKeyGesture.zip"&gt;Download the Solution&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/Sb6otL-09HI/AAAAAAAABNA/WMu0rd-veNQ/s1600-h/image%5B4%5D.png"&gt;&lt;img style="border-right-width: 0px; margin: 0px 0px 0px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="right" src="http://lh5.ggpht.com/_i_HIkiy_ogI/Sb6ouOtq9BI/AAAAAAAABNE/xk1WFpLn3eg/image_thumb%5B2%5D.png?imgmax=800" width="180" height="65" /&gt;&lt;/a&gt; A colleague recently asked whether it was possible to invoke a WPF &lt;code&gt;Command&lt;/code&gt; when the user presses a sequence of keys. As an example, consider the &lt;em&gt;Format Document &lt;/em&gt;command in Visual Studio, which is generally mapped to &lt;strong&gt;Ctrl+K, D&lt;/strong&gt;. &lt;/p&gt;  &lt;p&gt;In WPF, a &lt;code&gt;Command&lt;/code&gt; can be invoked via &amp;quot;input gestures&amp;quot; in a couple of different ways:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;When creating a &lt;code&gt;RoutedCommand&lt;/code&gt;, you can add any number of &lt;code&gt;InputGesture&lt;/code&gt;s to the &lt;code&gt;InputGestures&lt;/code&gt; collection. Adding an &lt;code&gt;InputGesture&lt;/code&gt; to this collection ensures that the &lt;code&gt;Command&lt;/code&gt; will be executed (if it can be) when that gesture is performed by the user. &lt;/li&gt;    &lt;li&gt;Via the &lt;code&gt;UIElement&lt;/code&gt;'s &lt;code&gt;InputBindings&lt;/code&gt; collection. Adding an &lt;code&gt;InputBinding&lt;/code&gt; to this collection ensures that a certain &lt;code&gt;InputGesture&lt;/code&gt; will execute a certain &lt;code&gt;Command&lt;/code&gt; against that &lt;code&gt;UIElement&lt;/code&gt;. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;WPF's built-in &lt;code&gt;KeyGesture&lt;/code&gt; class is an &lt;code&gt;InputGesture&lt;/code&gt; subclass that recognises a gesture based on keyboard input. The problem is, its definition of &amp;quot;gesture&amp;quot; is a single keypress. What I'd like to do is treat multiple keypresses as a single gesture, and &lt;code&gt;KeyGesture&lt;/code&gt; does not support that. &lt;/p&gt;  &lt;p&gt;Enter my &lt;code&gt;MultiKeyGesture&lt;/code&gt; class. At first I thought I'd subclass &lt;code&gt;InputGesture&lt;/code&gt; rather than &lt;code&gt;KeyGesture&lt;/code&gt;, since the &lt;code&gt;KeyGesture&lt;/code&gt; constructors reflect the single-key assumption. However, I found I had little choice but to subclass &lt;code&gt;KeyGesture&lt;/code&gt; because the built-in WPF &lt;code&gt;MenuItem&lt;/code&gt; control treats it as a special case in determining the text to display for the shortcut string. I could manually set the &lt;code&gt;InputGestureText&lt;/code&gt; of the &lt;code&gt;MenuItem&lt;/code&gt;, but I just couldn't be bothered for the purposes of this post. &lt;/p&gt;  &lt;p&gt;Never mind though, because I can simply pass in &lt;code&gt;Key.None&lt;/code&gt; to the &lt;code&gt;KeyGesture&lt;/code&gt; constructor and override its matching logic: &lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;public MultiKeyGesture(IEnumerable&amp;lt;Key&amp;gt; keys, ModifierKeys modifiers, string displayString)
    : base(Key.None, modifiers, displayString)
{
    _keys = new List&amp;lt;Key&amp;gt;(keys); 

    if (_keys.Count == 0)
    {
        throw new ArgumentException(&amp;quot;At least one key must be specified.&amp;quot;, &amp;quot;keys&amp;quot;);
    }
} 

public override bool Matches(object targetElement, InputEventArgs inputEventArgs)
{
    ...
}I&lt;/pre&gt;

&lt;pre&gt;n other words, I'm only inheriting from &lt;code&gt;KeyGesture&lt;/code&gt; so that our particular gesture implementation gels with other WPF classes that make annoying assumptions and break the &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov substitution principle&lt;/a&gt;. &lt;/pre&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/Sb6ovj6a4XI/AAAAAAAABNI/ASwkSovyRoA/s1600-h/image%5B17%5D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" align="left" src="http://lh6.ggpht.com/_i_HIkiy_ogI/Sb6oxxCQRRI/AAAAAAAABNM/j9Mc_fQcWgk/image_thumb%5B13%5D.png?imgmax=800" width="240" height="180" /&gt;&lt;/a&gt; Notice from the constructor that the &lt;code&gt;MultiKeyGesture&lt;/code&gt; class takes an enumeration of &lt;code&gt;Key&lt;/code&gt;s. In order for a match to occur, the user must type in all of those keys (in order, of course). Generally, you would have a maximum of two keystrokes, but the sky really is the limit here. You could make the user type in &amp;quot;Ctrl+A, p, r, i, l, O, n, e, i, l, l, i, s, h, a, w, t&amp;quot; before your super-secret command is executed. You'd be pretty childish if you did that, but you could. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Matches()&lt;/code&gt; method is where all the magic happens. It is this method that determines whether the user input matches the keys in the &lt;code&gt;Keys&lt;/code&gt; collection. It does this with a mini state machine. As input is received, one of three things can occur:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;No match. The user entered the wrong key or paused too long between keystrokes. The index into the &lt;code&gt;Keys&lt;/code&gt; collection is reset back to zero and the method returns &lt;code&gt;false&lt;/code&gt;. &lt;/li&gt;

  &lt;li&gt;Partial match. The user entered a matching key but not all keys have been entered yet. The index into the &lt;code&gt;Keys&lt;/code&gt; collection is incremented and the method returns &lt;font face="Courier New"&gt;false&lt;/font&gt; (but marks the &lt;code&gt;RoutedEvent&lt;/code&gt; as handled). &lt;/li&gt;

  &lt;li&gt;Full match. The user entered the final matching key in the &lt;code&gt;Keys&lt;/code&gt; collection. The index into the &lt;code&gt;Keys&lt;/code&gt; collection is reset back to zero and the method returns &lt;code&gt;true&lt;/code&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it really. All the usual disclaimers apply about blog-quality code, but it does at least show that the scenario is possible in WPF. &lt;/p&gt;

&lt;p&gt;If you look at the code, you'll notice a couple of other classes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;&lt;/code&gt;&lt;font face="Courier New"&gt;MultiKeyBinding&lt;/font&gt; &lt;/li&gt;

  &lt;li&gt;&lt;code&gt;MultiKeyGestureConverter&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't strictly necessary unless you want &lt;code&gt;UIElement.InputBindings&lt;/code&gt; and XAML integration respectively. &lt;code&gt;MultiKeyBinding&lt;/code&gt; is used to map a &lt;code&gt;MultiKeyGesture&lt;/code&gt; to a particular &lt;code&gt;Command&lt;/code&gt; for a &lt;code&gt;UIElement&lt;/code&gt; (in XAML in this case, but could also be in code, of course): &lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;TextBox x:Name=&amp;quot;_textBox&amp;quot;&amp;gt;
    &amp;lt;TextBox.InputBindings&amp;gt;
        &amp;lt;local:MultiKeyBinding Command=&amp;quot;{x:Static local:Commands.Secret}&amp;quot;            Gesture=&amp;quot;Ctrl+A,p,r,i,l,O,n,e,i,l,l,i,s,h,a,w,t&amp;quot;/&amp;gt;
    &amp;lt;/TextBox.InputBindings&amp;gt;
&amp;lt;/TextBox&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;MultiKeyGestureConverter&lt;/code&gt; is used to parse the &lt;code&gt;Gesture&lt;/code&gt; attribute in the XAML into a &lt;code&gt;MultiKeyGesture&lt;/code&gt; for the &lt;code&gt;MultiKeyBinding&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Note that I didn't put much effort into these supporting classes at all. They are bare-bones to get the demo working. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/multikeygesture/MultiKeyGesture.zip"&gt;Download the Solution&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-3487297025649919287?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/3487297025649919287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=3487297025649919287' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3487297025649919287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3487297025649919287'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/03/multikeygesture.html' title='MultiKeyGesture'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_i_HIkiy_ogI/Sb6ouOtq9BI/AAAAAAAABNE/xk1WFpLn3eg/s72-c/image_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-7014797004638621179</id><published>2009-03-07T10:54:00.001Z</published><updated>2011-09-03T17:59:26.107+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><title type='text'>Unselectable, Interactive Items in a Selector</title><content type='html'>&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/UnselectableInteractiveItemsInSelector/UnselectableInteractiveItemsInSelector.zip"&gt;Download the Solution&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Disabling an item in a &lt;code&gt;Selector&lt;/code&gt; (such as a &lt;code&gt;ComboBox&lt;/code&gt;) is easy once you understand that each item is automatically wrapped in its own container, and that you can apply a style to that container. &lt;/p&gt;  &lt;p&gt;Suppose you have a view-model that represents a customer: &lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;public class CustomerViewModel : ViewModel
{
    private string _name; 

    public string Name
    {
        get { return _name; }
        set
        {
            if (_name != value)
            {
                _name = value;
                OnPropertyChanged(&amp;quot;Name&amp;quot;);
                OnPropertyChanged(&amp;quot;IsEnabled&amp;quot;);
            }
        }
    } 

    public bool IsEnabled
    {
        get
        {
            return !Name.StartsWith(&amp;quot;Kent &amp;quot;);
        }
    }
} &lt;/pre&gt;

&lt;p&gt;You can bind to the &lt;code&gt;IsEnabled&lt;/code&gt; property from the item container's style thusly: &lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;ComboBox ItemsSource=&amp;quot;{Binding Customers}&amp;quot; DisplayMemberPath=&amp;quot;Name&amp;quot;&amp;gt;
    &amp;lt;ComboBox.ItemContainerStyle&amp;gt;
        &amp;lt;Style&amp;gt;
            &amp;lt;Setter Property=&amp;quot;UIElement.IsEnabled&amp;quot; Value=&amp;quot;{Binding IsEnabled}&amp;quot;/&amp;gt;
        &amp;lt;/Style&amp;gt;
    &amp;lt;/ComboBox.ItemContainerStyle&amp;gt;
&amp;lt;/ComboBox&amp;gt; &lt;/pre&gt;

&lt;pre&gt;Then any &lt;code&gt;Customer&lt;/code&gt;'s who share my Christian name will be completely disabled: &lt;/pre&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SbJSL9LRxOI/AAAAAAAABMc/tgg5iIHmct4/image%5B5%5D.png?imgmax=800" width="286" height="106" /&gt; &lt;/p&gt;

&lt;p&gt;The user is unable to select the disabled items with the keyboard or mouse, nor can they interact with them in anyway (eg. if there was a &lt;code&gt;Button&lt;/code&gt; in the &lt;code&gt;ItemTemplate&lt;/code&gt; of the &lt;code&gt;ComboBox&lt;/code&gt;, the &lt;code&gt;Button&lt;/code&gt; would also be disabled). &lt;/p&gt;

&lt;p&gt;But what if I &lt;em&gt;want &lt;/em&gt;to allow the user to interact with an item in the &lt;code&gt;ComboBox&lt;/code&gt;, but not allow them to select it via the keyboard or mouse? There are numerous reasons you might want to do this, but my use case was as follows (this is a financial application):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;User can select from a number of market-related times (such as Open, Closing, Live, T - 1, T - 2 etcetera) in a &lt;code&gt;ComboBox&lt;/code&gt; &lt;/li&gt;

  &lt;li&gt;&lt;code&gt;&lt;/code&gt;User can alternatively click on a specific date in a &lt;code&gt;Calendar&lt;/code&gt; that is inside the same &lt;code&gt;ComboBox&lt;/code&gt; &lt;/li&gt;

  &lt;li&gt;&lt;code&gt;&lt;/code&gt;When the user selects a date in the &lt;code&gt;Calendar&lt;/code&gt;, the &lt;code&gt;SelectedValue&lt;/code&gt; of the &lt;code&gt;ComboBox&lt;/code&gt; reflects this fact &lt;/li&gt;

  &lt;li&gt;The user cannot manually (via keyboard or mouse) select the interactive calendar item in the &lt;code&gt;ComboBox&lt;/code&gt; &lt;/li&gt;

  &lt;li&gt;&lt;code&gt;&lt;/code&gt;In addition to manually selecting values, the user can type values in the &lt;code&gt;ComboBox&lt;/code&gt; (ie. it is editable). For example, they might type &amp;quot;Open&amp;quot;, &amp;quot;T - 1&amp;quot;, or a specific date, such as &amp;quot;31/12/2004&amp;quot; &lt;/li&gt;

  &lt;li&gt;When typing in dates, the calendar should &amp;quot;scroll to&amp;quot; the correct month for the date entered &lt;/li&gt;

  &lt;li&gt;Future dates are not permitted &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First of all let me say that it might be possible to pull this off by re-templating the &lt;code&gt;ComboBox&lt;/code&gt; such that its &lt;code&gt;Popup&lt;/code&gt; displays all items and then a &lt;code&gt;Calendar&lt;/code&gt; below the items. However, this has some serious disadvantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;re-templating a complex control such as &lt;code&gt;ComboBox&lt;/code&gt; is time-consuming and error-prone &lt;/li&gt;

  &lt;li&gt;re-templating needs to be done for each theme supported by the application, and for each control we want to use this technique in (what if I want to change from a &lt;code&gt;ComboBox&lt;/code&gt; to a &lt;code&gt;ListBox&lt;/code&gt;, for example) &lt;/li&gt;

  &lt;li&gt;I really want the interactive item in the &lt;code&gt;ComboBox&lt;/code&gt; to be programmatically selectable. This will be particularly useful for those who want to use this technique with a &lt;code&gt;ComboBox&lt;/code&gt; that isn't editable &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's time to set the stage a bit. Please bear with me a little here. Here are the view models I threw together to get myself started solving this problem: &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/SbJSNqg2naI/AAAAAAAABMg/G7QFvncccEw/s1600-h/image%5B10%5D.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_i_HIkiy_ogI/SbJSO198E7I/AAAAAAAABMk/gunWBYsmQX0/image_thumb%5B5%5D.png?imgmax=800" width="551" height="480" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The view models take care of various details such as parsing and validating any text entered by the user. I could then put together some minimalistic data templates to render these view models: &lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;!-- explicit points in time are rendered as a Calendar so that the user can choose the point in time they want --&amp;gt;
&amp;lt;DataTemplate DataType=&amp;quot;{x:Type local:ExplicitPointInTimeViewModel}&amp;quot;&amp;gt;
    &amp;lt;wpf:Calendar SelectedDate=&amp;quot;{Binding SelectedValue, Mode=TwoWay}&amp;quot;/&amp;gt;
&amp;lt;/DataTemplate&amp;gt; 

&amp;lt;!-- financial times are rendered as an editable combo box listing all times --&amp;gt;
&amp;lt;DataTemplate DataType=&amp;quot;{x:Type local:FinancialTimesViewModel}&amp;quot;&amp;gt;
    &amp;lt;ComboBox x:Name=&amp;quot;_comboBox&amp;quot; ItemsSource=&amp;quot;{Binding Items}&amp;quot; IsEditable=&amp;quot;True&amp;quot; Text=&amp;quot;{Binding Text, ValidatesOnDataErrors=True}&amp;quot;&amp;gt;
        &amp;lt;ComboBox.ItemContainerStyle&amp;gt;
            &amp;lt;Style TargetType=&amp;quot;ComboBoxItem&amp;quot;&amp;gt;
                &amp;lt;!-- ensure relevant combo box items are disabled --&amp;gt;
                &amp;lt;Setter Property=&amp;quot;IsEnabled&amp;quot; Value=&amp;quot;{Binding Converter={StaticResource IsEnabledConverter}}&amp;quot;/&amp;gt;
            &amp;lt;/Style&amp;gt;
        &amp;lt;/ComboBox.ItemContainerStyle&amp;gt;
    &amp;lt;/ComboBox&amp;gt;
&amp;lt;/DataTemplate&amp;gt;&lt;/pre&gt;

&lt;p&gt;Finally, I put a &lt;code&gt;ContentControl&lt;/code&gt; in my &lt;code&gt;Window&lt;/code&gt; and stuck a &lt;code&gt;FinancialTimesViewModel&lt;/code&gt; in it: &lt;/p&gt;

&lt;pre&gt;var viewModel = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; FinancialTimesViewModel();
viewModel.Items.Add(&amp;quot;&lt;span style="color: #8b0000"&gt;Live&lt;/span&gt;&amp;quot;);
viewModel.Items.Add(&amp;quot;&lt;span style="color: #8b0000"&gt;Open&lt;/span&gt;&amp;quot;);
viewModel.Items.Add(&amp;quot;&lt;span style="color: #8b0000"&gt;Closing&lt;/span&gt;&amp;quot;);
viewModel.Items.Add(&amp;quot;&lt;span style="color: #8b0000"&gt;T - 2&lt;/span&gt;&amp;quot;);
viewModel.Items.Add(&amp;quot;&lt;span style="color: #8b0000"&gt;T - 3&lt;/span&gt;&amp;quot;);
viewModel.Items.Add(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ExplicitPointInTimeViewModel());
_contentControl.Content = viewModel;&lt;/pre&gt;

&lt;p&gt;Running this we can see that the templates are being used to render the view models: &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/SbJSP5kF4_I/AAAAAAAABMo/kZKhe3zmK4Q/s1600-h/image%5B15%5D.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SbJSQkIe00I/AAAAAAAABMs/JixR524aQEY/image_thumb%5B8%5D.png?imgmax=800" width="230" height="260" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As expected, the &lt;code&gt;Calendar&lt;/code&gt; is completely disabled and useless so far as our use case goes. The first thing I tried to get around this was to just re-enable a child control inside the &lt;code&gt;DataTemplate&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;DataTemplate DataType=&amp;quot;{x:Type local:ExplicitPointInTimeViewModel}&amp;quot;&amp;gt;
    &amp;lt;ContentControl IsEnabled=&amp;quot;True&amp;quot;&amp;gt;
        &amp;lt;wpf:Calendar SelectedDate=&amp;quot;{Binding SelectedValue, Mode=TwoWay}&amp;quot;/&amp;gt;
    &amp;lt;/ContentControl&amp;gt;
&amp;lt;/DataTemplate&amp;gt; &lt;/pre&gt;

&lt;p&gt;However, this had no effect. It was time to do some investigative work (otherwise known as Reflector) to determine how the &lt;code&gt;ComboBox&lt;/code&gt; was making its decision to disable the item. I found this method in &lt;code&gt;ComboBox&lt;/code&gt; that determines whether an item is selectable: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;private bool IsSelectableHelper(object o)
{
    DependencyObject obj2 = o as DependencyObject;
    return ((obj2 == null) || ((bool) obj2.GetValue(UIElement.IsEnabledProperty)));
}&lt;/pre&gt;

&lt;p&gt;So if it's not a &lt;code&gt;DependencyObject&lt;/code&gt;, the item is selectable. And if it is, the &lt;code&gt;IsEnabled&lt;/code&gt; property is used to determine its &amp;quot;selectability&amp;quot;. &lt;/p&gt;

&lt;p&gt;But wait - we changed the &lt;code&gt;IsEnabled&lt;/code&gt; property of the &lt;code&gt;ContentControl&lt;/code&gt; within the template and it didn't enable its children. That's because &lt;code&gt;IsEnabled&lt;/code&gt; doesn't get to make the final decision about whether a &lt;code&gt;UIElement&lt;/code&gt; is enabled or not. From &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.uielement.isenabled.aspx"&gt;MSDN&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note that this property is influenced by class-specific implementations of &lt;code&gt;IsEnabledCore&lt;/code&gt; on particular elements, often at runtime. Therefore, the default value listed here is sometimes not effective. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examining &lt;code&gt;UIElement&lt;/code&gt; further, I found that the &lt;code&gt;IsEnabled&lt;/code&gt; property was being coerced to &lt;code&gt;false&lt;/code&gt; if any ancestor was disabled. That makes perfect sense really. You'd hardly want to have to manually disable all the children of a &lt;code&gt;Panel&lt;/code&gt; when you disable the &lt;code&gt;Panel&lt;/code&gt; itself. It’s much nicer that you can just disable the &lt;code&gt;Panel&lt;/code&gt; and all children become disabled. &lt;/p&gt;

&lt;p&gt;So what to do? I needed a control that didn't consider the &lt;code&gt;IsEnabled&lt;/code&gt; state of any parent, and that's when I wrote the &lt;code&gt;AlwaysEnabledControl&lt;/code&gt;: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public class AlwaysEnabledControl : Border
{
    static AlwaysEnabledControl()
    {
        //override IsEnabled to coerce to true rather than considering the enabled state of the parent combo box item
        IsEnabledProperty.OverrideMetadata(typeof(AlwaysEnabledControl), new FrameworkPropertyMetadata(true, IsEnabled_Changed, CoerceIsEnabled));
    } 

    private static void IsEnabled_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
    } 

    private static object CoerceIsEnabled(DependencyObject dependencyObject, object value)
    {
        //we're always enabled
        return true;
    }
}&lt;/pre&gt;



&lt;p&gt;As you can see, this control overrides the coercion logic in &lt;code&gt;UIElement&lt;/code&gt; such that it is always enabled. Now, if I can wrap my &lt;code&gt;Calendar&lt;/code&gt; in this baby: &lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;DataTemplate DataType=&amp;quot;{x:Type local:ExplicitPointInTimeViewModel}&amp;quot;&amp;gt;
    &amp;lt;local:AlwaysEnabledControl&amp;gt;
        &amp;lt;wpf:Calendar SelectedDate=&amp;quot;{Binding SelectedValue, Mode=TwoWay}&amp;quot;/&amp;gt;
    &amp;lt;/local:AlwaysEnabledControl&amp;gt;
&amp;lt;/DataTemplate&amp;gt;&lt;/pre&gt;

&lt;p&gt;And here's what I get at runtime: &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/SbJSSIdwA9I/AAAAAAAABMw/xUPBhdXS4j4/s1600-h/image%5B20%5D.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_i_HIkiy_ogI/SbJSSn2kWUI/AAAAAAAABM0/KCKFs16mfQg/image_thumb%5B11%5D.png?imgmax=800" width="196" height="261" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Hooray! Our &lt;code&gt;Calendar&lt;/code&gt; is now enabled and the user can interact with it. However, there are some problems:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;As evident in the screenshot, the &lt;code&gt;Calendar&lt;/code&gt; gets highlighted when the user mouses over it, which looks ugly &lt;/li&gt;

  &lt;li&gt;Not evident in the screenshot, the user can select the &lt;code&gt;ComboBoxItem&lt;/code&gt; containing the &lt;code&gt;Calendar&lt;/code&gt; by using the keyboard or mouse &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In reality I dealt with the second problem first because it was a deal-breaker. However, I'll talk about the first problem first here because it's conceptually easier. &lt;/p&gt;

&lt;p&gt;I considered a couple of different solutions to the selection highlight problem. My first thought was to override the &lt;code&gt;SystemColors.HighlightBrushKey&lt;/code&gt; and &lt;code&gt;SystemColors.HighlightTextBrushKey&lt;/code&gt; resources for the &lt;code&gt;ComboBoxItem&lt;/code&gt; containing the &lt;code&gt;Calendar&lt;/code&gt;. The &lt;code&gt;ComboBoxItem&lt;/code&gt; template uses these resources to look up &lt;code&gt;Brush&lt;/code&gt;es when highlighting itself. &lt;/p&gt;

&lt;p&gt;The problem was, I couldn't override these resources for individual &lt;code&gt;ComboBoxItem&lt;/code&gt;s - at least, not from within the XAML. I could override for all &lt;code&gt;ComboBoxItem&lt;/code&gt;s like this: &lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;ComboBox.Resources&amp;gt;
    &amp;lt;SolidColorBrush x:Key=&amp;quot;{x:Static SystemColors.HighlightBrushKey}&amp;quot;&amp;gt;Red&amp;lt;/SolidColorBrush&amp;gt;
&amp;lt;/ComboBox.Resources&amp;gt; &lt;/pre&gt;

&lt;p&gt;But attempting to override at the ComboBoxItem failed: &lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;ComboBox.ItemContainerStyle&amp;gt;
    &amp;lt;Style TargetType=&amp;quot;ComboBoxItem&amp;quot;&amp;gt;
        &amp;lt;Setter Property=&amp;quot;Resources&amp;quot;&amp;gt;
            &amp;lt;Setter.Value&amp;gt;
                &amp;lt;ResourceDictionary&amp;gt;
                    &amp;lt;SolidColorBrush x:Key=&amp;quot;{x:Static SystemColors.HighlightBrushKey}&amp;quot;&amp;gt;Red&amp;lt;/SolidColorBrush&amp;gt;
                &amp;lt;/ResourceDictionary&amp;gt;
            &amp;lt;/Setter.Value&amp;gt;
        &amp;lt;/Setter&amp;gt;
    &amp;lt;/Style&amp;gt;
&amp;lt;/ComboBox&amp;gt;&lt;/pre&gt;



&lt;p&gt;This fails at runtime, and is not really what I want to do anyway. What I want is to selectively inject resources into the &lt;code&gt;ComboBoxItem&lt;/code&gt;'s &lt;code&gt;Resources&lt;/code&gt; collection. I could not figure out how to do this from XAML, so I decided to ponder other solutions. &lt;/p&gt;

&lt;p&gt;The solution ended up being reasonably simple. I added these &lt;code&gt;Setter&lt;/code&gt;s to the &lt;code&gt;ComboBoxItem&lt;/code&gt; Style: &lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;!-- ensure we can't see the highlighting when we mouse over any always-enabled control --&amp;gt;
&amp;lt;Setter Property=&amp;quot;HorizontalContentAlignment&amp;quot; Value=&amp;quot;Stretch&amp;quot;/&amp;gt;
&amp;lt;Setter Property=&amp;quot;VerticalContentAlignment&amp;quot; Value=&amp;quot;Stretch&amp;quot;/&amp;gt;
&amp;lt;Setter Property=&amp;quot;Margin&amp;quot; Value=&amp;quot;0&amp;quot;/&amp;gt;
&amp;lt;!-- most items require some padding, but the calendar control should not have any --&amp;gt;
&amp;lt;Setter Property=&amp;quot;Padding&amp;quot;&amp;gt;
    &amp;lt;Setter.Value&amp;gt;
        &amp;lt;Binding Path=&amp;quot;.&amp;quot; Converter=&amp;quot;{StaticResource PaddingConverter}&amp;quot;&amp;gt;
            &amp;lt;Binding.FallbackValue&amp;gt;
                &amp;lt;Thickness&amp;gt;2,0,2,0&amp;lt;/Thickness&amp;gt;
            &amp;lt;/Binding.FallbackValue&amp;gt;
        &amp;lt;/Binding&amp;gt;
    &amp;lt;/Setter.Value&amp;gt;
&amp;lt;/Setter&amp;gt;&lt;/pre&gt;

&lt;p&gt;What we're doing here is making sure the content in the &lt;code&gt;ComboBoxItem&lt;/code&gt; stretches across the entire expanse of the &lt;code&gt;ComboBoxItem&lt;/code&gt;. Therefore, even if the interactive item &lt;em&gt;is &lt;/em&gt;highlighted, we won't be able to see the highlighting. Of course, I need to also give the interactive item a non-transparent &lt;code&gt;Background&lt;/code&gt;: &lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;local:AlwaysEnabledControl Background=&amp;quot;LightGray&amp;quot;&amp;gt;
    &amp;lt;wpf:Calendar SelectedDate=&amp;quot;{Binding SelectedValue, Mode=TwoWay}&amp;quot;/&amp;gt;
&amp;lt;/local:AlwaysEnabledControl&amp;gt;&lt;/pre&gt;

&lt;p&gt;Now running the application we see this: &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_i_HIkiy_ogI/SbJSTSIkFEI/AAAAAAAABM4/-lQfoYXpPzE/s1600-h/image%5B25%5D.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_i_HIkiy_ogI/SbJST7SuENI/AAAAAAAABM8/vBqLMKM5ndY/image_thumb%5B14%5D.png?imgmax=800" width="197" height="260" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;It won't win any beauty contests, but we're edging closer and closer to the desired behaviour. &lt;/p&gt;

&lt;p&gt;The last big problem that required solving is the fact that the user can still select the interactive item via the keyboard or mouse. This is counterintuitive and annoying for the user if they actually click just outside the &lt;code&gt;Calendar&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;It seems wrong that the &lt;code&gt;ComboBoxItem&lt;/code&gt; is considered selectable given that it has been disabled (remember, it's just the contents inside the &lt;code&gt;ComboBoxItem&lt;/code&gt; that are enabled). The key to solving this problem is understanding that the &lt;code&gt;ComboBox&lt;/code&gt; executes different selection logic based on whether the drop-down is open or not. Indeed, if I run the application at this point and try to select the interactive item without opening the &lt;code&gt;ComboBox&lt;/code&gt; drop-down, I can't. But if I open the drop-down first, I can cursor down until the &lt;code&gt;Calendar&lt;/code&gt; is selected.&lt;/p&gt;

&lt;p&gt;When the drop-down is open, the &lt;code&gt;ComboBox&lt;/code&gt; actually delegates to an internal method on &lt;code&gt;ItemsControl&lt;/code&gt; to select the next item. That method (&lt;code&gt;ItemsControl.NavigateByLine&lt;/code&gt;) uses keyboard navigation to determine an items eligibility for selection - not the &lt;code&gt;IsEnabled&lt;/code&gt; state of its container. So, because the &lt;code&gt;Calendar&lt;/code&gt; and its children can accept focus, the &lt;code&gt;ItemsControl&lt;/code&gt; considers it eligible for selection. &lt;/p&gt;

&lt;p&gt;Thankfully, we can dig ourselves out of this hole by disabling directional navigation on the &lt;code&gt;ComboBoxItem&lt;/code&gt;s: &lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;Setter Property=&amp;quot;KeyboardNavigation.DirectionalNavigation&amp;quot; Value=&amp;quot;None&amp;quot;/&amp;gt;&lt;/pre&gt;

&lt;p&gt;This has the effect of making the contents of the &lt;code&gt;ComboBoxItem&lt;/code&gt; “invisible” to the logic used by the &lt;code&gt;ItemsControl&lt;/code&gt;. Therefore, we can no longer select the &lt;code&gt;Calendar&lt;/code&gt; with the keyboard. &lt;/p&gt;

&lt;p&gt;But the mouse can still be used to select it. At first glance, it looked like I could workaround this by setting &lt;code&gt;IsHitTestVisible&lt;/code&gt; to &lt;font face="Courier New"&gt;false&lt;/font&gt; on the &lt;code&gt;ComboBoxItem&lt;/code&gt; and then overriding the coercion logic like I did with the &lt;code&gt;IsEnabled&lt;/code&gt; property. However, that didn't seem to work and I'm not entirely sure why. I suspect there are assumptions about hit test visibility in parent/child relationships ingrained into other areas of WPF. &lt;/p&gt;

&lt;p&gt;Again, solving this required some inside knowledge into how the mouse clicks were being handled by the &lt;code&gt;ComboBoxItem&lt;/code&gt;s. Basically, &lt;code&gt;ComboBoxItem&lt;/code&gt;s pass the various mouse events to the owning &lt;code&gt;ComboBox&lt;/code&gt; and the &lt;code&gt;ComboBox&lt;/code&gt; decides what to do with them. It's the &lt;code&gt;MouseLeftButtonUp&lt;/code&gt; event that causes the item to be selected. Therefore, I added this to the &lt;code&gt;AlwaysEnabledControl&lt;/code&gt;: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
{
    base.OnPreviewMouseLeftButtonUp(e); 

    //if the user clicks directly on this control, don't let that click propagate to the container
    if (VisualTreeHelper.HitTest(this, e.GetPosition(this)).VisualHit == this)
    {
        e.Handled = true;
    }
}&lt;/pre&gt;

&lt;p&gt;As you can see, this override ensures any clicks directly on the &lt;code&gt;AlwaysEnabledControl&lt;/code&gt; are swallowed. That means the &lt;code&gt;ComboBoxItem&lt;/code&gt; will never see the event and therefore the item will not be selected. &lt;/p&gt;

&lt;p&gt;There are some other points of interest in the code base, but I'll let you discover them yourself. The end result is that we satisfy all our requirements. And with some minor modifications to the XAML, you can swap the &lt;code&gt;ComboBox&lt;/code&gt; out for a different &lt;code&gt;Selector&lt;/code&gt; (such as a &lt;code&gt;ListBox&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;This technique of having interactive items that are &amp;quot;disabled&amp;quot; from the perspective of the &lt;code&gt;Selector&lt;/code&gt; in which they're contained could be useful in quite a few different scenarios. Here are a couple off the top of my head:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A colour pick list that contains the names of many common colours and then an interactive colour wheel at the bottom &lt;/li&gt;

  &lt;li&gt;A multi-select list of customers (or whatever) with an interactive search item up the top. When the search item is used, it actually resolves to a dynamic query that selects any number of customers based on some criteria &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should note that the attached solution was my POC only. I ended up refactoring the code a fair bit to make it cleaner and more extensible.&lt;/p&gt;

&lt;p&gt;Enjoy! &lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/UnselectableInteractiveItemsInSelector/UnselectableInteractiveItemsInSelector.zip"&gt;Download the Solution&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-7014797004638621179?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/7014797004638621179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=7014797004638621179' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7014797004638621179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7014797004638621179'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/03/unselectable-interactive-items-in.html' title='Unselectable, Interactive Items in a Selector'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_i_HIkiy_ogI/SbJSL9LRxOI/AAAAAAAABMc/tgg5iIHmct4/s72-c/image%5B5%5D.png?imgmax=800' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-379459956155703638</id><published>2009-02-24T17:50:00.001Z</published><updated>2011-09-03T18:00:41.650+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MEF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='MAF'/><title type='text'>MAF and MEF</title><content type='html'>&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/maf_and_mef/MAFandMEF.zip"&gt;Download the Solution&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This morning I listened to &lt;a href="http://www.hanselminutes.com/default.aspx?showID=166"&gt;Glenn Block's MEF talk on Hanselminutes&lt;/a&gt;, wherein he touched on the differences between MAF and MEF. I was glad he did. Not only are their names confusingly similar, but their goals seem so on the surface, too. &lt;/p&gt;  &lt;p&gt;Glenn sums up the differences well by saying that MEF is about &lt;em&gt;extensibility&lt;/em&gt; whilst MAF is about &lt;em&gt;isolation&lt;/em&gt;. Moreover, they are not mutually exclusive. It is entirely possible - and legitimate - to use both together. &lt;/p&gt;  &lt;p&gt;Indeed, this is something I've been meaning to try and I will cover it in this post. Specifically, I will show how a MAF add-in can use MEF to compose a set of unknown parts to do its job. &lt;/p&gt;  &lt;p&gt;First of all, I started with my &lt;a href="http://kentb.blogspot.com/2008/06/maf-gymnastics-skeletal-solution.html"&gt;skeletal MAF solution&lt;/a&gt;. I'm really glad I took the time to put that thing together - it has saved me a lot of time with these MAF-related blog posts ;) &lt;/p&gt;  &lt;p&gt;Next up, I grabbed the latest preview of MEF from the &lt;a href="http://mef.codeplex.com/"&gt;MEF CodePlex site&lt;/a&gt;. I copied the &lt;em&gt;System.ComponentModel.Composition &lt;/em&gt;assembly into my skeletal solution and referenced it from my sample add-in. MEF will eventually be part of the framework (version 4.0 is the target) but for now it is standalone. &lt;/p&gt;  &lt;p&gt;Then, I defined the interface my add-in will rely on (import): &lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;public interface IMessageProvider
{
    string Message { get; }
}&lt;/pre&gt;

&lt;p&gt;It will import any implementations of this interface it finds and print out the corresponding messages. I added one implementation of this interface to the add-in project: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;[Export(typeof(IMessageProvider))]
public class SampleMessageProvider : IMessageProvider
{
    public string Message
    {
        get { return &amp;quot;A message provider in the same assembly as the add-in.&amp;quot;; }
    }
}&lt;/pre&gt;

&lt;p&gt;I added a &lt;font face="courier new"&gt;Compose()&lt;/font&gt; method to the add-in: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;private void Compose()
{
    var directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    var container = new CompositionContainer(new DirectoryCatalog(directory));
    var batch = new CompositionBatch();
    batch.AddPart(this);
    container.Compose(batch);
} &lt;/pre&gt;

&lt;p&gt;This method is called by the add-in when it is initialized. It composes the MEF container by looking for all parts in the directory containing the add-in. The easiest way to get that directory was to use the location of the currently executing assembly, since that assembly is the add-in itself. &lt;/p&gt;

&lt;p&gt;The add-in imports all message providers: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;[Import]
public IEnumerable&amp;lt;IMessageProvider&amp;gt; MessageProviders { get; set; } &lt;/pre&gt;

&lt;p&gt;And then it iterates over them during its &lt;font face="courier new"&gt;Initialize()&lt;/font&gt; method: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public void Initialize(IHost host)
{
    Compose();
    Console.WriteLine(&amp;quot;This is the sample add-in, running inside host with name '{0}', version {1}. AppDomain name is '{2}'.&amp;quot;, host.Name, host.Version, AppDomain.CurrentDomain.FriendlyName); 

    foreach (var messageProvider in MessageProviders)
    {
        Console.WriteLine(messageProvider.Message);
    }
}&lt;/pre&gt;

&lt;p&gt;Running the application at this point works just fine and we see the single message provider was found: &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_i_HIkiy_ogI/SaQzal0vW_I/AAAAAAAABMM/ZDff0qYbjHo/s1600-h/image9.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SaQzb_ZHXqI/AAAAAAAABMQ/huHiJhlhElI/image_thumb5.png?imgmax=800" width="669" height="134" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Now I wanted to add another message provider in a completely different assembly to the add-in. So I added a new project called &lt;em&gt;MessageProviders&lt;/em&gt;. This project references both the &lt;em&gt;System.ComponentModel.Composition &lt;/em&gt;assembly as well as the add-in assembly (so it can use the &lt;font face="courier new"&gt;IMessageProvider&lt;/font&gt; type). Importantly, the add-in assembly does not reference the &lt;em&gt;MessageProviders &lt;/em&gt;assembly. The MEF catalog ties the two together for us. Also, you could imagine that the &lt;font face="courier new"&gt;IMessageProvider&lt;/font&gt; interface could be in a standalone assembly, so that the add-in assembly and &lt;em&gt;MessageProviders&lt;/em&gt; assembly don't need to reference each other. &lt;/p&gt;

&lt;p&gt;I added another message provider to the new project: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;[Export(typeof(IMessageProvider))]
public class ExternalMessageProvider : IMessageProvider
{
    public string Message
    {
        get { return &amp;quot;A message provider in an external assembly.&amp;quot;; }
    }
}&lt;/pre&gt;

&lt;p&gt;Then I ensured the build script copied the output of this new project to the add-in's directory. I hit F5 and things just worked: &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/SaQzciZoDrI/AAAAAAAABMU/XVkY1h1fYDA/s1600-h/image14.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SaQzdP9mpbI/AAAAAAAABMY/C9E11CtMGf8/image_thumb8.png?imgmax=800" width="669" height="122" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Both message providers were found by MEF running in the context of a MAF add-in. &lt;/p&gt;

&lt;p&gt;To me, one of the benefits of achieving isolation with MAF is that add-in authors are free to use whatever technology they want to meet the needs of their add-in. If they need dependency injection, the host has not imposed on their choice. They can use Unity, StructureMap, autofac, ObjectBuilder or whatever best suits them. And if they need composition, they can use MEF. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/maf_and_mef/MAFandMEF.zip"&gt;Download the Solution&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-379459956155703638?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/379459956155703638/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=379459956155703638' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/379459956155703638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/379459956155703638'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/02/maf-and-mef.html' title='MAF and MEF'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_i_HIkiy_ogI/SaQzb_ZHXqI/AAAAAAAABMQ/huHiJhlhElI/s72-c/image_thumb5.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-4724010816698996383</id><published>2009-02-05T20:09:00.001Z</published><updated>2011-09-03T18:02:56.616+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Code Locali[zs]ation</title><content type='html'>&lt;p&gt;Not too long ago I was sitting at my painfully uncomfortable work desk minding my own business when I sensed a presence over my left shoulder. Turning, I discovered one of my managers staring intently at my screen. &lt;/p&gt;  &lt;p&gt;&amp;quot;I hope you're going to rename that&amp;quot;, he said, pointing at my monitor. He was referring to a method I had named &amp;quot;Synchronize&amp;quot;. &amp;quot;We spell that with an 's' here&amp;quot;, he stated, perhaps forgetting that Australians share British spelling - or perhaps forgetting that I was Australian. &lt;/p&gt;  &lt;p&gt;Assuming that he was joking, I smiled and chuckled. &amp;quot;I'm serious&amp;quot;, he said. &lt;/p&gt;  &lt;p&gt;And he was. &lt;/p&gt;  &lt;p&gt;And I was flummoxed. &lt;/p&gt;  &lt;p&gt;Looking through my team's code base I found that they are indeed using the &lt;a href="http://en.wikipedia.org/wiki/Queen%27s_English"&gt;Queen's English&lt;/a&gt; in naming their methods and types. I completely disagree with this decision. This post serves as a reference for my reasoning, and as something I can point future colleagues to. &lt;/p&gt;  &lt;p&gt;The reason is really simple, actually: consistency. For better or worse, all Windows and .NET APIs are in American English. The last thing I want to see in a code base is this: &lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;public class MyClass
{
    private SomeComponent _component;

    public void Initialise()
    {
        _component.Initialize();
    }
} &lt;/pre&gt;

&lt;p&gt;Since &lt;font face="courier new"&gt;SomeComponent&lt;/font&gt; was developed by those who conform with the status quo, the code has inconsistent spelling. It's inevitable, confusing and sloppy. &lt;/p&gt;

&lt;p&gt;We have coding conventions to &lt;em&gt;reduce &lt;/em&gt;inconsistencies in code bases. In the interests of said consistency, one of your coding convention should be to use American English. Indeed, I suspect the framework design guidelines state this, but I do not have a copy of the book to confirm. &lt;/p&gt;

&lt;p&gt;In saying all this, I can't help but picture my Mum and my high school English teacher - Mr. Butler - standing sternly in front of me, scolding me for my unpatriotic attitude.&lt;/p&gt;

&lt;p&gt;Mum, you will always be my &amp;quot;Mum&amp;quot; and never my &amp;quot;Mom&amp;quot;, unless you run my software in the US. And if you ever read my code I warn you now that you will see names such as &amp;quot;Initialize&amp;quot;, &amp;quot;Synchronize&amp;quot;, and &amp;quot;Color&amp;quot;. You can scold me only if those spellings surface in the user interface. &lt;/p&gt;

&lt;p&gt;Mr. Butler, you practically accused me of cheating in front of my entire year 11 class, so I make no apologies†.&lt;/p&gt;

&lt;p&gt;Anyway, my point is that coding in anything other than American English will make your code base inconsistent and harder to maintain. We switch contexts when communicating all the time (think SMS and IM where a whole different lexicon applies), so we should be able to switch context when communicating in code. No biggie, but it makes a big difference to the resultant code. &lt;/p&gt;

&lt;p&gt;† Just in case someone takes this too seriously, I will point out that Mr. B was one of the best teachers I ever had. This was a very rare black mark against his name. I had received 98% for my essay on &lt;a href="http://en.wikipedia.org/wiki/Animal_Farm"&gt;Animal Farm&lt;/a&gt;. After congratulating me, he mentioned how similar it was to my sister's effort of two years past, and asked me pointedly whether I had copied it. I hadn't. Indeed, I didn't even know my sister had written an essay on the same topic. I think it far more likely that my sis is a cyborg and she travelled back in time to copy my essay. I will have to ask her about that.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-4724010816698996383?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/4724010816698996383/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=4724010816698996383' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4724010816698996383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4724010816698996383'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2009/02/code-localizsation.html' title='Code Locali[zs]ation'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-5056323880734162508</id><published>2008-12-28T22:03:00.001Z</published><updated>2008-12-28T22:03:00.866Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Game'/><category scheme='http://www.blogger.com/atom/ns#' term='PS3'/><title type='text'>Things I don’t like about Little Big Planet</title><content type='html'>  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-5056323880734162508?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/5056323880734162508/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=5056323880734162508' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/5056323880734162508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/5056323880734162508'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/12/things-i-dont-like-about-little-big.html' title='Things I don’t like about Little Big Planet'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-7569395244248933746</id><published>2008-12-24T17:24:00.001Z</published><updated>2011-09-03T18:04:11.226+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Game'/><category scheme='http://www.blogger.com/atom/ns#' term='Free'/><title type='text'>Kentis</title><content type='html'>&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/kentis/Kentis.zip"&gt;Download&lt;/a&gt; (zip)     &lt;br /&gt;&lt;a href="http://www.users.on.net/~kentcb/kentis/Kentis.exe"&gt;Download&lt;/a&gt; (exe)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;a href="http://lh5.ggpht.com/_i_HIkiy_ogI/SfIx2AbiQOI/AAAAAAAABNk/LZuczHm7XDw/s1600-h/image3%5B1%5D.png"&gt;&lt;img style="border-right-width: 0px; margin: 0px 0px 0px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="right" src="http://lh6.ggpht.com/_i_HIkiy_ogI/SVJviP5HrQI/AAAAAAAABNo/yoFybvWq_mU/image3_thumb.png?imgmax=800" width="240" height="180" /&gt;&lt;/a&gt;Introduction&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Kentis is a Tetris clone that I wrote back in 2004 whilst in hospital awaiting the birth of my daughter. It is packaged as a single executable that you can download from either of the links above.&lt;/p&gt;  &lt;p&gt;Kentis attempts to remain true to the original game-play, but with an added arcade feel.&lt;/p&gt;  &lt;p&gt;If you have any recommendations for how the game can be improved, or if you are able to provide feedback on whether the game works on any additional platforms, please do so in the comments.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_i_HIkiy_ogI/SVJwJG5nGoI/AAAAAAAABNw/S83Dav8Wklw/s1600-h/image19%5B1%5D.png"&gt;&lt;img style="border-right-width: 0px; margin: 0px 10px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="left" src="http://lh4.ggpht.com/_i_HIkiy_ogI/SVJwLE3dJzI/AAAAAAAABN4/AkVgjKdRuDA/image19_thumb.png?imgmax=800" width="240" height="180" /&gt;&lt;/a&gt; &lt;strong&gt;Score System&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The scoring system in Kentis favors those who place blocks faster, and eliminate more lines in one move.&lt;/p&gt;  &lt;p&gt;The descent speed of blocks can be increased by pressing the down arrow. A block can be dropped immediately by pressing the space key. The faster you drop a block, the greater your score will be for that move. And the greater your current level, the greater your score will be.&lt;/p&gt;  &lt;p&gt;For example, suppose it takes you 1 second to place and drop a block. If you’re on level 1, you will score 12 points. If you’re on level 2, you will score 15 points. If you’re on level 9, you will score 27 points.&lt;/p&gt;  &lt;p&gt;For each block you place, you will get an additional score if you clear rows with that block. When clearing rows, the score increases exponentially with the number of rows you clear, and linearly with your current level. For example, if you’re on level 1, you will score an extra 46 points for clearing a single row. But if you clear 2 rows in one move, you will score an extra 58 points, and clearing 4 rows will earn you 202 points. Clearing 4 rows whilst on level 9 will earn you a whopping 1010 points – and that’s in addition to your block score.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_i_HIkiy_ogI/SVJwNqSc64I/AAAAAAAABN8/YX4IVZlufpQ/s1600-h/image59%5B1%5D.png"&gt;&lt;img style="border-right-width: 0px; margin: 0px 0px 0px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="right" src="http://lh4.ggpht.com/_i_HIkiy_ogI/SVJwO6AeHRI/AAAAAAAABOE/qKlAEHo017U/image59_thumb.png?imgmax=800" width="240" height="180" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Options&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Kentis includes a number of options that allow you to challenge yourself further as you increase your skill at playing the game. The table below gives a brief description of each option.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;table border="1" cellspacing="0" cellpadding="2" width="568"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="135"&gt;&lt;strong&gt;Option&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="117"&gt;&lt;strong&gt;Values&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="314"&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="135"&gt;Sound&lt;/td&gt;        &lt;td valign="top" width="117"&gt;On          &lt;br /&gt;Off&lt;/td&gt;        &lt;td valign="top" width="314"&gt;Turns sound on and off.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="135"&gt;Rubbish Rows&lt;/td&gt;        &lt;td valign="top" width="117"&gt;0 – 10&lt;/td&gt;        &lt;td valign="top" width="314"&gt;Determines the number of rows that will be filled with random “rubbish” at the start of each game. Rubbish is colored gray and can be cleared just like any other block color.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="135"&gt;Rubbish Frequency&lt;/td&gt;        &lt;td valign="top" width="117"&gt;10% – 90%&lt;/td&gt;        &lt;td valign="top" width="314"&gt;Determines how frequent the rubbish will be in the rubbish rows. Rubbish is more challenging if it is sparse and covers many rows.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="135"&gt;Starting Level&lt;/td&gt;        &lt;td valign="top" width="117"&gt;0 – 9&lt;/td&gt;        &lt;td valign="top" width="314"&gt;Determines what level you start each game on.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="135"&gt;Block Types&lt;/td&gt;        &lt;td valign="top" width="117"&gt;Standard          &lt;br /&gt;Standard + Extra           &lt;br /&gt;You’re Crazy!&lt;/td&gt;        &lt;td valign="top" width="314"&gt;Determines what blocks you will be playing with. The extra blocks are challenging enough. The crazy setting is just . . . crazy.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="135"&gt;Block Preview&lt;/td&gt;        &lt;td valign="top" width="117"&gt;On          &lt;br /&gt;Off&lt;/td&gt;        &lt;td valign="top" width="314"&gt;Determines whether you will be given a preview of the upcoming block.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="135"&gt;Block Color&lt;/td&gt;        &lt;td valign="top" width="117"&gt;Fixed          &lt;br /&gt;Random&lt;/td&gt;        &lt;td valign="top" width="314"&gt;Determines whether block colors are fixed for each type of block, or whether random colors are assigned to each new block.&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Operating System: Windows XP (98, 2000, and Vista are as yet untested)    &lt;br /&gt;RAM: Minimal (tested on 128MB)     &lt;br /&gt;HDD: 2MiB     &lt;br /&gt;Graphics/Audio: Pretty much anything&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Version History&lt;/strong&gt;&lt;/p&gt;                                                                          &lt;p&gt;&lt;em&gt;December 2008&lt;/em&gt; : Updated to use resource compression and cut executable size from over 12MiB to under 2MiB.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;January 2005 &lt;/em&gt;: Original release on &lt;a href="http://www.gamedev.net/"&gt;gamedev.net&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-7569395244248933746?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/7569395244248933746/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=7569395244248933746' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7569395244248933746'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7569395244248933746'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/12/kentis.html' title='Kentis'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_i_HIkiy_ogI/SVJviP5HrQI/AAAAAAAABNo/yoFybvWq_mU/s72-c/image3_thumb.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-7448845078540897353</id><published>2008-12-24T17:18:00.001Z</published><updated>2008-12-24T17:18:58.463Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Game'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++/Assembly'/><title type='text'>Kentis Update</title><content type='html'>&lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px; border-right-width: 0px" height="67" alt="image" src="http://lh5.ggpht.com/_i_HIkiy_ogI/SVJu7BpakNI/AAAAAAAABKQ/p-FrtqHSkBk/image29.png?imgmax=800" width="70" align="right" border="0" /&gt; I’m on leave at the moment and was looking for something a little different to occupy me. To that end, I spent some time over the past couple of days adding resource compression to Kentis. This took the download size from 12.3MiB down to 1.9MiB, so it was certainly worth it!&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Kentis used to be hosted on &lt;a href="http://www.gamedev.net"&gt;GameDev.net&lt;/a&gt;, but in attempting to update my project I found out my membership had expired (no surprise really, given how long it’s been). I was willing to part with a few quid until I saw that their preferred payment method is &lt;a href="http://www.paypalsucks.com/"&gt;PayPal&lt;/a&gt;, which I hate with the heat of a thousand suns. Therefore, I’ll be hosting it myself, and I’ll provide the details in my next blog post.&lt;/p&gt;  &lt;p&gt;For now, however, I just want to discuss the improvements I made.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Image Compression&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Previously in Kentis I was using solely bitmaps as my graphic resources. As far as storage efficiency goes, that’s pretty much the worst possible choice. The reason I was using them was for simplicity – I didn’t have to do any conversion in order to consume them in my game because &lt;a href="http://en.wikipedia.org/wiki/DirectX"&gt;DirectX&lt;/a&gt; understands bitmaps directly (I’m using DirectX 7, which does not support JPEGs or PNGs natively).&lt;/p&gt;  &lt;p&gt;I have two basic image types in my game: backgrounds and sprites. The backgrounds are large, complex in color, don’t require transparency, and can be stored in a &lt;a href="http://en.wikipedia.org/wiki/Lossy"&gt;lossy&lt;/a&gt; format. The sprites are smaller, have far fewer colors and gradients, &lt;em&gt;do &lt;/em&gt;require transparency, and must be stored in a &lt;a href="http://en.wikipedia.org/wiki/Lossless"&gt;lossless&lt;/a&gt; format. &lt;a href="http://en.wikipedia.org/wiki/JPEG"&gt;JPEG&lt;/a&gt; compression is perfectly suited to storing the backgrounds, and &lt;a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics"&gt;PNG&lt;/a&gt; is the best candidate for the sprites.&lt;/p&gt;  &lt;p&gt;My first foray into providing a solution was to use the &lt;a href="http://www.ijg.org/"&gt;ijp&lt;/a&gt; libraries. However, I couldn’t even get the simplest of console applications to decode a JPEG without the &lt;font face="Courier New"&gt;jpeg_read_header()&lt;/font&gt; function throwing an access violation. I never did figure out why, so perhaps I’ll post on &lt;a href="http://www.stackoverflow.com"&gt;stackoverflow&lt;/a&gt; later to see if anyone can shed some light.&lt;/p&gt;  &lt;p&gt;Anyway, ijp would only be a partial solution because it only supports JPEGs – not PNGs. So I turned my attention to a windows API called &lt;a href="http://msdn.microsoft.com/en-us/library/ms532289(VS.85).aspx"&gt;StretchDIBits()&lt;/a&gt;. This API should allow you to copy a bitmap, JPEG or PNG to a device context (DC). Long story short, I couldn’t get it to work and I’ll come back to my theory why in a minute.&lt;/p&gt;  &lt;p&gt;At this point I was getting a little tired of not getting anywhere. I was about to give up and go and watch &lt;a href="http://en.wikipedia.org/wiki/Band_of_brothers"&gt;Band of Brothers&lt;/a&gt; on Blu-ray when I happened upon the &lt;a href="http://www.codeproject.com/KB/graphics/cximage.aspx"&gt;CxImage&lt;/a&gt; library on CodeProject. It looked like a good alternative to the &lt;font face="Courier New"&gt;StretchDIBits()&lt;/font&gt; API, so I thought I’d give it a whirl. I had to fix some things first though. For one, the projects were not set up with the correct runtime library settings. Secondly, when I tried disabling functionality I didn’t need (such as extra graphic formats, layers, and encoding support) it no longer compiled.&lt;/p&gt;  &lt;p&gt;After I got it to compile and link with Kentis, I again ran into problems. I don’t remember the manifestation of the problem, but the point is I spent a good 4 or 5 hours scrutinizing and debugging my code. I eventually tracked down the problem to my .rc file (resource script). Visual Studio had gotten confused somehow when I was making changes to my resources and this file was far from correct. I updated it by hand and recompiled and relinked. Success!&lt;/p&gt;  &lt;p&gt;I suspect the problem with the .rc file also prevented the &lt;font face="Courier New"&gt;StretchDIBits()&lt;/font&gt; API from working. I think I’ll test this theory a little later, because it would be good to reduce the binary size even further. CxImage is a fantastic library, but it has way more functionality than I need. I spent a good amount of time getting it down to a minimum, but getting rid of the dependency altogether may yield even better results.&lt;/p&gt;  &lt;p&gt;Anyway, I managed to shave off roughly 4MiB from the executable size by compressing the graphics.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Audio Compression&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_i_HIkiy_ogI/SVJu7kW0PYI/AAAAAAAABKU/vMtD6n-0BrQ/s1600-h/image24.png"&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 15px 0px 0px; border-right-width: 0px" height="347" alt="image" src="http://lh5.ggpht.com/_i_HIkiy_ogI/SVJu_U0xYqI/AAAAAAAABKY/6GeVBXrTZ64/image_thumb12.png?imgmax=800" width="250" align="left" border="0" /&gt;&lt;/a&gt;All the audio in Kentis was stored in &lt;a href="http://en.wikipedia.org/wiki/WAV"&gt;WAVE&lt;/a&gt; format. Again, this was to avoid any decoding steps but came at the cost of significant storage space. Unlike graphics, all the audio could be encoded in a lossy format.&lt;/p&gt;  &lt;p&gt;I settled on &lt;a href="http://en.wikipedia.org/wiki/Ogg_vorbis"&gt;Ogg Vorbis&lt;/a&gt; as the format. I converted each of my .wav files to .ogg files, incorporated the ogg and vorbis libraries into my code base, and updated parts of game’s audio layer to do the decoding.&lt;/p&gt;  &lt;p&gt;It all went rather well. The only hiccup was that the decoding time for the music tracks was excessive (around 2-3 seconds). I tracked down the problem to resizing of a &lt;font face="Courier New"&gt;vector&amp;lt;char&amp;gt;&lt;/font&gt; I was storing the decoded data in. Even a single resize was costing a lot of time. Therefore, I put in a call to &lt;a href="http://www.cplusplus.com/reference/stl/vector/reserve.html"&gt;vector::reserve()&lt;/a&gt; and an assertion that would let me know if resizing ever occurs in the vector.&lt;/p&gt;  &lt;p&gt;Compressing the audio took off a further 6MiB or so off the executable size.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;What next?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;My goals for these changes were simple: reduce the executable size without affecting functionality at all. I did remove one of the five backgrounds (because the contrast was poor) and two short sounds (because the vorbis libraries didn’t like the sampling rate) but other than that, it is functionally identical to the previous 12.3MiB executable.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;I am toying with the idea of doing other updates or doing a different game entirely, but haven’t decided on anything yet.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-7448845078540897353?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/7448845078540897353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=7448845078540897353' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7448845078540897353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/7448845078540897353'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/12/kentis-update.html' title='Kentis Update'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_i_HIkiy_ogI/SVJu7BpakNI/AAAAAAAABKQ/p-FrtqHSkBk/s72-c/image29.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-2904171289857358330</id><published>2008-11-08T11:43:00.001Z</published><updated>2011-09-03T18:05:54.681+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>Visual Studio: Referencing the Same Assembly Multiple Times</title><content type='html'>&lt;p&gt;At work I have the somewhat esoteric requirement of referencing multiple versions of the same assembly from a consuming assembly. The reason why I need to do this is superfluous to this post and I won’t be elaborating on that. It’s the &lt;em&gt;how&lt;/em&gt; that is the topic of this post. Regardless of &lt;em&gt;why &lt;/em&gt;you need to reference the same assembly multiple times, this post should help you do so if you run into issues. &lt;/p&gt;      &lt;p&gt;The first thing you might try is simply adding a reference via Visual Studio’s &lt;em&gt;Add Reference…&lt;/em&gt; dialog. However, you’ll get an error if you do this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;A reference to 'C:\Sample\Lib\Example.Model.dll' could not be added. A reference to the component &lt;strong&gt;'Example.Model'&lt;/strong&gt; already exists in the project.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;As highlighted in the error message, Visual Studio uses only the assembly (or project) name to identify references. Therefore, the version of the assembly does not help to disambiguate the reference.&lt;/p&gt;  &lt;p&gt;The C# compiler (&lt;em&gt;csc.exe&lt;/em&gt;) has a &lt;code&gt;/reference&lt;/code&gt; switch to supply references that takes the following format (from &lt;a href="http://msdn.microsoft.com/en-us/library/yabyz3h4.aspx"&gt;MSDN&lt;/a&gt;):&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre&gt;/reference:[alias=]filename&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice that an alias can be optionally supplied. Further down in the MSDN documentation you will read:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Sometimes it is necessary to reference two different versions of the same component from within one assembly. To do this, use the alias suboption on the &lt;b&gt;/reference&lt;/b&gt; switch for each file to distinguish between the two files. This alias will be used as a qualifier for the component name, and will resolve to the component in one of the files.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To be clear, the C# compiler &lt;em&gt;does &lt;/em&gt;allow us to reference different versions of the same assembly. Those references just need different aliases to disambiguate them.&lt;/p&gt;

&lt;p&gt;Cracking open the Visual Studio project file for our consuming assembly, we find something like this:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;Reference Include=&amp;quot;Example.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8c3ef16ce2e2f88d, processorArchitecture=MSIL&amp;quot;&amp;gt;
    &amp;lt;HintPath&amp;gt;..\Lib\2\Example.Model.dll&amp;lt;/HintPath&amp;gt;
    &amp;lt;Private&amp;gt;False&amp;lt;/Private&amp;gt;
&amp;lt;/Reference&amp;gt; &lt;/pre&gt;

&lt;p&gt;Thankfully, the Visual Studio limitation can be overcome simply by editing the project file directly. So we can add a reference to version 2 of our assembly with a simple copy, paste and edit:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;Reference Include=&amp;quot;Example.Model, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8c3ef16ce2e2f88d, processorArchitecture=MSIL&amp;quot;&amp;gt;
    &amp;lt;HintPath&amp;gt;..\Lib\1\Example.Model.dll&amp;lt;/HintPath&amp;gt;
    &amp;lt;Private&amp;gt;False&amp;lt;/Private&amp;gt;
    &amp;lt;Aliases&amp;gt;legacy2&amp;lt;/Aliases&amp;gt; &amp;lt;/Reference&amp;gt;&amp;lt;Reference Include=&amp;quot;Example.Model, Version=3.0.0.0, Culture=neutral, PublicKeyToken=8c3ef16ce2e2f88d, processorArchitecture=MSIL&amp;quot;&amp;gt;
    &amp;lt;HintPath&amp;gt;..\Lib\1\Example.Model.dll&amp;lt;/HintPath&amp;gt;
    &amp;lt;Private&amp;gt;False&amp;lt;/Private&amp;gt;
    &amp;lt;Aliases&amp;gt;legacy3&amp;lt;/Aliases&amp;gt; &amp;lt;/Reference&amp;gt; &lt;/pre&gt;

&lt;p&gt;Notice how we’ve added the alias to differentiate the two references in the code. When we load such a project file in Visual Studio, it gives us a warning indicator next to any references it considers to be duplicates:&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SRV7VEiZkdI/AAAAAAAABKM/g2bXoTmyhDQ/image14.png?imgmax=800" width="249" height="239" /&gt; &lt;/p&gt;

&lt;p&gt;However, rather than complaining about these at build time, it simply passes the details of these references onto the C# compiler and lets it sort things out:&lt;/p&gt;

&lt;p&gt;&lt;font face="Courier New"&gt;csc.exe 
    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; /reference:legacy2=..\Lib\2\Example.Model.dll 

    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; /reference:legacy3=..\Lib\3\Example.Model.dll…&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;As such, we can consume the referenced assemblies as follows:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;extern alias legacy1;
extern alias legacy2;
extern alias legacy3;

namespace ConsumingLibrary
{
    public static class Consumer
    {
        public static void CreateInstances()
        {
            //version 2 of SomeClass
            var v2 = new legacy2::Model.SomeClass();
            v2.SomeProperty = &amp;quot;test&amp;quot;;

            //version 3 of SomeClass
            var v3 = new legacy3::Model.SomeClass();
            v3.SomeProperty = &amp;quot;test&amp;quot;;
            v3.SomeOtherProperty = &amp;quot;test&amp;quot;;
        }
    }
}&lt;/pre&gt;

&lt;p&gt;The &lt;font face="Courier New"&gt;extern alias&lt;/font&gt; keyword allows us to pull in the types defined by the assemblies that have been assigned aliases outside of the default “global” alias. Thereafter, we can qualify types with those aliases as per the above example, or even use those aliases to qualify &lt;font face="Courier New"&gt;using&lt;/font&gt; directives:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;using legacy2::Model;&lt;/pre&gt;

&lt;p&gt;One thing to look out for with all this, is that WPF projects don’t seem to like it. If you add these multiple references to a WPF project the compiler seems to pick one of the references at random and ignores the rest.&lt;/p&gt;

&lt;p&gt;Further to this, the only way I could get &lt;em&gt;consistent &lt;/em&gt;behavior from the &lt;code&gt;AppDomain.AssemblyResolve&lt;/code&gt; event was to separate the consumer into its own library. The entry point to the application attaches a handler to the aforementioned event and then calls into the consuming library to construct the types. Attempting to combine these two activities into the same assembly (even in separate types) would result in the event not always being fired.&lt;/p&gt;

&lt;p&gt;Finally, Visual Studio sometimes has trouble providing Intellisense in these scenarios. And sometimes it erroneously places squiggly compile errors where it shouldn’t. Sometimes you just have to ignore them and build.&lt;/p&gt;

&lt;p&gt;To see this all in action, you can download the little sample I put together &lt;a href="http://www.users.on.net/~kentcb/AliasedReferenceSample.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-2904171289857358330?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/2904171289857358330/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=2904171289857358330' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2904171289857358330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2904171289857358330'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/11/visual-studio-referencing-same-assembly.html' title='Visual Studio: Referencing the Same Assembly Multiple Times'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_i_HIkiy_ogI/SRV7VEiZkdI/AAAAAAAABKM/g2bXoTmyhDQ/s72-c/image14.png?imgmax=800' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-4803916243034251320</id><published>2008-11-06T19:40:00.001Z</published><updated>2011-09-03T18:07:01.840+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Using ComboBox.Text as a Hint</title><content type='html'>&lt;p&gt;At work I was after a quick-and-dirty way to get a &lt;code&gt;ComboBox&lt;/code&gt; to show some hint text like this:&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_i_HIkiy_ogI/SRNILdXNTjI/AAAAAAAABKI/ZaFwvDcGUbw/image4.png?imgmax=800" width="107" height="21" /&gt; &lt;/p&gt;  &lt;p&gt;When the user chooses an item, I want to kick off a task but &lt;em&gt;leave the &lt;code&gt;ComboBox&lt;/code&gt; exactly as it was &lt;/em&gt;(including the hint text). I know there are nicer ways to achieve this by customizing the &lt;code&gt;ComboBox&lt;/code&gt; template or by using a different control entirely, but I was integrating this with a third-party ribbon control that precluded any fancy stuff.&lt;/p&gt;    &lt;p&gt;The &lt;code&gt;ComboBox&lt;/code&gt; control has a &lt;code&gt;Text&lt;/code&gt; property that MSDN explains as follows:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;When the &lt;code&gt;IsEditable&lt;/code&gt; property is &lt;code&gt;true&lt;/code&gt;, setting this property places initial text entered in the text box.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;My &lt;code&gt;ComboBox&lt;/code&gt; is editable to ensure the &lt;code&gt;Text&lt;/code&gt; property is displayed, but is read-only to ensure that the user cannot type any text themselves. What MSDN fails to explain is what constitutes “initial”. Is it a one-off thing? Does “initial” mean when there is no selected item?&lt;/p&gt;                  &lt;p&gt;My first attempt at resetting the &lt;code&gt;ComboBox&lt;/code&gt; after a selection was made looked something like this:&lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;_comboBox.SelectionChanged += delegate
{
    if (_comboBox.SelectedIndex == -1)
    {
        return;
    }

    _comboBox.SelectedIndex = -1;
    _comboBox.Text = &amp;quot;Select an Item&amp;quot;;
};&lt;/pre&gt;

&lt;p&gt;Alas, setting the &lt;code&gt;Text&lt;/code&gt; property had no effect. The &lt;code&gt;ComboBox&lt;/code&gt; would just appear blank after this code executed. Even if I completely reset the &lt;code&gt;ComboBox&lt;/code&gt; bindings and properties, it still refused to display the value of the &lt;code&gt;Text&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;I was beginning to think the MSDN documentation was accurate, if a little lacking. It &lt;em&gt;did &lt;/em&gt;seem as if the &lt;code&gt;Text&lt;/code&gt; property would only be used once prior to the user making a selection. Thereafter, it did not seem to take effect.&lt;/p&gt;

&lt;p&gt;On a hunch, I decided to try setting the &lt;code&gt;Text&lt;/code&gt; property in a separate message:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;_comboBox.SelectionChanged += delegate
{
    if (_comboBox.SelectedIndex == -1)
    {
        return;
    }

    _comboBox.SelectedIndex = -1;
    Dispatcher.BeginInvoke(new ThreadStart(delegate
    {
        _comboBox.Text = &amp;quot;Select an Item&amp;quot;;
    }));
};&lt;/pre&gt;

&lt;p&gt;That did the trick. The &lt;code&gt;ComboBox&lt;/code&gt; now correctly displays the &lt;code&gt;Text&lt;/code&gt; property after the user selects an item. This seems like something of a bug to me, but I haven’t really investigated further.&lt;/p&gt;

&lt;p&gt;You may wonder whether it’s necessary for us to set the &lt;code&gt;SelectedIndex&lt;/code&gt; to &lt;code&gt;-1&lt;/code&gt; anymore. It probably isn’t because your hint text is unlikely to match selectable items in the &lt;code&gt;ComboBox&lt;/code&gt;. However, if there happens to be a selectable item with the same value as the &lt;code&gt;Text&lt;/code&gt; property, setting the &lt;code&gt;Text&lt;/code&gt; property will select that item and affect &lt;code&gt;SelectedIndex&lt;/code&gt; accordingly. That may or may not be a problem in your scenario. Better to be safe than sorry, I figure…&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-4803916243034251320?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/4803916243034251320/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=4803916243034251320' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4803916243034251320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4803916243034251320'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/11/using-comboboxtext-as-hint.html' title='Using ComboBox.Text as a Hint'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_i_HIkiy_ogI/SRNILdXNTjI/AAAAAAAABKI/ZaFwvDcGUbw/s72-c/image4.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-657016787824289600</id><published>2008-11-03T19:53:00.001Z</published><updated>2008-11-03T19:53:40.746Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Family'/><category scheme='http://www.blogger.com/atom/ns#' term='London'/><title type='text'>New Place</title><content type='html'>&lt;p&gt;A couple of weeks ago we moved from &lt;a href="http://en.wikipedia.org/wiki/Woolwich"&gt;Woolwich&lt;/a&gt; to &lt;a href="http://en.wikipedia.org/wiki/North_Greenwich"&gt;North Greenwich&lt;/a&gt;, which almost feels like a different country despite being only 30 minutes away. It’s right next to a great park, there’s a shopping center two minutes down the road, and the bus stops on our doorstep to take me on my 15 minute commute to work. Oh, and people are actually &lt;em&gt;nice &lt;/em&gt;in this neighborhood.&lt;/p&gt;  &lt;p&gt;Since the move I’ve been wrestling baffling feats of BT incompetence to get my Internet connection back. Seriously, it was like being stuck in the middle of a scene from &lt;em&gt;&lt;a href="http://www.imdb.com/title/tt0387808/"&gt;Idiocracy&lt;/a&gt;&lt;/em&gt;. The highlight was when a BT operator asked me to urgently call another BT number to correct one of their many mistakes.&lt;/p&gt;  &lt;p&gt;Despite the odds, I’m finally back online and have a bunch of catching up to do. Things aren’t entirely fixed yet (faulty wireless on their “new and improved” router, and extension points in my house aren’t working) but I’ve managed to cobble together something from the bits and bobs of my old router and the master point tucked away in one of the cupboards in our house.&lt;/p&gt;  &lt;p&gt;I have a couple of posts written and saved up during the down-time. Given that a “stay tuned” post is a blogging sin and all, let me give this post some more substance with some photos of our new abode, courtesy of our budding photographer, Tempany:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/SQ9WfK8jJJI/AAAAAAAABJE/VoiSOekhE54/s1600-h/PA2502635.jpg"&gt;&lt;img title="PA250263" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="200" alt="PA250263" src="http://lh6.ggpht.com/_i_HIkiy_ogI/SQ9WflNc_bI/AAAAAAAABJI/lXDe8MwfN1g/PA250263_thumb3.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/SQ9Wg2RwmoI/AAAAAAAABJM/E0Kvb03B_cY/s1600-h/PA2502472.jpg"&gt;&lt;img title="PA250247" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="200" alt="PA250247" src="http://lh6.ggpht.com/_i_HIkiy_ogI/SQ9WhjJEOsI/AAAAAAAABJQ/x72J7ESP1D8/PA250247_thumb.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/SQ9Wi-c4HyI/AAAAAAAABJU/iVvSzCbsvbg/s1600-h/PA2502662.jpg"&gt;&lt;img title="PA250266" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="200" alt="PA250266" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SQ9WjVPSlLI/AAAAAAAABJY/QNIpHGvDRng/PA250266_thumb.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; (the neighbours)&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_i_HIkiy_ogI/SQ9WmGsp6tI/AAAAAAAABJc/Q_FfL9b9CDs/s1600-h/PA2502972.jpg"&gt;&lt;img title="PA250297" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="200" alt="PA250297" src="http://lh5.ggpht.com/_i_HIkiy_ogI/SQ9WmuxHDPI/AAAAAAAABJg/xGBUeELoyNw/PA250297_thumb.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; (decor)&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_i_HIkiy_ogI/SQ9WpQTGmxI/AAAAAAAABJk/o2i2-x6A3SU/s1600-h/PA2503082.jpg"&gt;&lt;img title="PA250308" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="200" alt="PA250308" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SQ9WqbhemvI/AAAAAAAABJo/AZXywUYDYuA/PA250308_thumb.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; (Boris the bear on Tempany’s bed)&lt;/p&gt;  &lt;p&gt;And here are some we took: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_i_HIkiy_ogI/SQ9WsIVEA7I/AAAAAAAABJs/h2niszuYSSM/s1600-h/PA2102092.jpg"&gt;&lt;img title="PA210209" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="200" alt="PA210209" src="http://lh5.ggpht.com/_i_HIkiy_ogI/SQ9WsbsgMXI/AAAAAAAABJw/h8r0_TLt8aU/PA210209_thumb.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; (Modern dishwashers: cute, but unreliable)&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_i_HIkiy_ogI/SQ9Wt-FJKmI/AAAAAAAABJ4/RsS98kz3XJw/s1600-h/PA2703472.jpg"&gt;&lt;img title="PA270347" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="200" alt="PA270347" src="http://lh6.ggpht.com/_i_HIkiy_ogI/SQ9Wuki0XSI/AAAAAAAABJ8/qOGdwtzLxMg/PA270347_thumb.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; (a very sick Tempany, unrelated to previous photo)&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_i_HIkiy_ogI/SQ9WwTgTqhI/AAAAAAAABKA/Jxtr19TFxE0/s1600-h/PB0203482.jpg"&gt;&lt;img title="PB020348" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="260" alt="PB020348" src="http://lh3.ggpht.com/_i_HIkiy_ogI/SQ9Ww9xcwGI/AAAAAAAABKE/ox3HxoRKsJI/PB020348_thumb.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; (all better now, out seeing Disney’s &lt;em&gt;&lt;a href="http://www.visitlondon.com/events/detail/3763374"&gt;Nemo on Ice&lt;/a&gt;&lt;/em&gt;)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-657016787824289600?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/657016787824289600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=657016787824289600' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/657016787824289600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/657016787824289600'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/11/new-place.html' title='New Place'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_i_HIkiy_ogI/SQ9WflNc_bI/AAAAAAAABJI/lXDe8MwfN1g/s72-c/PA250263_thumb3.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-4828758693979641651</id><published>2008-10-04T17:05:00.001+01:00</published><updated>2011-09-03T18:08:42.752+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><title type='text'>Customizing Logical Children</title><content type='html'>&lt;p&gt;WPF’s logical tree is used in providing all kinds of functionality, such as &lt;a href="http://msdn.microsoft.com/en-us/library/ms753197.aspx"&gt;property inheritance&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/ms750613.aspx"&gt;resource resolution&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Yesterday a colleague asked me how to customize the logical children of a control. Basically, he had a control that hosted a collection of child items that aren’t actually visuals. In the XAML, he wanted to be able to bind properties of the children. Kind of like how you can bind to the &lt;code&gt;Height&lt;/code&gt; property of a &lt;code&gt;RowDefinition&lt;/code&gt; in a WPF &lt;code&gt;Grid&lt;/code&gt; control. The &lt;code&gt;RowDefinition&lt;/code&gt; isn’t a &lt;code&gt;Visual&lt;/code&gt;, but it can participate in binding by virtue of being part of the logical tree.&lt;/p&gt;  &lt;p&gt;My initial thought was to override the &lt;font face="Courier New"&gt;FrameworkElement.LogicalChildren&lt;/font&gt; property, but he had already tried that without success. Altering the logical tree is not something I’ve ever had need to do before. Therefore, I decided to try this out for myself and am recording my findings here.&lt;/p&gt;  &lt;p&gt;To test this all out, I created a user control called &lt;code&gt;ArtistsControl&lt;/code&gt; that has an &lt;code&gt;Artists&lt;/code&gt; property containing a collection of &lt;code&gt;Artist&lt;/code&gt; objects. Each &lt;code&gt;Artist&lt;/code&gt; object just has a name. The &lt;code&gt;ArtistsControl&lt;/code&gt; contains a &lt;code&gt;ListBox&lt;/code&gt; that shows each &lt;code&gt;Artist&lt;/code&gt; in the collection.&lt;/p&gt;  &lt;p&gt;I wanted to address the following use cases:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Non-bound &lt;code&gt;Artist&lt;/code&gt; declaration &lt;/li&gt;    &lt;li&gt;&lt;code&gt;Artist&lt;/code&gt; bound to a property on the owning &lt;code&gt;Window&lt;/code&gt; &lt;/li&gt;    &lt;li&gt;&lt;code&gt;Artist&lt;/code&gt; bound to a property on the current &lt;code&gt;DataContext&lt;/code&gt; &lt;/li&gt;    &lt;li&gt;&lt;code&gt;Artist&lt;/code&gt; whose name comes from a statically-resolved resource defined in the owning &lt;code&gt;Window&lt;/code&gt; &lt;/li&gt;    &lt;li&gt;&lt;code&gt;Artist&lt;/code&gt; whose name comes from a dynamically-resolved resource defined in the owning &lt;code&gt;Window&lt;/code&gt; &lt;/li&gt;    &lt;li&gt;     &lt;p&gt;&lt;code&gt;Artist&lt;/code&gt; bound to a property on the owning &lt;code&gt;Window&lt;/code&gt;, but done in the code-behind setting the source of the binding directly&lt;/p&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#808080"&gt;&lt;strong&gt;&lt;font color="#000000"&gt;Aside: &lt;/font&gt;&lt;/strong&gt;&lt;em&gt;The first issue I came up against had nothing to do with the initial problem at all. I wanted to define a user control called ArtistsControl that had a collection property called Artists that could be populated very easily from XAML:&lt;/em&gt;&lt;/font&gt;&lt;/p&gt;    &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;local:ArtistsControl&amp;gt;
    &amp;lt;local:Artist&amp;gt;Powderfinger&amp;lt;/local:Artist&amp;gt;
&amp;lt;/local:ArtistsControl&amp;gt;&lt;/pre&gt;

  &lt;p&gt;&lt;em&gt;&lt;font color="#808080"&gt;However, I kept running into obscure compile errors such as:&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;

  &lt;p&gt;&lt;em&gt;&lt;font color="#808080"&gt;Cannot set content property 'Artists' on element 'ArtistsControl'. 'Artists' has incorrect access level or its assembly does not allow access.&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;

  &lt;p&gt;&lt;em&gt;&lt;font color="#808080"&gt;Long story short, the problem was that my dependency property was of type IList&amp;lt;Artist&amp;gt;. In order for the collection to play nice with XAML, it needs to be a non-generic type (can’t even be a closed generic type). To resolve this I just created my own ArtistCollection type which inherits from ObservableCollection&amp;lt;Artist&amp;gt;. After that, the above XAML snippet worked fine.&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;#1, #4 and #6 all work fine “out-of-the-box”. That makes sense because they don’t rely on the logical tree in any way.&lt;/p&gt;















&lt;p&gt;As I mentioned earlier, the first thing I tried at this point is to override the &lt;code&gt;LogicalTree&lt;/code&gt; property in &lt;code&gt;ArtistsControl&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;protected override IEnumerator LogicalChildren
{
    get
    {
        if (Artists == null)
        {
            yield break;
        }

        foreach (var artist in Artists)
        {
            yield return artist;
        }
    }
}&lt;/pre&gt;

&lt;p&gt;This has the effect of fixing . . . nothing!&lt;/p&gt;

&lt;p&gt;However, I did notice this error in the output window:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;font face="Courier New"&gt;Cannot find governing FrameworkElement or FrameworkContentElement for target element.&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/aff23943-5483-40b2-816b-4ce687bc6bf8/"&gt;led me&lt;/a&gt; to change the base class of &lt;code&gt;Artist&lt;/code&gt; from &lt;code&gt;DependencyObject&lt;/code&gt; to &lt;code&gt;FrameworkElement&lt;/code&gt;. This also did nothing to solve the other use cases. But it did change the error in the output window to:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;font face="Courier New"&gt;Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:Path=Tag; DataItem=null; target element is 'Artist' (Name=''); target property is 'ArtistName' (type 'String')&lt;/font&gt;&lt;/p&gt;

  
&lt;/blockquote&gt;

&lt;p&gt;Hmmm. I have supposedly made the &lt;code&gt;Artist&lt;/code&gt; objects part of the logical tree, so why can they not resolve anything further up the tree?&lt;/p&gt;

&lt;p&gt;I had an epiphany around this point when I realized:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Just because the parent acknowledges the child, that doesn’t mean the child acknowledges the parent.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, just because the &lt;code&gt;Artist&lt;/code&gt; objects are part of the &lt;code&gt;ArtistControl&lt;/code&gt;’s &lt;code&gt;LogicalChildren&lt;/code&gt; collection, that doesn’t mean the &lt;code&gt;Artist&lt;/code&gt; objects have their &lt;code&gt;Parent&lt;/code&gt; property set to the &lt;code&gt;ArtistControl&lt;/code&gt;. The logical tree is a two-way connection: the child is connected to the parent, and the parent is connected to the child.&lt;/p&gt;











&lt;p&gt;So how do we connect the two? &lt;code&gt;FrameworkElement.Parent&lt;/code&gt; is a get-only property, and WPF uses internal methods to alter its value. Fortunately &lt;code&gt;FrameworkElement&lt;/code&gt; defines a couple of methods to help us here: &lt;code&gt;AddLogicalChild()&lt;/code&gt; and &lt;code&gt;RemoveLogicalChild()&lt;/code&gt;. All we need to do is call these methods to add and remove &lt;code&gt;Artist&lt;/code&gt; objects to and from the logical tree.&lt;/p&gt;

&lt;p&gt;Overriding the &lt;code&gt;LogicalChildren&lt;/code&gt; property allows property inheritance to work. The attached sample will still work without it, but any inherited properties will fail to propagate within your custom logical tree unless you also override &lt;code&gt;LogicalChildren&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When all is said and done, all use cases are satisfied and the following XAML works fine:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;local:ArtistsControl ...&amp;gt;
    &amp;lt;local:Artist&amp;gt;The Smashing Pumpkins&amp;lt;/local:Artist&amp;gt;
    &amp;lt;local:Artist ArtistName=&amp;quot;{Binding Tag, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}&amp;quot;/&amp;gt;
    &amp;lt;local:Artist ArtistName=&amp;quot;{Binding Tag}&amp;quot;/&amp;gt;
    &amp;lt;local:Artist ArtistName=&amp;quot;{StaticResource StaticArtistResource}&amp;quot;/&amp;gt;
    &amp;lt;local:Artist ArtistName=&amp;quot;{DynamicResource DynamicArtistResource}&amp;quot;/&amp;gt;
&amp;lt;/local:ArtistsControl&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/logicaltree/LogicalTreeExample.zip"&gt;Download Sample&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-4828758693979641651?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/4828758693979641651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=4828758693979641651' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4828758693979641651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4828758693979641651'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/10/customizing-logical-children.html' title='Customizing Logical Children'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-6683404639906615904</id><published>2008-09-10T20:10:00.001+01:00</published><updated>2008-09-10T20:10:20.998+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Add-in'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><category scheme='http://www.blogger.com/atom/ns#' term='Trac'/><category scheme='http://www.blogger.com/atom/ns#' term='Trac Explorer'/><title type='text'>Installing Trac Explorer</title><content type='html'>&lt;p&gt;Couldn’t find an existing post on this, so I’ll post here with the hope that it will be of some help to others.&lt;/p&gt;  &lt;p&gt;I was playing around with &lt;a href="http://tracexplorer.devjavu.com/?redirectedfrom=WikiStart"&gt;Trac Explorer&lt;/a&gt; (previously known as VSTrac) today, which is a Visual Studio add-in that provides &lt;a href="http://trac.edgewall.org/"&gt;Trac&lt;/a&gt; integration. My initial impression is that it’s pretty cool and if you use Trac in conjunction with Visual Studio I’d recommend checking it out.&lt;/p&gt;  &lt;p&gt;Anyway, I carefully followed the installation guide, only to find that the &lt;em&gt;Trac Explorer &lt;/em&gt;menu item did not appear in my &lt;em&gt;View&lt;/em&gt; menu as it should. Turns out that the suggested installation path is not included by default as an add-in folder in Visual Studio. It’s easy to add any path though.&lt;/p&gt;  &lt;p&gt;Click on Tools/Options and select the Add-in/Macro Security tree item:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="382" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SMgbm2ll7qI/AAAAAAAABJA/6c41yfJTpIU/image%5B5%5D.png?imgmax=800" width="644" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;Then click the &lt;em&gt;Add… &lt;/em&gt;button to add the path that contains the Trac Explorer add-in. Restart Visual Studio and you’re done.&lt;/p&gt;  &lt;p&gt;Incidentally, the &lt;font face="Courier New"&gt;%VSMYDOCUMENTS%\Addins&lt;/font&gt; entry looks promising, but the &lt;font face="Courier New"&gt;VSMYDOCUMENTS&lt;/font&gt; environment variable is undefined in both my VS2008 installations. Odd – perhaps this is a regression issue with VS.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-6683404639906615904?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/6683404639906615904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=6683404639906615904' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/6683404639906615904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/6683404639906615904'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/09/installing-trac-explorer.html' title='Installing Trac Explorer'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/kent.boogaart/SMgbm2ll7qI/AAAAAAAABJA/6c41yfJTpIU/s72-c/image%5B5%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-3565305791845839567</id><published>2008-08-25T16:26:00.001+01:00</published><updated>2008-08-25T16:26:00.582+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSTO'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Office'/><title type='text'>Building VSTO Projects without Visual Studio</title><content type='html'>&lt;p&gt;At work, I recently added a VSTO project to our solution. Predictably, the build server didn’t like it. Less predictably, I found that the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=5E86CAB3-6FD6-4955-B979-E1676DB6B3CB&amp;amp;displaylang=en"&gt;installation package&lt;/a&gt; required to build VSTO projects also required Visual Studio to be installed:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="534" alt="image" src="http://lh3.ggpht.com/kent.boogaart/SLLPBlSuChI/AAAAAAAAAzo/mSTBog4uA-0/image11.png?imgmax=800" width="453" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;My initial thought was that there must be another installer that does &lt;em&gt;not &lt;/em&gt;require VS to be installed. However, after searching high and low I couldn’t find such a beast. I had an MS employee confirm this rather unsavory situation &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3759872&amp;amp;SiteID=1"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Frankly, this blows, since it wastes a VS license and also causes a VS instance to spin up on every build (which is very often when you’re doing CI with multiple projects hosted on the same build server). It just makes CI far messier and costly to set up and run, which is exactly the kind of friction I’d very much prefer to avoid.&lt;/p&gt;  &lt;p&gt;And when you think about it, it’s completely unnecessary. What &lt;em&gt;is &lt;/em&gt;VSTO besides some combination of managed and unmanaged DLLs? Why on earth is VS required to build a VSTO project? Next you’ll tell me I need Office installed on the build server!&lt;/p&gt;  &lt;p&gt;Thankfully, it’s &lt;em&gt;not &lt;/em&gt;required (except by the installer), and this post details how you can set up your build server to build VSTO projects without the overhead of VS. There may be simpler ways (by tricking the installer, for example), but this is how I achieved it.&lt;/p&gt;  &lt;p&gt;To write this post I set up a clean VPC with XP installed. I then created a VSTO project (Excel 2007 add-in) on the host machine and documented the steps necessary to build it on the guest machine. Some of these steps may not be necessary on your build machine (the first two steps in particular) but I’ve listed them here for completeness.&lt;/p&gt;  &lt;p&gt;1. Install the .NET Framework. I used &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=333325fd-ae52-4e35-b531-508d977d32a6&amp;amp;DisplayLang=en"&gt;.NET 3.5 Framework&lt;/a&gt; for the purposes of this post. &lt;/p&gt;  &lt;p&gt;2. Install the .NET SDK. For this post, I used the &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=E6E1C3DF-A74F-4207-8586-711EBE331CDC&amp;amp;displaylang=en"&gt;Windows SDK for 3.5&lt;/a&gt; and only installed the .NET developer tools component. &lt;/p&gt;  &lt;p&gt;Attempting to build at this point obviously yields an error:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New" size="1"&gt;C:\TestAddIn&amp;gt;msbuild TestAddIn.csproj      &lt;br /&gt;Microsoft (R) Build Engine Version 2.0.50727.1433       &lt;br /&gt;[Microsoft .NET Framework, Version 2.0.50727.1433]       &lt;br /&gt;Copyright (C) Microsoft Corporation 2005. All rights reserved. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New" size="1"&gt;C:\TestAddIn\TestAddIn.csproj(180,11): error MSB4019: &lt;strong&gt;The imported project        &lt;br /&gt;&amp;quot;C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\OfficeTools\Microsoft.VisualStudio.Tools.Office.Office2007.target         &lt;br /&gt;s&amp;quot; was not found.&lt;/strong&gt; Confirm that the path in the &amp;lt;Import&amp;gt; declaration is correct, and that the file exists on disk.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;3. Copy the folder &lt;em&gt;C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\OfficeTools&lt;/em&gt; from a developer machine that can build the VSTO project to the same location on the build server. &lt;/p&gt;  &lt;p&gt;Now attempting to build gives us a different set of errors along the lines of:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New" size="1"&gt;ThisAddIn.cs(3,17): error CS0234: The type or namespace name 'VisualStudio' does not exist in the namespace 'Microsoft'      &lt;br /&gt;(&lt;strong&gt;are you missing an assembly reference?&lt;/strong&gt;)       &lt;br /&gt;ThisAddIn.Designer.cs(19,55): error CS0234: The type or namespace name 'Office' does not exist in the namespace 'Microso       &lt;br /&gt;ft' (&lt;strong&gt;are you missing an assembly reference?&lt;/strong&gt;)&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;I think we can answer the question of ‘are you missing an assembly reference?’ with a resounding ‘yes!’. There are obviously a whole bunch of VSTO-related assemblies present on the developer machine that are not yet present on the build server. So how do we get them there?&lt;/p&gt;  &lt;p&gt;We have a couple of choices. One, we could manually copy VSTO assemblies from the developer’s GAC to the build server’s GAC. Two, we could change the project such that it references a &lt;em&gt;copy &lt;/em&gt;of the VSTO assemblies rather than referencing them in the GAC. I opted for the latter approach, because it is more self-contained.&lt;/p&gt;  &lt;p&gt;4. Place a copy of the VSTO assemblies into a &lt;em&gt;Lib &lt;/em&gt;(or similar) directory for your project. Reference these copies rather than those in the GAC. The easiest way to do this is to change the &lt;em&gt;Copy Local &lt;/em&gt;property to true on the existing references, rebuild, copy the assemblies from the build output directory to the &lt;em&gt;Lib &lt;/em&gt;directory, delete the old references, and then re-add the references by using the copies in &lt;em&gt;Lib&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;Now we get:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New" size="1"&gt;C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\OfficeTools\Microsoft.VisualStudio.Tools.Office.Office2007.targets(      &lt;br /&gt;146,9): error MSB4062: &lt;strong&gt;The &amp;quot;VerifyClickOnceSigningSettings&amp;quot; task could not be loaded from the assembly Microsoft.VisualS        &lt;br /&gt;tudio.Tools.Applications.BuildTasks&lt;/strong&gt;, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a. Could not load f       &lt;br /&gt;ile or assembly 'Microsoft.VisualStudio.Tools.Applications.BuildTasks, Version=9.0.0.0, Culture=neutral, PublicKeyToken=       &lt;br /&gt;b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified. Confirm that the &amp;lt;UsingTask&amp;gt; de       &lt;br /&gt;claration is correct, and that the assembly and all its dependencies are available.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Fair enough. VSTO has some custom MSBuild tasks that the &lt;em&gt;.targets &lt;/em&gt;file refers to, but is unable to load. If we crack open the &lt;em&gt;.targets &lt;/em&gt;file we see declarations such as:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New" size="1"&gt;&amp;lt;UsingTask TaskName=&amp;quot;VerifyClickOnceSigningSettings&amp;quot; AssemblyName=&amp;quot;Microsoft.VisualStudio.Tools.Applications.BuildTasks, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&amp;quot; /&amp;gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Since &lt;font face="Courier New"&gt;AssemblyName&lt;/font&gt; is specified (and not &lt;font face="Courier New"&gt;AssemblyFile&lt;/font&gt;), a probe for the assembly is occurring same as it would for an &lt;font face="Courier New"&gt;Assembly.Load()&lt;/font&gt; call. To rectify the situation, we need to . . .&lt;/p&gt;  &lt;p&gt;5. Copy the &lt;em&gt;Microsoft.VisualStudio.Tools.Applications.BuildTasks&lt;/em&gt; assembly from the developer machine to the build machine and register it in the GAC with &lt;em&gt;gacutil.exe&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;6. Do the same for &lt;em&gt;Microsoft.VisualStudio.Tools.Office.BuildTasks&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;We’re getting close now, but there are still some missing assemblies. We could manually GAC them as per step #6, but it turns out all the remaining assemblies are part of the VSTO runtime. Therefore, we can just install the runtime.&lt;/p&gt;  &lt;p&gt;7. Install the VSTO runtime on the build server. Since I’m using Office 2007 in this post, I used the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=54eb3a5a-0e52-40f9-a2d1-eecd7a092dcb&amp;amp;displaylang=en"&gt;VSTO 3 runtime&lt;/a&gt;. See &lt;a href="http://msdn.microsoft.com/en-us/library/bb608603.aspx"&gt;this page&lt;/a&gt; for information on which runtime you require.&lt;/p&gt;  &lt;p&gt;8. Build!&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="15" alt="image" src="http://lh4.ggpht.com/kent.boogaart/SLLPB3D-3zI/AAAAAAAAAzs/GISuUJcdY8c/image%5B4%5D.png?imgmax=800" width="129" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;Yay! Similar steps can be followed for Office 2003 projects (which is what we’re using at work, actually).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-3565305791845839567?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/3565305791845839567/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=3565305791845839567' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3565305791845839567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3565305791845839567'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/08/building-vsto-projects-without-visual.html' title='Building VSTO Projects without Visual Studio'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/kent.boogaart/SLLPBlSuChI/AAAAAAAAAzo/mSTBog4uA-0/s72-c/image11.png?imgmax=800' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-4244343576169886674</id><published>2008-08-25T11:11:00.001+01:00</published><updated>2008-08-25T11:11:00.665+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UK/Europe'/><category scheme='http://www.blogger.com/atom/ns#' term='Family'/><title type='text'>Belfast</title><content type='html'>&lt;p&gt;The first thing that struck me about &lt;a href="http://en.wikipedia.org/wiki/Belfast"&gt;Belfast&lt;/a&gt; was how incredibly neat, consistent, and well laid out it looked from above. The city itself did not disappoint – it was very clean and pretty.&lt;/p&gt;  &lt;p&gt;The night of our arrival we walked around the city center, took a trip on their wheel (like a smaller version of the &lt;a href="http://en.wikipedia.org/wiki/London_eye"&gt;London Eye&lt;/a&gt;), and did some shopping.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/kent.boogaart/SLKEN2t18yI/AAAAAAAAAx4/vQbFcjztw54/s1600-h/P8230036%5B4%5D.jpg"&gt;&lt;img title="P8230036" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P8230036" src="http://lh4.ggpht.com/kent.boogaart/SLKEO8zmp-I/AAAAAAAAAx8/OqVIwnb-CHg/P8230036_thumb%5B2%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SLKERaw-9xI/AAAAAAAAAyA/0YwvXbAhu5o/s1600-h/P8230039%5B4%5D.jpg"&gt;&lt;img title="P8230039" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P8230039" src="http://lh4.ggpht.com/kent.boogaart/SLKER87-1aI/AAAAAAAAAyE/fUahK5nYsD4/P8230039_thumb%5B2%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SLKEZGpLP5I/AAAAAAAAAyI/2nMofCEAOkE/s1600-h/P8230045%5B3%5D.jpg"&gt;&lt;img title="P8230045" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P8230045" src="http://lh3.ggpht.com/kent.boogaart/SLKEaNIse0I/AAAAAAAAAyM/cYpLGkTZXlA/P8230045_thumb%5B1%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SLKEeZWujEI/AAAAAAAAAyQ/jXox6w8K7HM/s1600-h/P8230044%5B3%5D.jpg"&gt;&lt;img title="P8230044" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P8230044" src="http://lh4.ggpht.com/kent.boogaart/SLKEgNfBurI/AAAAAAAAAyU/48EvtPhjj0o/P8230044_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;The next day we visited the Belfast zoo, which is situated not too far from the airport. The weather didn’t hold out for us, but we got to see a lot before the downpour.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SLKEk_rk-KI/AAAAAAAAAyY/Zdc5-A24E58/s1600-h/P8230072%5B3%5D.jpg"&gt;&lt;img title="P8230072" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P8230072" src="http://lh4.ggpht.com/kent.boogaart/SLKEl6EuhzI/AAAAAAAAAyc/Uf9720naqj0/P8230072_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SLKEn0i-YYI/AAAAAAAAAyg/3gwVLXpWEuk/s1600-h/P8230079%5B3%5D.jpg"&gt;&lt;img title="P8230079" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P8230079" src="http://lh6.ggpht.com/kent.boogaart/SLKEpXZCCOI/AAAAAAAAAyk/trKtWKLrgvk/P8230079_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SLKEsOjyTNI/AAAAAAAAAyo/RQ8cXNczC4o/s1600-h/P8230082%5B3%5D.jpg"&gt;&lt;img title="P8230082" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P8230082" src="http://lh6.ggpht.com/kent.boogaart/SLKEtxFMc9I/AAAAAAAAAys/XY0L7OjrnLw/P8230082_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SLKEw-5iQVI/AAAAAAAAAyw/pp9SO01KFik/s1600-h/P8230086%5B3%5D.jpg"&gt;&lt;img title="P8230086" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P8230086" src="http://lh4.ggpht.com/kent.boogaart/SLKEzAkNwxI/AAAAAAAAAy0/m-9QRh-Bwdc/P8230086_thumb%5B1%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SLKE2IC_i3I/AAAAAAAAAy4/1TQfbzpApn4/s1600-h/P8230094%5B3%5D.jpg"&gt;&lt;img title="P8230094" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P8230094" src="http://lh5.ggpht.com/kent.boogaart/SLKE3adxaWI/AAAAAAAAAy8/g5YTnLozuTk/P8230094_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SLKE7vQfWQI/AAAAAAAAAzA/tqBtCWZ8aFE/s1600-h/P8230097%5B3%5D.jpg"&gt;&lt;img title="P8230097" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P8230097" src="http://lh3.ggpht.com/kent.boogaart/SLKE8joaX6I/AAAAAAAAAzE/tUf456REyl0/P8230097_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SLKFBwnDvzI/AAAAAAAAAzI/o-1I-Qg8lUI/s1600-h/P8230111%5B3%5D.jpg"&gt;&lt;img title="P8230111" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P8230111" src="http://lh3.ggpht.com/kent.boogaart/SLKFC8KBFZI/AAAAAAAAAzM/_wPBpcSjcIY/P8230111_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SLKFEgiUE_I/AAAAAAAAAzQ/v0uvYANyZAc/s1600-h/P8230123%5B3%5D.jpg"&gt;&lt;img title="P8230123" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P8230123" src="http://lh5.ggpht.com/kent.boogaart/SLKFFYmthFI/AAAAAAAAAzU/vgpfL1mCmUk/P8230123_thumb%5B1%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SLKFHh5hOyI/AAAAAAAAAzY/n4jVCb8lnwI/s1600-h/P8230125%5B3%5D.jpg"&gt;&lt;img title="P8230125" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P8230125" src="http://lh4.ggpht.com/kent.boogaart/SLKFIhm_NWI/AAAAAAAAAzc/YS6ecWn9jro/P8230125_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;After that, we got to check out &lt;a href="http://en.wikipedia.org/wiki/Carrickfergus_Castle"&gt;Carrickfergus Castle&lt;/a&gt;, albeit briefly and from the comfort of a dry car.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SLKFL9HjrAI/AAAAAAAAAzg/POQ5bG8KP4Q/s1600-h/P8240133%5B3%5D.jpg"&gt;&lt;img title="P8240133" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P8240133" src="http://lh5.ggpht.com/kent.boogaart/SLKFM5VfGII/AAAAAAAAAzk/oYD8DcdTANg/P8240133_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;We also met some of Belinda’s relatives for the first time whilst in Belfast – all &lt;em&gt;very &lt;/em&gt;nice people. I won’t post their photos of course, but if you’re a family member give me a shout and I’d be happy to send them through.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-4244343576169886674?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/4244343576169886674/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=4244343576169886674' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4244343576169886674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4244343576169886674'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/08/belfast.html' title='Belfast'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/kent.boogaart/SLKEO8zmp-I/AAAAAAAAAx8/OqVIwnb-CHg/s72-c/P8230036_thumb%5B2%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-8683202736916170632</id><published>2008-08-09T00:46:00.001+01:00</published><updated>2008-08-09T12:15:33.587+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><category scheme='http://www.blogger.com/atom/ns#' term='London'/><title type='text'>London Underground WPF Demo</title><content type='html'>&lt;p&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="123" alt="image" src="http://lh4.ggpht.com/kent.boogaart/SJ17hXGZEgI/AAAAAAAAAxQ/z8SqS5kqEHU/image%5B22%5D.png?imgmax=800" width="242" align="right" border="0" /&gt; A while back I did an internal presentation for Infusion on WPF – a short crash course to get people interested and familiar with the basics. For it, I wrote a couple of WPF applications, each of which addressed the same use case with a very different interface. The use case was simple enough:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Allow the user to select two London train stations and show shortest route between those stations.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I had grand plans to turn this into a much larger demo based on &lt;a href="http://www.codeplex.com/CompositeWPF"&gt;Composite WPF&lt;/a&gt; (Prism), but unfortunately have never had the time. Instead, I’m just going to post about it here in case anyone is interested in taking a look. First, I’ll briefly describe each of the projects in the solution.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Demo.Domain&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This project contains a very simple domain layer as shown below:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SJzaiSEqaiI/AAAAAAAAAxU/54jesPzIUno/s1600-h/image%5B23%5D.png"&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="215" alt="image" src="http://lh6.ggpht.com/kent.boogaart/SJzakeukD6I/AAAAAAAAAxY/vgO4qtYFFDU/image_thumb%5B12%5D.png?imgmax=800" width="640" border="0" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Any one station exists at a single coordinate and can have any number of lines running through it. It can connect with any number of other stations via a given line. A trip represents a hop from one station to another via a line. That’s pretty much it.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Demo.Service&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This project defines a couple of services that are used by the UI layer.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SJzalpJeXjI/AAAAAAAAAxc/R47RWkB7FmQ/s1600-h/image26%5B1%5D.png"&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="206" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SJzanL5wcLI/AAAAAAAAAxg/E0fRSV5w5Lo/image26_thumb.png?imgmax=800" width="640" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The first service is the data service, which contains all the reference data describing the stations and their connections etcetera.&lt;/p&gt;  &lt;p&gt;The second service – the route service – provides an interface by which callers can determine the shortest route between any two stations. The definition of “shortest” is left up to the specific service implementation. For the purposes of the demo, I wrote a single implementation based on &lt;a href="http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm"&gt;Dijkstra’s algorithm&lt;/a&gt; which used the geographical distance between stations as the edge path cost. In other words, this service will tell you how to get from station A to station B whilst covering the shortest possible distance.&lt;/p&gt;  &lt;p&gt;There’s also a simple service manager in this project, in lieu of anything more sophisticated (which may have been a distraction).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Demo.DataSuck&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This project is just a helper tool. You don’t actually need to run it to see the demo. It takes the XML data file used by the data service and automates Google Earth to locate each station and record its coordinates. It saved me a lot of time because all I needed to do was fill in the &lt;em&gt;Input.xml &lt;/em&gt;file and it would spit out the &lt;em&gt;Data.xml &lt;/em&gt;file used in the service layer, complete with accurate coordinates.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;UI&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;During the presentation, I actually wrote this project whilst explaining what I was doing. It’s a simple UI that allows the user to pick stations from two lists. They can then click on a button and the shortest route is displayed in a third list:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/kent.boogaart/SJzaoXi5XmI/AAAAAAAAAxk/a946KMluVJw/s1600-h/image6%5B1%5D.png"&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="296" alt="image" src="http://lh6.ggpht.com/kent.boogaart/SJzaqUY48wI/AAAAAAAAAxo/yxxkuOpxwxs/image6_thumb.png?imgmax=800" width="640" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;It’s far from perfect, but it demonstrated a number of core WPF concepts such as layout, data binding, commands, and data templating.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Demo.UI.Controls&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This project contains a bunch of controls that are used by the second take on the UI (discussed below). Specifically, there’s a legend (which, for some inexplicable reason, I called “GraphLegend”), a control for showing directions, and a control showing a map.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Demo.Take2&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This stupidly-named project is a second take on the UI that shows a more advanced, WPF-like approach to solving the use case. It uses the geographical information available for each station to position them in 2D space. It draws appropriately-colored lines between stations to represent the train lines. It supports zooming and panning. And the user can simply click on stations to see the shortest route between them, both graphically (see the green highlight) and textually.&lt;/p&gt;  &lt;p&gt;It looks something like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SJzarjU1iqI/AAAAAAAAAxs/cIti-ED-Fg4/s1600-h/image16%5B1%5D.png"&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="390" alt="image" src="http://lh4.ggpht.com/kent.boogaart/SJzauBWH8-I/AAAAAAAAAx0/6NaF-EJDEfY/image16_thumb.png?imgmax=800" width="640" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Like I said, I had grand plans for this, including putting satellite imagery in the background and making the lines more true to form, but you know how it is ;)&lt;/p&gt;  &lt;p&gt;Below, you can download the code as well as a few PowerPoint slides I put together for the presentation. Enjoy!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/london_underground/Demo.pptx"&gt;Download PowerPoint Deck&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://www.users.on.net/~kentcb/london_underground/Demo.zip"&gt;Download Source Code&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-8683202736916170632?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/8683202736916170632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=8683202736916170632' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/8683202736916170632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/8683202736916170632'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/08/london-underground-wpf-demo.html' title='London Underground WPF Demo'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/kent.boogaart/SJ17hXGZEgI/AAAAAAAAAxQ/z8SqS5kqEHU/s72-c/image%5B22%5D.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-6671890241782642557</id><published>2008-08-05T09:27:00.001+01:00</published><updated>2011-09-03T18:09:23.193+01:00</updated><title type='text'>WPF: Disabling Menu Items with Feedback</title><content type='html'>&lt;p&gt;I was listening to &lt;a href="http://itc.conversationsnetwork.org/shows/detail3741.html"&gt;episode 14 of StackOverflow&lt;/a&gt; on the way to work, wherein Joel and Jeff discuss disabling menu items:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;[JOEL] …don't disable menu items that aren't available. Uh, instead, leave them enabled, and that gives you an opportunity to tell people why that particular item was not gonna work.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Further on in the conversation:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;[JOEL] there's obviously a great middle ground here, where you try to disable the menu item somehow, but you still provide some indication as to what would have to be done to enable it, or why it doesn't work.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;WPF lets you do this quite easily:&lt;/p&gt;  &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;MenuItem Header=&amp;quot;StackOverflow&amp;quot; IsEnabled=&amp;quot;False&amp;quot; ToolTip=&amp;quot;You don't know C.&amp;quot; ToolTipService.ShowOnDisabled=&amp;quot;True&amp;quot;/&amp;gt;&lt;/pre&gt;










&lt;p&gt;Obviously you would actually bind the &lt;font face="Courier New"&gt;ToolTip&lt;/font&gt; property so that it varies depending on the &lt;font face="Courier New"&gt;IsEnabled&lt;/font&gt; state of the &lt;font face="Courier New"&gt;MenuItem&lt;/font&gt;. The end result is:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/kent.boogaart/SJgO1s6U6qI/AAAAAAAAAws/hrdLUfmH3Y0/image%5B12%5D.png?imgmax=800" width="194" height="124" /&gt; &lt;/p&gt;



&lt;p&gt;PS. Too short? ;)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-6671890241782642557?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/6671890241782642557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=6671890241782642557' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/6671890241782642557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/6671890241782642557'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/08/wpf-disabling-menu-items-with-feedback.html' title='WPF: Disabling Menu Items with Feedback'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/kent.boogaart/SJgO1s6U6qI/AAAAAAAAAws/hrdLUfmH3Y0/s72-c/image%5B12%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-4736613689380853914</id><published>2008-07-29T10:55:00.001+01:00</published><updated>2011-09-03T18:10:08.850+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XAML'/><title type='text'>ItemsControl as Basis for Pie Chart</title><content type='html'>&lt;p&gt;From &lt;a href="http://www.codeproject.com/KB/WPF/PieChartDataBinding.aspx#"&gt;this excellent article&lt;/a&gt;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;If someone out there can demonstrate how to modify an &lt;code&gt;ItemsControl&lt;/code&gt; so that the items it contains are rendered around a circle to produce a pie chart, I would love to hear from them&lt;/p&gt; &lt;/blockquote&gt;    &lt;p&gt;That’s what I’m going to do in this post.&lt;/p&gt;  &lt;p&gt;The key is to change the &lt;font face="Courier New"&gt;ItemsControl&lt;/font&gt;’s &lt;font face="Courier New"&gt;ItemsPanel&lt;/font&gt; to something that allows explicit positioning of child items. Normally I would use a &lt;font face="Courier New"&gt;Canvas&lt;/font&gt;, but Colin’s &lt;font face="Courier New"&gt;PiePiece&lt;/font&gt; shapes have their own positioning logic so I used a &lt;font face="Courier New"&gt;Grid&lt;/font&gt; instead:&lt;/p&gt;  &lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;ItemsControl ItemsSource=&amp;quot;{Binding DataPoints, ElementName=_root}&amp;quot;&amp;gt;
    &amp;lt;ItemsControl.ItemsPanel&amp;gt;
        &amp;lt;ItemsPanelTemplate&amp;gt;
            &amp;lt;Grid/&amp;gt;
        &amp;lt;/ItemsPanelTemplate&amp;gt;
    &amp;lt;/ItemsControl.ItemsPanel&amp;gt;&lt;/pre&gt;










&lt;p&gt;Then I used a few multi-converters to calculate the &lt;font face="Courier New"&gt;WedgeAngle&lt;/font&gt;, &lt;font face="Courier New"&gt;RotationAngle&lt;/font&gt; and &lt;font face="Courier New"&gt;Fill&lt;/font&gt; of each &lt;font face="Courier New"&gt;PiePiece&lt;/font&gt;:&lt;/p&gt;

&lt;pre class="brush: xhtml; toolbar: false"&gt;&amp;lt;ItemsControl.ItemTemplate&amp;gt;
    &amp;lt;DataTemplate&amp;gt;
        &amp;lt;b:PiePiece Radius=&amp;quot;100&amp;quot; CentreX=&amp;quot;200&amp;quot; CentreY=&amp;quot;200&amp;quot;&amp;gt;
            &amp;lt;b:PiePiece.WedgeAngle&amp;gt;
                &amp;lt;MultiBinding Converter=&amp;quot;{StaticResource WedgeAngleConverter}&amp;quot;&amp;gt;
                    &amp;lt;Binding RelativeSource=&amp;quot;{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}&amp;quot;/&amp;gt;
                    &amp;lt;Binding Path=&amp;quot;ItemsSource&amp;quot; RelativeSource=&amp;quot;{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}&amp;quot;/&amp;gt;
                    &amp;lt;Binding Path=&amp;quot;.&amp;quot;/&amp;gt;
                &amp;lt;/MultiBinding&amp;gt;
            &amp;lt;/b:PiePiece.WedgeAngle&amp;gt;
            &amp;lt;b:PiePiece.RotationAngle&amp;gt;
                &amp;lt;MultiBinding Converter=&amp;quot;{StaticResource RotationAngleConverter}&amp;quot;&amp;gt;
                    &amp;lt;Binding RelativeSource=&amp;quot;{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}&amp;quot;/&amp;gt;
                    &amp;lt;Binding Path=&amp;quot;ItemsSource&amp;quot; RelativeSource=&amp;quot;{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}&amp;quot;/&amp;gt;
                    &amp;lt;Binding Path=&amp;quot;.&amp;quot;/&amp;gt;
                &amp;lt;/MultiBinding&amp;gt;
            &amp;lt;/b:PiePiece.RotationAngle&amp;gt;
            &amp;lt;b:PiePiece.Fill&amp;gt;
                &amp;lt;MultiBinding Converter=&amp;quot;{StaticResource FillConverter}&amp;quot;&amp;gt;
                    &amp;lt;Binding RelativeSource=&amp;quot;{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}&amp;quot;/&amp;gt;
                    &amp;lt;Binding Path=&amp;quot;ItemsSource&amp;quot; RelativeSource=&amp;quot;{RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}&amp;quot;/&amp;gt;
                    &amp;lt;Binding Path=&amp;quot;.&amp;quot;/&amp;gt;
                &amp;lt;/MultiBinding&amp;gt;
            &amp;lt;/b:PiePiece.Fill&amp;gt;
        &amp;lt;/b:PiePiece&amp;gt;
    &amp;lt;/DataTemplate&amp;gt;
&amp;lt;/ItemsControl.ItemTemplate&amp;gt;&lt;/pre&gt;


&lt;p&gt;Each converter is pretty straightforward, and the &lt;font face="Courier New"&gt;FillConverter&lt;/font&gt; is very dumb indeed because it will run out of colors and throw an exception if there are too many data points (this is, after all, just a quick and dirty example of how to achieve the stated goal). The &lt;font face="Courier New"&gt;RotationAngle&lt;/font&gt; converter is the most complex:&lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    var itemsControl = values[0] as ItemsControl;
    var dataPoints = values[1] as ICollection&amp;lt;double&amp;gt;;
    var dataPoint = (double)values[2];
    var dataPointIndex = itemsControl.ItemContainerGenerator.IndexFromContainer(itemsControl.ItemContainerGenerator.ContainerFromItem(dataPoint));
    var total = dataPoints.Aggregate((working, current) =&amp;gt; working += current);
    var totalToCurrentDataPoint = 0d;

    if (dataPointIndex &amp;gt; 0)
    {
        totalToCurrentDataPoint = dataPoints.TakeWhile((value, index) =&amp;gt; index &amp;lt; dataPointIndex).Aggregate((working, current) =&amp;gt; working += current);
    }

    return (totalToCurrentDataPoint / total) * 360d;
}&lt;/pre&gt;


&lt;p&gt;It figures out the index of the current item by using the &lt;font face="Courier New"&gt;ItemsControl&lt;/font&gt;’s &lt;font face="Courier New"&gt;ItemContainerGenerator&lt;/font&gt;. Note that this code is fragile because the data points are of type &lt;font face="Courier New"&gt;double&lt;/font&gt;. As such, if any two data points have the same value, this code will incorrectly determine the index and the pie chart won’t look right. An easy way to work around this is to use a reference type for the data points.&lt;/p&gt;

&lt;p&gt;Once it knows the index of the item, it can work out how the total of data prior to the item, and the total of data in the whole data set. Based on that, it can work out the rotation angle.&lt;/p&gt;

&lt;p&gt;The end result looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SI7pC2ffm6I/AAAAAAAAAwo/5KRFvseQcvo/image%5B5%5D.png?imgmax=800" width="415" height="416" /&gt; &lt;/p&gt;









&lt;p&gt;Anyway, this was just a quick answer to Colin’s question. I will post a comment on his article pointing back to this post.&lt;/p&gt;

&lt;p&gt;You can download my code &lt;a href="http://www.users.on.net/~kentcb/wpf/WPFPieChart.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-4736613689380853914?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/4736613689380853914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=4736613689380853914' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4736613689380853914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4736613689380853914'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/07/itemscontrol-as-basis-for-pie-chart.html' title='ItemsControl as Basis for Pie Chart'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/kent.boogaart/SI7pC2ffm6I/AAAAAAAAAwo/5KRFvseQcvo/s72-c/image%5B5%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-1117379187990778745</id><published>2008-07-22T16:01:00.001+01:00</published><updated>2008-07-24T19:46:38.877+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UK/Europe'/><category scheme='http://www.blogger.com/atom/ns#' term='Family'/><title type='text'>Paris</title><content type='html'>&lt;p&gt;Dirty. Expensive. Confusing. Those are words I would use to describe Paris.&lt;/p&gt;  &lt;p&gt;Perhaps we were unlucky, but the neighborhood we stayed in (north-east of the city, near &lt;a href="http://en.wikipedia.org/wiki/Gare_de_Nord"&gt;Gare du Nord&lt;/a&gt; station) was far from idyllic. The streets were paved in rubbish and dog crap, and we witnessed plenty of Parisians adding their own bodily fluids into the soup. Charming.&lt;/p&gt;  &lt;p&gt;Eating out was nice enough, but really took its toll on the wallet. One place charged us €6.50 per beer! Of course, they didn’t tell us that until we’d finished drinking. And when we questioned the price, the manager was at the ready with a menu in hand. I suspect it was the specially-printed “tourist” menu.&lt;/p&gt;  &lt;p&gt;As for getting around, it wasn’t &lt;em&gt;too&lt;/em&gt; bad but was quite frustrating at times due to the strange layout of the city and the lack of good signs. There’s appears to be nothing consistent or logical about the geometry of the streets. It’s really kind of random.&lt;/p&gt;  &lt;p&gt;It’s not all bad though. Central Paris was amazing. &lt;a href="http://en.wikipedia.org/wiki/Notre_Dame_de_Paris"&gt;Notre Dame&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Mus%C3%A9e_du_Louvre"&gt;The Louvre&lt;/a&gt; were a sight to behold (apart from the eyesore that is The &lt;a href="http://en.wikipedia.org/wiki/Louvre_Pyramid"&gt;Louvre Pyramid&lt;/a&gt;). The &lt;a href="http://en.wikipedia.org/wiki/Eiffel_Tower"&gt;Eiffel Tower&lt;/a&gt; also looked great, but we didn’t get up close.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SIjM9kEGEzI/AAAAAAAAAvw/f2cOaiypUoU/s1600-h/P7170023%5B4%5D.jpg"&gt;&lt;img title="P7170023" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P7170023" src="http://lh4.ggpht.com/kent.boogaart/SIjM-H6DFEI/AAAAAAAAAv0/qEXxWWyJr3k/P7170023_thumb%5B2%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SIjM_Y2j4ZI/AAAAAAAAAv4/9k-2G3Bsk-M/s1600-h/P7170025%5B4%5D.jpg"&gt;&lt;img title="P7170025" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P7170025" src="http://lh4.ggpht.com/kent.boogaart/SIjNASNeuuI/AAAAAAAAAv8/J5jqMPUK4w0/P7170025_thumb%5B2%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SIjNBDvfd3I/AAAAAAAAAwA/nzHTikanwmA/s1600-h/P7170036%5B4%5D.jpg"&gt;&lt;img title="P7170036" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P7170036" src="http://lh4.ggpht.com/kent.boogaart/SIjNBsYJFlI/AAAAAAAAAwE/Gu93GmcVMvI/P7170036_thumb%5B2%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://lh3.ggpht.com/kent.boogaart/SIjNCpoUyZI/AAAAAAAAAwI/k7SABI3rw0s/s1600-h/P7170039%5B4%5D.jpg"&gt;&lt;img title="P7170039" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P7170039" src="http://lh4.ggpht.com/kent.boogaart/SIjNDHtvVrI/AAAAAAAAAwM/Gp50OjvhSpc/P7170039_thumb%5B2%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The second day saw us at &lt;a href="http://en.wikipedia.org/wiki/Disneyland_paris"&gt;Disneyland&lt;/a&gt; where rides and signatures are free, assuming your time and energy are worthless. Seriously – well over an hour to get Cinderella’s signature. By the time I reached her, she had changed shift and I got Snow White instead. I was &lt;em&gt;heartbroken&lt;/em&gt; ;)&lt;/p&gt;  &lt;p&gt;Tempany loved it all, though, which is the important thing.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SIjND5qsTXI/AAAAAAAAAwQ/NMMIk398nz8/s1600-h/IMG_0676%5B5%5D.jpg"&gt;&lt;img title="IMG_0676" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="IMG_0676" src="http://lh5.ggpht.com/kent.boogaart/SIjNEamba_I/AAAAAAAAAwU/7rAqcxAfBRw/IMG_0676_thumb%5B3%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SIjNGYWqtAI/AAAAAAAAAwY/naJdJ5QT7RM/s1600-h/IMG_0678%5B4%5D.jpg"&gt;&lt;img title="IMG_0678" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="IMG_0678" src="http://lh6.ggpht.com/kent.boogaart/SIjNG8MeVMI/AAAAAAAAAwc/FZToCySsW04/IMG_0678_thumb%5B2%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SIjNIKvN0rI/AAAAAAAAAwg/CAUod3E2kIk/s1600-h/IMG_0680%5B4%5D.jpg"&gt;&lt;img title="IMG_0680" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="IMG_0680" src="http://lh5.ggpht.com/kent.boogaart/SIjNIgwGnyI/AAAAAAAAAwk/ZbPwu_Fpr98/IMG_0680_thumb%5B2%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The next day we went shopping. We were told to check out a local shopping center, and check it out we did. It was pretty good, and I picked up some shirts (€35 each, in case you were wondering). However, I was disappointed not to see more Asterix and Obelix merchandise.&lt;/p&gt;  &lt;p&gt;The final day was a write-off, as we pretty much just hung around waiting for our train. Incidentally, &lt;a href="http://www.eurostar.com/dynamic/index.jsp"&gt;Eurostar&lt;/a&gt; was great. Far less hassle than flying, and the difference in travel time is negligible.&lt;/p&gt;  &lt;p&gt;I’ll probably go to France again one day, if only to see the Asterix and Obelix theme park.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-1117379187990778745?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/1117379187990778745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=1117379187990778745' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/1117379187990778745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/1117379187990778745'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/07/paris.html' title='Paris'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/kent.boogaart/SIjM-H6DFEI/AAAAAAAAAv0/qEXxWWyJr3k/s72-c/P7170023_thumb%5B2%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-2365947033483487108</id><published>2008-06-30T14:38:00.001+01:00</published><updated>2008-06-30T19:22:17.483+01:00</updated><title type='text'>Hawkeye</title><content type='html'>&lt;p&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="100" alt="image" src="http://lh6.ggpht.com/kent.boogaart/SGkkWKM843I/AAAAAAAAAu0/LCsm-JiWJ94/image%5B8%5D.png?imgmax=800" width="100" align="right" border="0" /&gt;&lt;/p&gt;  &lt;p&gt; Finally, it looks as though &lt;a href="http://www.cardiff.ac.uk/socsi/newsandevents/news/hawkeye.html"&gt;Hawkeye will be outed&lt;/a&gt;. It was always telling to me that suddenly we weren’t shown video replays of close calls anymore, only the Hawkeye simulation. I suspect if we were shown side-by-side replays all along then the technology would have proved to be inaccurate to the general public a lot sooner. Of course, it’s probably still more accurate than the human eye.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;On the subject of tennis, we went down to Wimbledon last Friday. There was a nice five hour wait to get into general admission. Five hours in line with a three year old to see maybe the last hour’s play? &lt;em&gt;Sure!&lt;/em&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-2365947033483487108?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/2365947033483487108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=2365947033483487108' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2365947033483487108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2365947033483487108'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/06/hawkeye.html' title='Hawkeye'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/kent.boogaart/SGkkWKM843I/AAAAAAAAAu0/LCsm-JiWJ94/s72-c/image%5B8%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-8997668705897521775</id><published>2008-06-18T09:32:00.001+01:00</published><updated>2008-07-26T13:39:35.957+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='System.AddIn'/><category scheme='http://www.blogger.com/atom/ns#' term='MAF'/><title type='text'>MAF Gymnastics: Service Provider</title><content type='html'>&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/MAF/ServiceProvider.zip"&gt;Download the Solution&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;If you’ve ever worked on a composite application, you’ll know that services are their backbone. Services allow modules in the application to collaborate in both state and behavior. Moreover, services can be swapped out easily, since the modules work against an interface and are (hopefully) ignorant of the implementation behind the interface.&lt;/p&gt;  &lt;p&gt;This post will address how to implement a service ecosystem using MAF in a composite application. In particular, how we can do this whilst keeping the host agnostic of the services it is hosting, and providing version tolerance for the services. Whilst I focus on composite applications, the techniques here can also be applied in non-composite applications.&lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Requirements&lt;/strong&gt;&lt;/h3&gt;  &lt;h4&gt;&lt;strong&gt;Agnostic Host&lt;/strong&gt;&lt;/h4&gt;  &lt;p&gt;One of the challenges of implementing a service provider in MAF is ensuring that the host is capable of hosting &lt;em&gt;any&lt;/em&gt; service, not just those services it knows about at compile-time. Without this ability, it’s not really a composite application and does not permit the kind of collaboration between add-ins that such an application requires.&lt;/p&gt;  &lt;p&gt;Of course, the types related to the services must not be loaded into the host’s &lt;code&gt;AppDomain&lt;/code&gt;. The services need to be isolated just like any other add-in.&lt;/p&gt;  &lt;h4&gt;&lt;strong&gt;Version Tolerance&lt;/strong&gt;&lt;/h4&gt;  &lt;p&gt;Consider how composite applications are often written in the real world. You have a bunch of autonomous teams, each team producing and/or consuming services. Some teams consume services &lt;em&gt;provided by other teams&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;Then there’s the shell (aka “host”), which is responsible for hosting these modules and allowing them to collaborate. The shell is often produced by another team altogether to those producing the modules (aka “add-ins”).&lt;/p&gt;  &lt;p&gt;Now think about what happens when one of the service-providing teams decides they need to modify their service interface. They can potentially break all the modules that depend on that service. In other words, the consumers of that service are at the mercy of the service provider.&lt;/p&gt;  &lt;p&gt;MAF pipelines already provide a nice solution to this problem between the host and add-ins, but wouldn’t it be nice if the service provider could version their service over time, providing backwards compatibility as desired?&lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;/h3&gt;  &lt;h4&gt;&lt;strong&gt;Add-in Types&lt;/strong&gt;&lt;/h4&gt;  &lt;p&gt;The contracts define two types of add-ins: an application add-in and a service add-in.&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="287" alt="image" src="http://lh6.ggpht.com/kent.boogaart/SGIAoGHXUqI/AAAAAAAAAuY/YRy4ukItfog/image5.png?imgmax=800" width="589" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;At this point, the difference between a service add-in and an application add-in is minimal. A service add-in provides an ID by which it will be resolved by consuming add-ins.&lt;/p&gt;  &lt;p&gt;Both add-in contracts have a common base interface (&lt;code&gt;IAddInContract&lt;/code&gt;) from which they inherit an &lt;code&gt;Initialize()&lt;/code&gt; method. Notice how this method returns an instance of &lt;code&gt;AddInInitResult&lt;/code&gt;. This is crucial to the host being able to track which add-ins are hosted in which &lt;code&gt;AppDomain&lt;/code&gt;s.&lt;/p&gt;  &lt;p&gt;The add-in views do not have this added complexity:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="261" alt="image" src="http://lh4.ggpht.com/kent.boogaart/SGIAodp4JoI/AAAAAAAAAuc/86a1vHLTToE/image14.png?imgmax=800" width="396" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;This is good, because the add-in developer need not worry about returning anything from their &lt;code&gt;Initialize()&lt;/code&gt; implementation. Instead, this is handled by the adapters, as we’ll see later.&lt;/p&gt;  &lt;p&gt;The host views mirror the contracts very closely, since the host &lt;em&gt;does &lt;/em&gt;need to know and track this extra initialization information:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="261" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SGIAojxML7I/AAAAAAAAAug/rRqmexV2PHs/image17.png?imgmax=800" width="587" border="0" /&gt; &lt;/p&gt;  &lt;h4&gt;&lt;strong&gt;Add-in Activation and Tracking&lt;/strong&gt;&lt;/h4&gt;  &lt;p&gt;When the host starts up, it first finds and activates service add-ins and then application add-ins. In both cases, it remembers the contract object for the add-in (that is, the &lt;code&gt;MarshalByRefObject&lt;/code&gt; implementing the add-in). For services, it also maps the service ID back to the &lt;code&gt;AddInToken&lt;/code&gt; so that it can obtain the contract implementation given only the service ID. This is important, of course, and you’ll see why soon.&lt;/p&gt;  &lt;p&gt;Note that the tracking information is only actually necessary to support services, but the host code tracks application add-ins too, since that made the logic simpler.&lt;/p&gt;  &lt;h4&gt;&lt;strong&gt;The Host&lt;/strong&gt;&lt;/h4&gt;  &lt;p&gt;It’s time to look at the pipeline components for the host. Firstly, the contract:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="254" alt="image" src="http://lh4.ggpht.com/kent.boogaart/SGIAqYSsouI/AAAAAAAAAuk/aru-cAIsnOI/image29.png?imgmax=800" width="612" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;We’re getting closer and closer to the &lt;a href="http://dictionary.reference.com/browse/nitty%20gritty"&gt;nitty-gritty&lt;/a&gt; now (I can’t believe that’s in the dictionary). The host contract has two methods of importance on it: &lt;code&gt;GetPipelineDetails()&lt;/code&gt; and &lt;code&gt;GetServiceDetails()&lt;/code&gt;.&lt;/p&gt;  &lt;p&gt;The former is quite simple: it just retrieves some basic information about the MAF pipeline. This information is needed by the add-in side adapters to support services. We’ll look at this further below.&lt;/p&gt;  &lt;p&gt;The latter is also straightforward: it retrieves the service contract for a given service ID. Recall from above that when we activate services we track some information about that service. This method just allows the caller to retrieve that information.&lt;/p&gt;  &lt;p&gt;The host view of the host is a mirror of the contract, so I won’t bother talking about it here. The add-in view of the host, on the other hand, is quite different:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="156" alt="image" src="http://lh4.ggpht.com/kent.boogaart/SGIAqmIHR-I/AAAAAAAAAuo/N9QFnwWPats/image34.png?imgmax=800" width="228" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;As you can see, add-ins get a simpler view of the host. There is a single method that they can use to resolve a service by ID. There is no nonsense about getting pipeline information or what have you. The service consumer doesn’t care about that - she just wants a service.&lt;/p&gt;  &lt;p&gt;I made this method generic just to save a little casting in the add-ins, but in reality I haven’t decided how I’d best like to compose this interface. I’m considering having the ID automatically determined by the interface type the service implements, so add-ins don’t even need to provide an ID. However, I haven’t spiked this yet so I don’t know if it will play out exactly as I hope. Anyway, I’ll be looking at that soon for a real project.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: It works great! In my “real” project services do not need to explicitly provide an ID. Instead, the adapters infer it based on the view type the service implements. In addition, services are not explicitly requested from the host. Instead, the adapters determine the services an add-in requires by examining its &lt;code&gt;Initialize()&lt;/code&gt; method and injecting any dependent services automatically. This results in a really nice, low-friction add-in development experience.&lt;/p&gt;  &lt;h4&gt;&lt;strong&gt;The Adapters&lt;/strong&gt;&lt;/h4&gt;  &lt;p&gt;Based on the interfaces we just saw, you might assume that there’s some magic happening in the adapters to close the gap, so to speak. And you’d be right.&lt;/p&gt;  &lt;p&gt;What we need to do is connect up the service consumer add-in to the service add-in, which already exists in its own &lt;code&gt;AppDomain&lt;/code&gt;. Indeed, we may need to connect up multiple consumers to the service. Those consumers might be application add-ins or even other service add-ins (the sample only demonstrates the former, but the latter should work too assuming that the services are activated in the correct order).&lt;/p&gt;  &lt;p&gt;Consider the following diagram:&lt;/p&gt;  &lt;p&gt;&lt;img title="Service Provider" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="392" alt="Service Provider" src="http://lh3.ggpht.com/kent.boogaart/SGIAsGS4V-I/AAAAAAAAAus/3qlWFnTDW8o/ServiceProvider6.png?imgmax=800" width="640" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;The black lines represent the “primary” pipeline between the host and the add-ins, be they regular application add-ins or service add-ins. In the diagram we have a single service add-in (up the top) and two consumers of that service. The two consumers are built against different versions of the service (V1 and V2) but they both need to consume whatever version of the service is loaded (assuming the appropriate pipeline adapters can be found).&lt;/p&gt;  &lt;p&gt;The service’s interface (&lt;code&gt;ISomeService&lt;/code&gt;) extends the core service interface provided by the host (&lt;code&gt;IService&lt;/code&gt;). Actually, this extension occurs in both the contracts and the views. As such, the service pipeline components depend on the pipeline components provided by the host. For the purposes of the primary pipeline, only the implementation of &lt;code&gt;IService&lt;/code&gt; is used (that is, &lt;code&gt;IServiceContract&lt;/code&gt; is used for communication over the black pipelines).&lt;/p&gt;  &lt;p&gt;The blue lines represent the “secondary” pipeline between the service consumers and the service. It is this pipeline that provides marshalling specific to the service implementation (&lt;code&gt;ISomeService&lt;/code&gt;).&lt;/p&gt;  &lt;p&gt;And it is here where we need to employ some trickery to get the job done. First though, thanks to the anonymous commenter who pointed out an easier way to do this.&lt;/p&gt;  &lt;p&gt;Here’s how it works. The add-in side contract to view adapter for the &lt;code&gt;IHost&lt;/code&gt; interface implements the &lt;code&gt;ResolveService&amp;lt;T&amp;gt;()&lt;/code&gt; method we saw above. In order to do this, it needs to construct a pipeline between the caller (ie. the consuming add-in) and the service itself.&lt;/p&gt;  &lt;p&gt;The host’s &lt;code&gt;AppDomain&lt;/code&gt; is impartial to this whole process – it merely provides some information the adapter needs to set up the pipeline. Once the adapter has this information, it uses MAF’s &lt;code&gt;ContractAdapter&lt;/code&gt; type to adapt between the add-in’s view of the service and the existing service instance (ie. create the pipeline represented by the blue lines above). Specifically, the &lt;code&gt;ContractToViewAdapter()&lt;/code&gt; method is used because we’re taking an existing contract (the service instance) and adapting it to the view.&lt;/p&gt;  &lt;p&gt;Since the &lt;code&gt;ContractToViewAdapter()&lt;/code&gt; method is generic and we don’t know the type until runtime, we need to invoke it reflectively. It might be nicer if MAF included non-generic overloads for these methods, but the fact that they’re public means that we do not need elevated privileges to invoke them via reflection. Thus, your add-in can still be hosted in a low-trust &lt;code&gt;AppDomain&lt;/code&gt;.&lt;/p&gt;  &lt;p&gt;Of course, once this pipeline is constructed we don’t need to do so again for the current &lt;code&gt;AppDomain&lt;/code&gt; (unless a different view of the same service is used from within the same &lt;code&gt;AppDomain&lt;/code&gt;, and the code caters for that case too). Therefore, we cache this information. Subsequent calls to &lt;code&gt;ResolveService&amp;lt;T&amp;gt;()&lt;/code&gt; won’t even leave the caller’s &lt;code&gt;AppDomain&lt;/code&gt;, which I think is pretty cool. Of course, calling into the service itself will marshal to the service’s &lt;code&gt;AppDomain&lt;/code&gt; as expected.&lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Limitations&lt;/strong&gt;&lt;/h3&gt;  &lt;p&gt;There are a couple of things you need to be aware of with respect to this technique. First and foremost, I mentioned above that MAF can only deal with one pipeline at a time. Further to this, it can only resolve one assembly from each pipeline folder. For example, all your add-in side adapters need to be in a single assembly inside the &lt;em&gt;[Pipeline]\AddInSideAdapters &lt;/em&gt;folder. If your add-in side adapters assembly depends on another assembly, that assembly must be in the GAC in order for MAF to resolve it. MAF will not try to resolve that assembly from the same pipeline directory from which your add-in side adapters were loaded.&lt;/p&gt;  &lt;p&gt;The problem with this is that the service pipelines depend on the host pipeline. As a simple example of this, the &lt;code&gt;ISomeServiceContract&lt;/code&gt; included in the download extends the host’s &lt;code&gt;IServiceContract&lt;/code&gt;. The upshot is that the host’s pipeline must be in the GAC.&lt;/p&gt;  &lt;p&gt;In fact, this GAC registration requirement spreads virally throughout your pipeline projects. If you look in the sample you’ll see that most pipeline assemblies are registered in the GAC when you build. As such, you’ll need local admin since &lt;code&gt;gacutil&lt;/code&gt; requires this. Unfortunately, I don’t see a way around this given MAF’s current architecture.&lt;/p&gt;  &lt;p&gt;It’s important to point out that installing the pipeline components in the GAC &lt;em&gt;is almost certainly what you want to do for deployments&lt;/em&gt;. Otherwise these assemblies cannot be shared between &lt;code&gt;AppDomain&lt;/code&gt;s and performance suffers badly. It’s just a shame that it’s also required for development.&lt;/p&gt;  &lt;p&gt;Related to this issue is the possibility of name clashes in pipeline assemblies. You may have many teams working on services, and the pipeline assemblies for those services must reside in the same folder. Therefore, if one team chooses the same assembly name as another you will get a clash. This is pretty unlikely, but it’s something to keep in mind.&lt;/p&gt;  &lt;p&gt;Less a limitation and more a “gotcha”: notice how the service implementation (in the &lt;em&gt;Service &lt;/em&gt;project) references the service add-in views project (&lt;em&gt;Service.AddInViews&lt;/em&gt;) and the service consumer add-ins reference the service host views project (&lt;em&gt;Service.HostViews&lt;/em&gt;). In MAF terminology, the consumers are “hosts” of the service. This terminology doesn’t quite fit here because the consumers aren’t explicitly activating the service. In a real application, I would probably rename the service add-in views and host views to “provider views” and “consumer views” accordingly.&lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;The Result&lt;/strong&gt;&lt;/h3&gt;  &lt;p&gt;If you download and execute the sample you’ll see this:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="195" alt="image" src="http://lh6.ggpht.com/kent.boogaart/SGIAtt3ddjI/AAAAAAAAAuw/-PBQi05nGkE/image40.png?imgmax=800" width="800" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;As unexciting as this looks at first glance, it’s actually really, really cool. &lt;em&gt;Trust me&lt;/em&gt;. What we’re seeing here is that there are four &lt;code&gt;AppDomain&lt;/code&gt;s:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;One for the host &lt;/li&gt;    &lt;li&gt;One for the service &lt;/li&gt;    &lt;li&gt;One for the first service consumer &lt;/li&gt;    &lt;li&gt;One for the second service consumer &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The host and its pipeline know nothing about the specific service at compile-time. That is, it has no knowledge of &lt;code&gt;ISomeService&lt;/code&gt;, only &lt;code&gt;IService&lt;/code&gt;. And yet, it is hosting this service. That’s a check for an agnostic host.&lt;/p&gt;  &lt;p&gt;The first service consumer is executing against version 2 of the service. It sets a value on the service to 26 and outputs the results of calling the service’s &lt;code&gt;GetTimestamp()&lt;/code&gt; method. When it calls this method, it passes in a custom format string of “ddd MMM yyyy”.&lt;/p&gt;  &lt;p&gt;The second service consumer is executing against version 1 of the service. It gets the value of 26 set by the first consumer and outputs it. Then it calls the service’s &lt;code&gt;GetTimestamp()&lt;/code&gt; method and outputs that. But what’s cool is that version 1 of the service did not allow a custom format string to be passed into this method! The adapters for the service (see the &lt;em&gt;Service.HostSideAdapters_V1toV2 &lt;/em&gt;project) are automatically using a default format string of “dd/MM/yyyy”. This proves that the correct pipeline components have been selected and used to join the service consumers to the service – that’s a check for version tolerance.&lt;/p&gt;  &lt;p&gt;We have achieved everything we set out to achieve here. The host is agnostic of the services it will be hosting at runtime and none of the service types leak into the host. Moreover, the pipeline between service consumers and the service itself has all the intelligence you’d expect of a MAF pipeline. It selects the correct components to ensure that the service consumer can interact with the service, even if the consumer was built against an older version of the service.&lt;/p&gt;  &lt;h3&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h3&gt;  &lt;p&gt;Composite applications need a facility to provide and share services. An effective shell for a composite application needs to be agnostic of the services it is hosting, otherwise developers leveraging the shell are hamstrung by its intrinsic assumptions about the services it will host.&lt;/p&gt;  &lt;p&gt;MAF’s concept of pipelines to handle version tolerance are equally applicable to services as they are to the shell itself. That’s simply because of the relationship between the provider of the deliverables and its consumers. As a shell or service developer, there is some uncertainty as to how many teams are leveraging your work, and how long they need to migrate to newer versions of your deliverables. Pipelines allow you to provide backwards compatibility so that consumers are not forced to update their code bases straight away.&lt;/p&gt;  &lt;p&gt;The solution presented in this post solves both these problems. The shell knows nothing about the exact services it will be hosting at runtime. In addition, it uses a pipeline provided by the service developer to connect the service consumers to the service.&lt;/p&gt;  &lt;p&gt;This was a particularly difficult topic to articulate, and I’m not confident that I did so well. If I failed to convey this information adequately, feel free to let me know in the comments and I’ll do my best to rectify the situation.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/MAF/ServiceProvider.zip"&gt;Download the Solution&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-8997668705897521775?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/8997668705897521775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=8997668705897521775' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/8997668705897521775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/8997668705897521775'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/06/maf-gymnastics-service-provider.html' title='MAF Gymnastics: Service Provider'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/kent.boogaart/SGIAoGHXUqI/AAAAAAAAAuY/YRy4ukItfog/s72-c/image5.png?imgmax=800' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-6288118449816893588</id><published>2008-06-11T21:40:00.001+01:00</published><updated>2008-06-12T22:05:21.462+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='System.AddIn'/><category scheme='http://www.blogger.com/atom/ns#' term='MAF'/><title type='text'>MAF Gymnastics: Event Hub</title><content type='html'>&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/MAF/EventHub.zip"&gt;Download the Solution&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The first problem I will attempt to address in this series is that of providing an &lt;a href="http://martinfowler.com/eaaDev/EventAggregator.html"&gt;event aggregator&lt;/a&gt; service (which I call an event hub, just to save on typing). That is, how can we allow add-ins to subscribe to, and publish events on a many-to-many event bus that is managed and implemented by the host?&lt;/p&gt;  &lt;p&gt;When using MAF, there are a number of problems that must be solved in order to facilitate such a service. For one, how can we present a decent API to the add-in developer? The lack of generics support in MAF makes this difficult (see my &lt;a href="http://kentb.blogspot.com/2008/06/maf-gymnastics-skeletal-solution.html"&gt;previous post&lt;/a&gt; for details), and limits the overall effectiveness of the solution.&lt;/p&gt;  &lt;p&gt;Next up, how can we ensure that event subject types (the CLR types that contain event payloads) do not leak into the host? If two add-ins communicate with a custom subject type, that type should not be loaded into the host's &lt;code&gt;AppDomain&lt;/code&gt;. It should only be loaded into the &lt;code&gt;AppDomain&lt;/code&gt; of those add-ins that care about that particular event.&lt;/p&gt;  &lt;p&gt;With that in mind, how can we allow the host to use the event hub in much the same way as add-ins? That is, how can we design the host views such that the host can remain agnostic of subject types where necessary, but can publish and subscribe on the event hub where desired?&lt;/p&gt;  &lt;p&gt;Finally, we'll discuss how the event hub service is exposed to add-ins. That is, how does an add-in actually obtain an instance of the event hub service.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The API&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The contracts for the event hub service looks like this:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="166" alt="image" src="http://lh3.ggpht.com/kent.boogaart/SFGOt3Z2pNI/AAAAAAAAAuE/43R4J7Uv1bM/image%5B39%5D.png?imgmax=800" width="778" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;Importantly, you can see that there is nothing in these APIs that will cause types to leak from the add-in &lt;code&gt;AppDomain&lt;/code&gt;s to the host (or vice-versa). A &lt;code&gt;string&lt;/code&gt; is used to identify subjects as opposed to a CLR type or &lt;code&gt;RuntimeTypeHandle&lt;/code&gt;, both of which will result in errors because the corresponding subject type may not be available to the host. Also, subjects themselves are passed around as a &lt;code&gt;byte&lt;/code&gt; array rather than an &lt;code&gt;object&lt;/code&gt; instance. That allows the host to remain completely unaware of the actual CLR types involved.&lt;/p&gt;  &lt;p&gt;The views for the event hub service look slightly different depending on whether you're an add-in or the host. For an add-in, the API looks like this:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="153" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SFGOvuU1_hI/AAAAAAAAAuI/Dvkr4cliz34/image%5B38%5D.png?imgmax=800" width="634" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;The &lt;code&gt;ISubscriber&lt;/code&gt; interface is what event subscribers must implement. It has a single method that is called when a relevant event is published on the event bus. The &lt;code&gt;IEventHubService&lt;/code&gt; interface allows events to be published, and subscribers to be registered and unregistered.&lt;/p&gt;  &lt;p&gt;A CLR type is used to scope events. That is, subscribers register their interest in events with a certain subject type. Subscribers will only receive events of types they have registered their interest in. In reality, you might want add-ins to just use a &lt;code&gt;string&lt;/code&gt; to identify events. However, I wanted something that demonstrates how to differ your view from your contract.&lt;/p&gt;  &lt;p&gt;This API is fairly clean and simple, but suffers from a lack of generics. Ideally, we would be able to define a generic &lt;code&gt;ISubscriber&amp;lt;T&amp;gt;&lt;/code&gt; interface and have subscribers receive a strongly-typed subject argument. However, whilst the MAF pipeline does allow generic members in non-generic types, it does not allow generic types. That's because it must automatically hook up contracts and views with their corresponding adapters. If the contract or view is a generic type, MAF is not able to close the type (presumably because it does not have enough information to do so).&lt;/p&gt;  &lt;p&gt;The API for the host is a little more complicated than that for the add-in:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="474" alt="image" src="http://lh6.ggpht.com/kent.boogaart/SFGO0QIPVhI/AAAAAAAAAuM/tyw0TWp1l_A/image%5B40%5D.png?imgmax=800" width="572" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;The reason for the complication is that we want the event hub to be usable from the host in much the same way as it is from an add-in. To that end, we differentiate between two different subscribers: add-in subscribers and the host itself. There are basically two &amp;quot;modes&amp;quot; that the host-side works in: type-agnostic (add-in subscriber) and type-aware (host subscriber). The type-aware mode is not strictly necessary for the host to work with the event hub, but it sure makes it easier and consistent with the way the event hub works for add-ins.&lt;/p&gt;  &lt;p&gt;The finally part of the API I want to draw your attention to is the &lt;code&gt;IHost&lt;/code&gt; interface:&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="160" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SFGO2gQZdqI/AAAAAAAAAuQ/P-fKyxQWy1g/image%5B41%5D.png?imgmax=800" width="306" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;The &lt;code&gt;EventHubService&lt;/code&gt; property on this interface is the means by which add-ins actually gain access to the service. In a later post I will discuss a more generalized and extensible way of exposing services to add-ins.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Adapters&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The key to this solution is contained within the adapters. The adapters ensure that the host remains blissfully unaware of subject types and payloads. Consider this add-in code:&lt;/p&gt;  &lt;pre class="code"&gt;host.EventHubService.Publish(&lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;CustomEventSubject&lt;/span&gt;() { Message = &lt;span style="color: rgb(163,21,21)"&gt;&amp;quot;Giggidy giggidy!&amp;quot;&lt;/span&gt; });&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The add-in side view-to-contract adapter adapts this call such that the subject type (&lt;code&gt;CustomEventSubject&lt;/code&gt;) is converted to a &lt;code&gt;string&lt;/code&gt; used to identify the event, and the subject itself (the &lt;code&gt;CustomEventSubject&lt;/code&gt; instance) becomes a &lt;code&gt;byte&lt;/code&gt; array via standard .NET serialization. Neither parameter makes it unscathed into the host's &lt;code&gt;AppDomain&lt;/code&gt;, which is fortunate because that would cause problems where the subject type was unknown to the host. The contract-to-view adapter does the opposite: it resolves a .NET &lt;code&gt;Type&lt;/code&gt; instance based on the identifying &lt;code&gt;string&lt;/code&gt;, and deserializes the &lt;code&gt;byte&lt;/code&gt; array into an instance of the subject type.&lt;/p&gt;

&lt;p&gt;If little alarm bells are going off inside your head right now after hearing about the automatic (de)serialization, it’s for good reason. I discuss why you should use the event hub service with care below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Host&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The host is largely untouched with respect to the &lt;a href="http://kentb.blogspot.com/2008/06/maf-gymnastics-skeletal-solution.html"&gt;skeletal solution&lt;/a&gt;. The one change is the use of qualification data to dictate the load order for add-ins. We need the subscriber add-in to load prior to the publisher add-in, otherwise the event publication will occur before there is a subscriber!&lt;/p&gt;

&lt;p&gt;Each add-in has a &lt;code&gt;QualificationDataAttribute&lt;/code&gt; applied to it to specify the load order. The host then uses the value in this attribute to order the add-ins prior to activation:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;var&lt;/span&gt; orderedTokens = &lt;span style="color: rgb(0,0,255)"&gt;from&lt;/span&gt; token &lt;span style="color: rgb(0,0,255)"&gt;in&lt;/span&gt; tokens
                    &lt;span style="color: rgb(0,0,255)"&gt;orderby&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;int&lt;/span&gt;.Parse(token.QualificationData[&lt;span style="color: rgb(43,145,175)"&gt;AddInSegmentType&lt;/span&gt;.AddIn][&lt;span style="color: rgb(163,21,21)"&gt;&amp;quot;LoadOrder&amp;quot;&lt;/span&gt;])
                    &lt;span style="color: rgb(0,0,255)"&gt;select&lt;/span&gt; token;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Note that this is just a simple fix for this specific scenario. A more real-world solution would be to allow one add-in to depend on another and order the activations accordingly. Perhaps I’ll address this in a later post.&lt;/p&gt;

&lt;p&gt;When you execute the host, you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="196" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SFGO5R1WA8I/AAAAAAAAAuU/zokjS88WbbU/image%5B37%5D.png?imgmax=800" width="997" border="0" /&gt; &lt;/p&gt;

&lt;p&gt;As you can see from the output, both the add-ins and the host are utilizing the event hub service. The add-ins are communicating with &lt;code&gt;string&lt;/code&gt; subjects, and with a custom subject.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Again, deployment hasn't really changed much compared to the skeletal solution. The one big difference is the &lt;em&gt;Subjects &lt;/em&gt;project. This project contains a subject type that the add-ins use to communicate. Since both add-ins require access to this type, it must be referenced by each add-in and loaded into their &lt;code&gt;AppDomain&lt;/code&gt;. Therefore, the build script for each add-in project copies this file to the add-in’s directory:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;Copy&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;SourceFiles&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: rgb(0,0,255)"&gt;$(OutputPath)\PublisherAddIn.dll;$(OutputPath)\Subjects.dll&lt;/span&gt;&amp;quot;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;DestinationFolder&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: rgb(0,0,255)"&gt;..\Host\$(OutputPath)\AddIns\PublisherAddIn&lt;/span&gt;&amp;quot;&lt;span style="color: rgb(0,0,255)"&gt; /&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Notably missing from the APIs is a filtering mechanism. That is, a way for publishers or subscribers to filter their interest in a particular event. I excluded this for two reasons:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It was too much effort for the purposes of this post, and would complicate things quite radically. &lt;/li&gt;

  &lt;li&gt;It would encourage cross &lt;code&gt;AppDomain&lt;/code&gt; filtering, which is a potential performance issue. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Any event published to the event hub service has the potential to visit many &lt;code&gt;AppDomain&lt;/code&gt;s, so it should be used with care and only when necessary. If your add-in requires an event hub service, but it does not need to cross the &lt;code&gt;AppDomain&lt;/code&gt; boundary (ie. it is internal to your add-in) you might instead consider something like &lt;a href="http://kentb.blogspot.com/2008/03/event-hub.html"&gt;this&lt;/a&gt;. To reiterate, the service discussed in this post should be used only when inter-add-in communication is required. Don’t use it for intra-add-in communications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Word of Warning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One thing you must be aware of before using this service is that it circumvents some of the measures MAF takes to protect you from versioning issues. Consider what would happen if you had a custom subject type that was consumed (subscribed to) by many add-ins. Suppose you wanted to alter that custom subject type and those alterations would break existing add-ins. You don’t have the luxury of using adapters to help out because the subject was never explicitly called out in the contracts. Instead, the best you can do is use built-in .NET serialization mechanisms (for example, &lt;code&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.runtime.serialization.optionalfieldattribute.aspx"&gt;OptionalFieldAttribute&lt;/a&gt;&lt;/code&gt;) to provide some compatibility, but this will be limited when compared to using a MAF pipeline.&lt;/p&gt;

&lt;p&gt;Because of this, you want to be sure that any custom subject types you create are resilient to change. And when they must change, be sure to ensure that changes are backwards compatible (write some unit tests to verify). And if you simply cannot preserve compatibility, consider defining a new subject type altogether because the alternative is requiring every add-in be recompiled against the new version of the subject type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An event hub service is imperative for applications where add-ins are required to communicate with each other in a loosely-coupled fashion. The solution I presented in this post allows you to achieve that even when add-ins are in completely separate &lt;code&gt;AppDomain&lt;/code&gt;s (or even processes) and the host has no knowledge of the types being used to communicate between the add-ins.&lt;/p&gt;

&lt;p&gt;Limitations of MAF prevent us from providing an ideal solution - one that leverages generics to provide a strongly-typed API. However, this solution is still very workable. Just be cautious when defining subject types - you don't want them to become a versioning headache, especially considering MAF is designed to help prevent such headaches.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/MAF/EventHub.zip"&gt;Download the Solution&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-6288118449816893588?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/6288118449816893588/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=6288118449816893588' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/6288118449816893588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/6288118449816893588'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/06/maf-gymnastics-event-hub.html' title='MAF Gymnastics: Event Hub'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/kent.boogaart/SFGOt3Z2pNI/AAAAAAAAAuE/43R4J7Uv1bM/s72-c/image%5B39%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-3268506734858454300</id><published>2008-06-08T12:55:00.001+01:00</published><updated>2008-06-08T12:55:52.105+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='System.AddIn'/><category scheme='http://www.blogger.com/atom/ns#' term='MAF'/><title type='text'>MAF Gymnastics: Skeletal Solution</title><content type='html'>&lt;p&gt;To kick off this series of posts, I've put together a &lt;a href="http://www.users.on.net/~kentcb/MAF/SkeletonSolution.zip"&gt;skeletal solution&lt;/a&gt; that will be used as a starting point for subsequent posts. MAF requires a lot of plumbing code and infrastructure to be in place before even the simplest example will work. As such, it is prudent for me to avoid duplicating much of that plumbing for each post.&lt;/p&gt;  &lt;p&gt;If you download the solution, you'll see that it is comprised of quite a few different projects. Those projects are partitioned into solution folders.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="72" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SEvIqZWwbJI/AAAAAAAAAs8/YctnJ-G-0F4/image%5B4%5D.png?imgmax=800" width="173" border="0" /&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Most of the projects are contained in the &amp;quot;Pipeline&amp;quot; solution folder. It is these projects that implement the pipeline that MAF uses to connect the add-in to the host. The &amp;quot;AddIns&amp;quot; solution folder contains any add-in projects (there is one sample add-in in the download). Finally, the &amp;quot;Host&amp;quot; project is a simple console host that activates any add-ins that it finds.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The Pipeline&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The pipeline consists of a bunch of projects:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/kent.boogaart/SEvIrI4_YeI/AAAAAAAAAtA/XbnmF7d8xas/s1600-h/image%5B13%5D.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="179" alt="image" src="http://lh4.ggpht.com/kent.boogaart/SEvIrlMWYsI/AAAAAAAAAtE/oWSlZoxc7Xs/image_thumb%5B5%5D.png?imgmax=800" width="169" border="0" /&gt;&lt;/a&gt;&amp;#160; &lt;/p&gt;  &lt;p&gt;The &lt;em&gt;Contracts &lt;/em&gt;project defines the contracts that MAF will load into both sides of the isolation boundary. It consists of a few simple contracts: &lt;code&gt;IHostContract&lt;/code&gt; , &lt;code&gt;IAddInContract&lt;/code&gt; and &lt;code&gt;IApplicationAddInContract&lt;/code&gt;.&lt;/p&gt;  &lt;p&gt;&lt;code&gt;IHostContract&lt;/code&gt; provides some properties that add-ins can invoke to get information about their host (name and version, to be specific). &lt;code&gt;IAddInContract&lt;/code&gt; defines a single &lt;code&gt;Initialize()&lt;/code&gt; method that add-ins implement. This method takes an instance of &lt;code&gt;IHostContract&lt;/code&gt; as a parameter, so the add-in can invoke members against the host. &lt;code&gt;IApplicationAddInContract&lt;/code&gt; extends &lt;code&gt;IAddInContract&lt;/code&gt; but does not add any members. In later posts I will have more than one type of add-in. &lt;code&gt;IAddInContract&lt;/code&gt; will serve as a base contract for add-ins.&lt;/p&gt;  &lt;p&gt;The &lt;em&gt;AddInViews&lt;/em&gt; and &lt;em&gt;HostViews&lt;/em&gt; projects define the view of the world for the add-in and host respectively. In this case, they mirror the contracts very tightly, but in later posts we'll see views that differ quite drastically from their corresponding contracts.&lt;/p&gt;  &lt;p&gt;The &lt;em&gt;AddInSideAdapters &lt;/em&gt;and &lt;em&gt;HostSideAdapters&lt;/em&gt; projects provide adapters that MAF uses to adapt views to contracts and vice-versa. The adapters allow the view to be ignorant of the contract and vice-versa, which is required for supporting version tolerance.&lt;/p&gt;  &lt;p&gt;Note that I have not used any code generation or tools to generate the pipeline. It is written entirely by hand. The reason I did not use &lt;a href="http://www.codeplex.com/clraddins"&gt;Pipeline Builder&lt;/a&gt; is because it is simply not mature enough. I ran into many bugs and limitations when I tried to use it, and it does not give enough control over the generated code.&lt;/p&gt;  &lt;p&gt;When I originally decided to ditch Pipeline Builder and write my pipeline by hand, I tried factoring out common adapter functionality into generic base classes. Unfortunately, MAF does not allow adapter classes to inherit from generic classes, even if the adapter itself is closed (I consider this an awful bug and have &lt;a href="http://www.codeplex.com/clraddins/WorkItem/View.aspx?WorkItemId=1951"&gt;reported it as such&lt;/a&gt;). Moreover, common utility code for adapters cannot be placed into a separate assembly and placed into each adapter's folder because MAF will not load it (unless that assembly is placed into the GAC).&lt;/p&gt;  &lt;p&gt;For these reasons, I had to jump through some hoops to factor out this code. Basically, if you look under the &amp;quot;Pipeline\Shared Code&amp;quot; solution folder you'll see some source code files. These files are then linked to from the adapter projects. In effect, the code is stored in one place (good for maintenance) but compiled into two separate projects (to appease MAF).&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="521" alt="image" src="http://lh4.ggpht.com/kent.boogaart/SEvIt42RJ0I/AAAAAAAAAtI/DFIydi7JdyI/image%5B19%5D.png?imgmax=800" width="600" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;The utility code itself isn't as clean as it would be if MAF supported adapters with generic base types. However, it's still pretty straightforward. Adapters implement one of the two interfaces (&lt;code&gt;IContractToViewAdapter&amp;lt;TContract&amp;gt;&lt;/code&gt; or &lt;code&gt;IViewToContractAdapter&amp;lt;TView&amp;gt;&lt;/code&gt;) according to what type of adapter they are. From there, the static &lt;code&gt;Adapt&lt;/code&gt; class can be used to convert views to contract and vice-versa. This cuts down on a lot of code repetition, but - again - not as much as I'd like.&lt;/p&gt;  &lt;p&gt;The other option I had was to use a &lt;a href="http://www.codeplex.com/Gauntlet"&gt;simple code generation tool&lt;/a&gt;. In a &amp;quot;real&amp;quot; project I would probably do exactly that, but I didn't want to complicate these examples.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The Add-in&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Included in the solution is a very simple add-in that simply outputs some information when it is initialized by the host (via the &lt;code&gt;Initialize()&lt;/code&gt; method):&lt;/p&gt;  &lt;pre class="code"&gt;[&lt;span style="color: rgb(43,145,175)"&gt;AddIn&lt;/span&gt;(&lt;span style="color: rgb(163,21,21)"&gt;&amp;quot;Sample add-in&amp;quot;&lt;/span&gt;)]
&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;AddIn&lt;/span&gt; : &lt;span style="color: rgb(43,145,175)"&gt;IApplicationAddIn
&lt;/span&gt;{
    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Initialize(&lt;span style="color: rgb(43,145,175)"&gt;IHost&lt;/span&gt; host)
    {
        &lt;span style="color: rgb(43,145,175)"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: rgb(163,21,21)"&gt;&amp;quot;This is the sample add-in, running inside host with name '{0}', version {1}. AppDomain name is '{2}'.&amp;quot;&lt;/span&gt;, host.Name, host.Version, &lt;span style="color: rgb(43,145,175)"&gt;AppDomain&lt;/span&gt;.CurrentDomain.FriendlyName);
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;As you can see, it outputs the details of the host (name and version) and the name of the &lt;code&gt;AppDomain&lt;/code&gt; in which it is running (to prove we're being hosted in a separate &lt;code&gt;AppDomain&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Host&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Host &lt;/em&gt;project is a console application that activates and initializes any add-ins it finds that implement the &lt;code&gt;IApplicationAddIn&lt;/code&gt; interface. The most pertinent code is contained in the &lt;code&gt;Host.Run()&lt;/code&gt; method. This is the code that updates the add-in store, finds and activates any add-ins, and then initializes them.&lt;/p&gt;

&lt;p&gt;When you execute this project, you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SEvIwfAcOkI/AAAAAAAAAtM/KPZpks4zohc/s1600-h/image%5B30%5D.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="100" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SEvIxZmsqOI/AAAAAAAAAtQ/kVAyR110_kE/image_thumb%5B12%5D.png?imgmax=800" width="677" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MAF has strict requirements on how the pipeline and add-ins are deployed. If you've read through the MSDN documentation, you'll see recommendations on creating a solution-level &lt;em&gt;output &lt;/em&gt;folder and deploying all DLLs within there. I don't like this recommendation because it's non-standard and doesn't deal with multiple configurations (although you could have &lt;em&gt;output\Debug&lt;/em&gt; and &lt;em&gt;output\Release &lt;/em&gt;folders).&lt;/p&gt;

&lt;p&gt;In order to remain somewhat standard and not cause too much confusion, my solution builds into the output folder of the &lt;em&gt;Host &lt;/em&gt;project, as you'd expect. Under &lt;em&gt;bin\Debug &lt;/em&gt;(or &lt;em&gt;bin\Release&lt;/em&gt;) you'll find directories called &lt;em&gt;Pipeline &lt;/em&gt;and &lt;em&gt;AddIns&lt;/em&gt;. Pipeline segments and add-ins are automatically copied to these directories when you build the solution.&lt;/p&gt;

&lt;p&gt;If you're wondering how these files are copied, take a look in one of the project files. For example, crack open the &lt;em&gt;SampleAddIn.csproj &lt;/em&gt;file and you'll see this at the end:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;Target&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;Name&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: rgb(0,0,255)"&gt;AfterBuild&lt;/span&gt;&amp;quot;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;Copy&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;SourceFiles&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: rgb(0,0,255)"&gt;$(OutputPath)\SampleAddIn.dll&lt;/span&gt;&amp;quot;&lt;span style="color: rgb(0,0,255)"&gt; &lt;/span&gt;&lt;span style="color: rgb(255,0,0)"&gt;DestinationFolder&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: rgb(0,0,255)"&gt;..\Host\$(OutputPath)\AddIns\SampleAddIn&lt;/span&gt;&amp;quot;&lt;span style="color: rgb(0,0,255)"&gt;/&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163,21,21)"&gt;Target&lt;/span&gt;&lt;span style="color: rgb(0,0,255)"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Well, this has turned into a long post - and we haven't even started yet! MAF is a complex beast - &lt;a href="http://kentb.blogspot.com/2008/04/how-to-waste-3-hours-on-wednesday.html"&gt;incredibly frustrating at times&lt;/a&gt;, and yet very rewarding at others. Hopefully I have set the stage for the subsequent posts, where I will look at how some specific application scenarios can be addressed in MAF.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-3268506734858454300?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/3268506734858454300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=3268506734858454300' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3268506734858454300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3268506734858454300'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/06/maf-gymnastics-skeletal-solution.html' title='MAF Gymnastics: Skeletal Solution'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/kent.boogaart/SEvIqZWwbJI/AAAAAAAAAs8/YctnJ-G-0F4/s72-c/image%5B4%5D.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-8403955048119424567</id><published>2008-06-05T19:59:00.001+01:00</published><updated>2008-06-05T19:59:35.140+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='System.AddIn'/><category scheme='http://www.blogger.com/atom/ns#' term='MAF'/><title type='text'>MAF Gymnastics: Prologue</title><content type='html'>&lt;p&gt;The Managed Add-in Framework (MAF) was introduced in .NET 3.5. In short, it is a framework that aims to ease the burden of supporting an add-in ecosystem within your application. It provides features around add-in discovery, loading, and isolation.&lt;/p&gt;  &lt;p&gt;The benefits of a good add-in model include:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Security. Add-ins can be isolated and sand-boxed, each with its own set of permissions. &lt;/li&gt;    &lt;li&gt;Stability. Isolation also means add-ins have a limited ability to affect each other. If one add-in fails, it does not necessarily affect other add-ins. In addition, it is often possible to switch add-ins from AppDomain isolation to process isolation, which affords even more stability. &lt;/li&gt;    &lt;li&gt;Version tolerance. The host application can version independently of add-ins. If the host is developed with care, an add-in written against version 1 of the host can still work against version 2 of the host. &lt;/li&gt;    &lt;li&gt;User experience. With add-ins isolated into separate .NET AppDomains, it becomes possible to load and unload add-ins without requiring the host application be restarted. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The key to achieving these benefits is AppDomain isolation. Without it, most of these benefits cannot be realised (version tolerance is the exception). However, supporting AppDomain isolation in your application and add-ins is no walk in the park. It introduces a slew of complexities that will have you tearing your hair out in no time.&lt;/p&gt;  &lt;p&gt;This series of blog posts addresses some MAF scenarios that I believe are quite common, but have not so obvious an implementation. I haven't finalized the set of scenarios I'll be covering, but I have two written, with a further two in mind.&lt;/p&gt;  &lt;p&gt;Note that I do assume the reader has a fundamental understanding of MAF throughout this series. If you're just getting started with MAF, you should check out &lt;a href="http://msdn.microsoft.com/library/bb384241.aspx"&gt;this section in MSDN&lt;/a&gt; and read this series later.&lt;/p&gt;  &lt;p&gt;In the next post I'll provide a skeletal MAF solution which we'll be using as a starting point for subsequent posts.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-8403955048119424567?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/8403955048119424567/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=8403955048119424567' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/8403955048119424567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/8403955048119424567'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/06/maf-gymnastics-prologue.html' title='MAF Gymnastics: Prologue'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-9170480481547968406</id><published>2008-06-04T19:35:00.002+01:00</published><updated>2008-06-05T14:49:24.106+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PS3'/><title type='text'>PS3 Power Consumption</title><content type='html'>&lt;p&gt;From &lt;a href="http://news.yahoo.com/s/nm/20080603/wr_nm/power_electronics_study_dc"&gt;this article&lt;/a&gt;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Our tests found that leaving a Playstation 3 on while not in use would cost almost... five times more than it would take to run a refrigerator for the same yearly period&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;And, in response, I have this to say:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SEbgVggDPwI/AAAAAAAAAss/yvsk7YgjE70/s1600-h/P6050222%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="483" alt="P6050222" src="http://lh4.ggpht.com/kent.boogaart/SEbgXQNgX8I/AAAAAAAAAsw/Eu9AictpPkU/P6050222_thumb%5B1%5D.jpg?imgmax=800" width="644" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Yep, that's my PS3 power consumption in standby. A &lt;em&gt;massive&lt;/em&gt; &lt;strong&gt;4 watts&lt;/strong&gt;. And, in comparison, here is my microwave in standby (I can't reach my fridge socket):&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/kent.boogaart/SEbgZw9JJpI/AAAAAAAAAs0/ZaAgAD4FnOs/s1600-h/P6050224%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="483" alt="P6050224" src="http://lh5.ggpht.com/kent.boogaart/SEbgbHDi5nI/AAAAAAAAAs4/NL361pqNO0c/P6050224_thumb%5B1%5D.jpg?imgmax=800" width="644" border="0" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;All I can think of is they measured with wireless on, which may consume more power, but if they at least published specifics that would be helpful. I couldn't track down the supposed original article on choice.com.au.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;UPDATE: &lt;/strong&gt;Nope, just tested and even with wireless on it still uses a measly 4 watts when on standby.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;UPDATE 2: &lt;/strong&gt;OK, I tracked down the original article. It's &lt;a href="http://www.choice.com.au/viewArticle.aspx?id=106346&amp;catId=100245&amp;tid=100008&amp;p=1&amp;title=Computers%27+energy+costs"&gt;here&lt;/a&gt;. It turns out they were misquoted in the yahoo post. The incorrect quote is "an Australian consumer agency study has found that videogame consoles ... are major electricity guzzlers, &lt;strong&gt;even when left on stand-by&lt;/strong&gt;". However, the article itself points out that you should put consoles on stand by when not in use. Wow, revolutionary advice. Who the hell would leave a console on when they're not playing it? That's like leaving the TV on and muting it when you're not watching it. Newsflash: refrigerators are designed to be on 24/7; consoles are not.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-9170480481547968406?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/9170480481547968406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=9170480481547968406' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/9170480481547968406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/9170480481547968406'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/06/ps3-power-consumption.html' title='PS3 Power Consumption'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/kent.boogaart/SEbgXQNgX8I/AAAAAAAAAsw/Eu9AictpPkU/s72-c/P6050222_thumb%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-8556944424716864868</id><published>2008-05-18T17:53:00.001+01:00</published><updated>2008-05-18T18:31:16.445+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Build'/><title type='text'>Gauntlet V1 Released</title><content type='html'>&lt;p&gt;Today I released V1 of Gauntlet, which is a .NET code generation tool that integrates seamlessly into your build process. I've been working away at it on and off (mainly off) for a few months now, so it felt somewhat therapeutic to finally release it.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SDBn4BonEOI/AAAAAAAAAsc/Ajj9tIerBGw/s1600-h/CodeGenerationProcess%5B4%5D.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="255" alt="CodeGenerationProcess" src="http://lh3.ggpht.com/kent.boogaart/SDBn4xonEPI/AAAAAAAAAsk/PT0jc8HgUR4/CodeGenerationProcess_thumb%5B2%5D.png?imgmax=800" width="640" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;There are a wide variety of uses for Gauntlet, but here are a couple of examples:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Gaining control over the proxy classes generated for web / WCF services &lt;/li&gt;    &lt;li&gt;Generating large parts of your domain / business layer &lt;/li&gt;    &lt;li&gt;Generating constants or enumerations from sample data&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Head on over to the &lt;a href="http://www.codeplex.com/Gauntlet"&gt;Gauntlet CodePlex site&lt;/a&gt; for more information.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-8556944424716864868?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/8556944424716864868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=8556944424716864868' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/8556944424716864868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/8556944424716864868'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/05/gauntlet-v1-released.html' title='Gauntlet V1 Released'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/kent.boogaart/SDBn4xonEPI/AAAAAAAAAsk/PT0jc8HgUR4/s72-c/CodeGenerationProcess_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-3929753213179598022</id><published>2008-05-15T19:47:00.001+01:00</published><updated>2008-05-15T19:47:10.208+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Expander and VisualBrush</title><content type='html'>&lt;p&gt;Today I was trying to implement some drag and drop spiffiness by including a semi-transparent preview of the item being dragged. Basically when the user starts dragging something, it &amp;quot;tears off&amp;quot; and follows the mouse cursor, so they can see exactly what they're dragging. Like I said: spiffy. Don't deny it.&lt;/p&gt;  &lt;p&gt;Sounds like a job for &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.media.visualbrush.aspx"&gt;VisualBrush&lt;/a&gt;, and indeed it is. I was able to get this working pretty nicely, but noticed a weird problem with &lt;code&gt;Expander&lt;/code&gt;s. Basically, if you expand and then collapse an &lt;code&gt;Expander&lt;/code&gt;, and then use a &lt;code&gt;VisualBrush&lt;/code&gt; to clone it, the &lt;code&gt;VisualBrush&lt;/code&gt; will clone both the header of the &lt;code&gt;Expander&lt;/code&gt;, and the white space the &lt;code&gt;Expander&lt;/code&gt; previously occupied when expanded. &lt;/p&gt;  &lt;p&gt;&lt;em&gt;Huh?&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Let me explain with pictures. Say you've got an &lt;code&gt;Expander&lt;/code&gt;: &lt;/p&gt;  &lt;p&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="161" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SCyFJRonEKI/AAAAAAAAAr8/K_QtCGfjW0M/image%5B44%5D.png?imgmax=800" width="258" border="0" /&gt;&lt;/p&gt;  &lt;p&gt;And you then expand it, and subsequently collapse it: &lt;/p&gt;  &lt;p&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="161" alt="image" src="http://lh4.ggpht.com/kent.boogaart/SCyFKBonELI/AAAAAAAAAsE/qz10kiYd1Wo/image%5B38%5D.png?imgmax=800" width="258" border="0" /&gt;&amp;#160;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="161" alt="image" src="http://lh5.ggpht.com/kent.boogaart/SCyFJRonEKI/AAAAAAAAAr8/K_QtCGfjW0M/image%5B44%5D.png?imgmax=800" width="258" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;Then then your code creates a &lt;code&gt;VisualBrush&lt;/code&gt; around the &lt;code&gt;Expander&lt;/code&gt; like this: &lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: rgb(43,145,175)"&gt;Rect&lt;/span&gt; rect = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Rect&lt;/span&gt;(0, 0, _expander.RenderSize.Width, _expander.RenderSize.Height);
&lt;span style="color: rgb(43,145,175)"&gt;VisualBrush&lt;/span&gt; visualBrush = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;VisualBrush&lt;/span&gt;(_expander);
_rectangle.Fill = visualBrush;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;What you get looks like this: &lt;/p&gt;

&lt;p&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="161" alt="image" src="http://lh6.ggpht.com/kent.boogaart/SCyFKhonEMI/AAAAAAAAAsM/cEcoxTIrjE8/image%5B50%5D.png?imgmax=800" width="258" border="0" /&gt; &lt;/p&gt;

&lt;p&gt;What the...? What's happened here is what I described above. The size of the &lt;code&gt;Rectangle&lt;/code&gt; hosting the &lt;code&gt;VisualBrush&lt;/code&gt; is correct. However, the snapshot the &lt;code&gt;VisualBrush&lt;/code&gt; has taken of the &lt;code&gt;Expander&lt;/code&gt; is incorrect because it includes white-space below the header, even though the &lt;code&gt;Expander&lt;/code&gt; is collapsed. &lt;/p&gt;

&lt;p&gt;As I discovered, &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1069807&amp;amp;SiteID=1"&gt;other people have come up against this problem too&lt;/a&gt;, but no solution was apparent. Thus, I set about to find one. &lt;/p&gt;

&lt;p&gt;And here it is: &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: rgb(43,145,175)"&gt;Rect&lt;/span&gt; rect = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Rect&lt;/span&gt;(0, 0, _expander.RenderSize.Width, _expander.RenderSize.Height);
&lt;span style="color: rgb(43,145,175)"&gt;VisualBrush&lt;/span&gt; visualBrush = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;VisualBrush&lt;/span&gt;(_expander);

&lt;strong&gt;visualBrush.ViewboxUnits = &lt;span style="color: rgb(43,145,175)"&gt;BrushMappingMode&lt;/span&gt;.Absolute;
visualBrush.Viewbox = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;Rect&lt;/span&gt;(_expander.TranslatePoint(rect.TopLeft, &lt;span style="color: rgb(0,0,255)"&gt;this&lt;/span&gt;), rect.Size);
&lt;/strong&gt;
_rectangle.Fill = visualBrush;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;This time we get the expected result: &lt;/p&gt;

&lt;p&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="161" alt="image" src="http://lh4.ggpht.com/kent.boogaart/SCyFLBonENI/AAAAAAAAAsU/qy_zZzK10v8/image%5B56%5D.png?imgmax=800" width="258" border="0" /&gt; &lt;/p&gt;

&lt;p&gt;The trick is to use absolute units for the view box, and to translate the &lt;code&gt;Rectangle&lt;/code&gt; relative to the host. This doesn't really explain the bug, but it does work around it. You can download the sample project (pictured in the images above) right about &lt;a href="http://www.users.on.net/~kentcb/visualbrush/VisualBrushBug.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-3929753213179598022?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/3929753213179598022/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=3929753213179598022' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3929753213179598022'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/3929753213179598022'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/05/expander-and-visualbrush.html' title='Expander and VisualBrush'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/kent.boogaart/SCyFJRonEKI/AAAAAAAAAr8/K_QtCGfjW0M/s72-c/image%5B44%5D.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-5654857650764366962</id><published>2008-04-28T20:09:00.001+01:00</published><updated>2011-09-03T18:12:31.167+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Dispatcher Frames</title><content type='html'>&lt;p&gt;With scant exception, WPF controls must be accessed from the same thread on which they were created. Because of this, we say they have 'thread affinity'. &lt;/p&gt;  &lt;p&gt;In WPF, thread affinity is realised via &lt;code&gt;DispatcherObject&lt;/code&gt;s, which can be accessed directly only on the thread on which they were created. Alternatively, they can be accessed via their &lt;code&gt;Dispatcher&lt;/code&gt;. The &lt;code&gt;Dispatcher&lt;/code&gt; contains methods for adding operations to a queue which is processed on the &lt;code&gt;Dispatcher&lt;/code&gt;'s thread. Each thread has at most one &lt;code&gt;Dispatcher&lt;/code&gt; instance associated with it (which is created on demand). Many WPF classes - including controls such as &lt;code&gt;TextBox&lt;/code&gt; and &lt;code&gt;Button&lt;/code&gt; - inherit from &lt;code&gt;DispatcherObject&lt;/code&gt;. This means that accessing instances of these controls must be done on the control's thread, possibly via the control's &lt;code&gt;Dispatcher&lt;/code&gt;. &lt;/p&gt;  &lt;p&gt;You may have noticed a type called &lt;code&gt;DispatcherFrame&lt;/code&gt; whilst browsing MSDN (as you may be inclined to do on a Saturday night. Or not). That's what I want to discuss in this post. &lt;/p&gt;  &lt;p&gt;You can think of a &lt;code&gt;DispatcherFrame&lt;/code&gt; as something that forces operations to be processed until some condition is met. Every WPF application has at least one &lt;code&gt;DispatcherFrame&lt;/code&gt; that is created when you run the application. It will continue pumping operations until the application is shut down. &lt;/p&gt;  &lt;p&gt;At times it can be useful to pump operations until some condition of your own is met. Perhaps your code is executing on the UI thread and you want to empty the queue of operations in the &lt;code&gt;Dispatcher&lt;/code&gt; to force control and screen updates. In the Winforms world, this is achieved via a call to &lt;font face="Courier New"&gt;Application.DoEvents()&lt;/font&gt;. In WPF, there is no equivalent method, but we can easily simulate one: &lt;/p&gt;  &lt;pre class="brush: c-sharp; toolbar: false"&gt;public static void DoEvents(this Application application)
{
    DispatcherFrame frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new ExitFrameHandler(frm =&amp;gt; frm.Continue = false), frame);
    Dispatcher.PushFrame(frame);
}

private delegate void ExitFrameHandler(DispatcherFrame frame);&lt;/pre&gt;


&lt;p&gt;The above code is part of a small demo project, which you can download &lt;a href="http://www.users.on.net/~kentcb/doevents/DoEvents.zip"&gt;here&lt;/a&gt;. It adds a &lt;code&gt;DoEvents()&lt;/code&gt; method to WPF's &lt;code&gt;Application&lt;/code&gt; class. The &lt;code&gt;DoEvents()&lt;/code&gt; method adds a &lt;code&gt;Background&lt;/code&gt; priority operation to the &lt;code&gt;Dispatcher&lt;/code&gt;'s queue, and then pushes a new frame that pumps operations until that operation is processed. As a result, all other operations that were already queued in the &lt;code&gt;Dispatcher&lt;/code&gt; will be processed. There are several important things I need to point out here: &lt;/p&gt;

&lt;p&gt;1. Adding the new operation to the &lt;code&gt;Dispatcher&lt;/code&gt; is done asynchronously. As such, the operation is not processed until we call &lt;code&gt;PushFrame()&lt;/code&gt;. 

  &lt;br /&gt;2. The choice of &lt;code&gt;Background&lt;/code&gt; as the priority is important. If we were to choose a higher priority (such as &lt;code&gt;Render&lt;/code&gt;), then we would potentially leave lower-priority operations in the queue after the frame had exited. That's because our operation would be executed prior to those lower-priority operations, and thus we'd end the frame too soon. Perhaps there's value in adding a &lt;code&gt;DoEvents()&lt;/code&gt; overload that accepts a minimum priority of operations that should be executed, but I haven't included one in the download. 

  &lt;br /&gt;3. Operations in a &lt;code&gt;Dispatcher&lt;/code&gt; are not associated with a particular &lt;code&gt;DispatcherFrame&lt;/code&gt;. A &lt;code&gt;DispatcherFrame&lt;/code&gt; can cause any queued operation to be processed, not just those added after the frame is pushed. 

  &lt;br /&gt;4. The code assumes it is running on the thread whose &lt;code&gt;Dispatcher&lt;/code&gt; should be pumped. &lt;/p&gt;

&lt;p&gt;A &lt;code&gt;DoEvents()&lt;/code&gt; implementation is nice for illustrating the utility of &lt;code&gt;DispatcherFrame&lt;/code&gt;s (indeed it is used in the MSDN documentation too), but I believe it is unnecessary. As you can see in the demo, it is possible to simulate &lt;code&gt;DoEvents()&lt;/code&gt; in a much simpler fashion: by synchronously adding a low-priority no-op to the &lt;code&gt;Dispatcher&lt;/code&gt;'s queue: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public static void DoEvents(this Application application)
{
    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new VoidHandler(() =&amp;gt; { }));
}

private delegate void VoidHandler();&lt;/pre&gt;


&lt;p&gt;The call to &lt;code&gt;Invoke()&lt;/code&gt; will not return until our operation has been processed, which won't be until all higher priority operations are processed. Therefore, the end result is the same - all queued operations are pumped (apart from those with a priority lower than &lt;code&gt;Background&lt;/code&gt;, but I'm ignoring that in this post). &lt;/p&gt;

&lt;p&gt;So where would you use a &lt;code&gt;DispatcherFrame&lt;/code&gt;? &lt;/p&gt;

&lt;p&gt;I recently had need for one at my day job. We have a splash screen that usually just shows progress information (downloading files, searching for modules etcetera) but sometimes needs to ask the user which catalog they would like to load (a catalog is just a set of modules). &lt;/p&gt;

&lt;p&gt;The splash presenter tries as hard as it can not to ask the user (if they only have one catalog, or it has been specified via a command line switch then it doesn't need to ask), but if it does need to, it delegates a call to the splash view on the UI thread. This call needs to return the catalog that the user selected. However, it has been called on the UI thread, so obtaining a catalog from the user requires pumping operations so they can select one from a list. The code looks like this: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;public Catalog SelectCatalog(ICollection&amp;lt;Catalog&amp;gt; availableCatalogs)
{
    StatusLabel = &amp;quot;Please select a catalog:&amp;quot;;
    _catalogsItemsControl.ItemsSource = availableCatalogs;

    _catalogSelectionFrame = new DispatcherFrame(true);
    Dispatcher.PushFrame(_catalogSelectionFrame);
    StatusLabel = &amp;quot;Thank you&amp;quot;;     _catalogsItemsControl.ItemsSource = null;

    return _selectedCatalog;
}&lt;/pre&gt;

&lt;p&gt;This method sets up the catalogs for the user to select from by assigning them to an &lt;code&gt;ItemsControl&lt;/code&gt; (which renders each catalog as a hyperlink). It then pushes a new &lt;code&gt;DispatcherFrame&lt;/code&gt;, which blocks until the frame is stopped. After the &lt;code&gt;DispatcherFrame&lt;/code&gt; finishes, the selected catalog is returned. The only way to end the frame is by clicking on one of the hyperlinks representing the catalogs. Each hyperlink rendered by the &lt;code&gt;ItemsControl&lt;/code&gt; has a &lt;code&gt;Click&lt;/code&gt; handler as follows: &lt;/p&gt;

&lt;pre class="brush: c-sharp; toolbar: false"&gt;private void _hyperlink_Click(object sender, EventArgs e)
{
    _selectedCatalog = (sender as Hyperlink).DataContext as Catalog;
    _catalogSelectionFrame.Continue = false;
}&lt;/pre&gt;

&lt;p&gt;When a hyperlink is clicked, I store the selected catalog and then end the &lt;code&gt;DispatcherFrame&lt;/code&gt;. As a result, the code that pushed the &lt;code&gt;DispatcherFrame&lt;/code&gt; will continue execution. Note that I would not have to manually track the selected catalog if I was using a &lt;code&gt;ListBox&lt;/code&gt;, but for now I'm using with the &lt;code&gt;ItemsControl&lt;/code&gt; because it was simpler to style. &lt;/p&gt;

&lt;p&gt;Above I suggested that the only way to end the &lt;code&gt;DispatcherFrame&lt;/code&gt; was by setting &lt;code&gt;DispatcherFrame.Continue&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;. That's not the entire story. &lt;code&gt;DispatcherFrame&lt;/code&gt;s may also be asked to stop during application shutdown. When that happens, &lt;code&gt;DispatcherFrame&lt;/code&gt;s will, by default, comply with the request. However, there is a constructor overload that allows you to bypass this behaviour and instead continue processing operations until your condition is met. This might be useful for a short-lived frame whose completion is critical to the correctness of your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.users.on.net/~kentcb/doevents/DoEvents.zip"&gt;Download Demo&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-5654857650764366962?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/5654857650764366962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=5654857650764366962' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/5654857650764366962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/5654857650764366962'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/04/dispatcher-frames.html' title='Dispatcher Frames'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-4221870483049382901</id><published>2008-04-19T12:51:00.001+01:00</published><updated>2008-04-19T12:51:31.967+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UK/Europe'/><category scheme='http://www.blogger.com/atom/ns#' term='Family'/><title type='text'>Berlin</title><content type='html'>&lt;p&gt;Last weekend we headed to Berlin. We stayed south-east of the city, in the appropriately-named &lt;em&gt;Holiday Inn&lt;/em&gt;. Friday night was basically a write-off, since we didn't arrive until around 10PM. On Saturday we had a late breakfast and then headed into the City.&lt;/p&gt;  &lt;p&gt;Unfortunately, the &lt;a href="http://en.wikipedia.org/wiki/S9_(Berlin)"&gt;S9 line&lt;/a&gt; which connected us to the centre of the city was under weekend maintenance, so it was a time-consuming process getting anywhere. This is one of the train stations we waited at (Betriebsbahnhof Sch&amp;#246;neweide):&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SAncJe6VsWI/AAAAAAAAAm4/aGnWTvJ7inc/s1600-h/P4120023%5B4%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4120023" src="http://lh6.ggpht.com/kent.boogaart/SAncK-6VsXI/AAAAAAAAAnA/j_N79MGhMmY/P4120023_thumb%5B2%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SAncL-6VsYI/AAAAAAAAAnI/v_cmm7TGP3w/s1600-h/P4120025%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4120025" src="http://lh4.ggpht.com/kent.boogaart/SAncNe6VsZI/AAAAAAAAAnQ/nmQJU2Tmv54/P4120025_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Eventually we made it into the city and headed to the &lt;a href="http://en.wikipedia.org/wiki/Berlin_Zoo"&gt;Berlin Zoo&lt;/a&gt;, which was fantastic:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SAncPu6VsaI/AAAAAAAAAnY/8LqnzIT5EW0/s1600-h/P4120031%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4120031" src="http://lh3.ggpht.com/kent.boogaart/SAncQO6VsbI/AAAAAAAAAng/LNysHtVaAHs/P4120031_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SAncRe6VscI/AAAAAAAAAno/8A7ndJ2CoJo/s1600-h/P4120036%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P4120036" src="http://lh3.ggpht.com/kent.boogaart/SAncSO6VsdI/AAAAAAAAAnw/rhoitOGHNVs/P4120036_thumb%5B1%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SAncS-6VseI/AAAAAAAAAn4/F7Xot_vhCwI/s1600-h/P4120039%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P4120039" src="http://lh5.ggpht.com/kent.boogaart/SAncTu6VsfI/AAAAAAAAAoA/MzKF2rKCW20/P4120039_thumb%5B1%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/kent.boogaart/SAncVO6VsgI/AAAAAAAAAoI/pAkxM95246I/s1600-h/P4120044%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4120044" src="http://lh4.ggpht.com/kent.boogaart/SAncWe6VshI/AAAAAAAAAoQ/9gn1z5_BUMs/P4120044_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SAncXe6VsiI/AAAAAAAAAoY/MIkHcK0_aBU/s1600-h/P4120060%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4120060" src="http://lh3.ggpht.com/kent.boogaart/SAncYO6VsjI/AAAAAAAAAog/D7ycWHunjDw/P4120060_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; (poor photo, but I just love black panthers. All cats want to be them)&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SAncZ-6VskI/AAAAAAAAAoo/XQHR_lAe25c/s1600-h/P4130072%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4130072" src="http://lh5.ggpht.com/kent.boogaart/SAncau6VslI/AAAAAAAAAo0/U1FJOiRuXNs/P4130072_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SAncb-6VsmI/AAAAAAAAAo8/mOOtpKcqQ74/s1600-h/P4130076%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4130076" src="http://lh5.ggpht.com/kent.boogaart/SAnccu6VsnI/AAAAAAAAApE/GBOBSMITttY/P4130076_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/kent.boogaart/SAncd-6VsoI/AAAAAAAAApM/zh58oIjni9o/s1600-h/P4130087%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4130087" src="http://lh4.ggpht.com/kent.boogaart/SAncee6VspI/AAAAAAAAApU/43xutWkJmYE/P4130087_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SAncfu6VsqI/AAAAAAAAApc/N_ZFOantmBk/s1600-h/P4130094%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4130094" src="http://lh4.ggpht.com/kent.boogaart/SAncge6VsrI/AAAAAAAAApk/iuNfT5RBQRw/P4130094_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SAnche6VssI/AAAAAAAAAps/8XfNsDjTvuI/s1600-h/P4130097%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P4130097" src="http://lh3.ggpht.com/kent.boogaart/SAnciO6VstI/AAAAAAAAAp0/dGsb3wXouqc/P4130097_thumb%5B1%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SAncje6VsuI/AAAAAAAAAp8/wPtYHV5WyYo/s1600-h/P4130104%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4130104" src="http://lh3.ggpht.com/kent.boogaart/SAnckO6VsvI/AAAAAAAAAqE/d64OQetC-I0/P4130104_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SAncmu6VswI/AAAAAAAAAqM/iATKkCw3Omk/s1600-h/P4130106%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4130106" src="http://lh4.ggpht.com/kent.boogaart/SAncne6VsxI/AAAAAAAAAqU/NvAbhtpTxLw/P4130106_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SAncou6VsyI/AAAAAAAAAqc/AXJXMvWpmfY/s1600-h/P4130109%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4130109" src="http://lh3.ggpht.com/kent.boogaart/SAncpO6VszI/AAAAAAAAAqk/P04idSYR4KI/P4130109_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/kent.boogaart/SAncqO6Vs0I/AAAAAAAAAqs/n6xAPAXMJIY/s1600-h/P4130111%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P4130111" src="http://lh6.ggpht.com/kent.boogaart/SAncq-6Vs1I/AAAAAAAAAq0/Y4owM6o_CqM/P4130111_thumb%5B1%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/kent.boogaart/SAncsO6Vs2I/AAAAAAAAAq8/zczXZm7EDhg/s1600-h/P4130118%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4130118" src="http://lh6.ggpht.com/kent.boogaart/SAncs-6Vs3I/AAAAAAAAArE/L-BqRRYm_RA/P4130118_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;On Sunday we wanted to visit &lt;a href="http://en.wikipedia.org/wiki/Fernsehturm"&gt;Fernsehturm&lt;/a&gt;, which is a 365 metre high tower in central Berlin. After waiting for 40 minutes or so, we gave up because the line wasn't moving. However, here are some pictures of the tower:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kent.boogaart/SAncte6Vs4I/AAAAAAAAArM/qVDaSS0pcR4/s1600-h/P4130174%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P4130174" src="http://lh6.ggpht.com/kent.boogaart/SAnct-6Vs5I/AAAAAAAAArU/IW-19PANQTM/P4130174_thumb%5B1%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/kent.boogaart/SAncuu6Vs6I/AAAAAAAAArc/FFgDtuR8aOA/s1600-h/P4130183%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="260" alt="P4130183" src="http://lh6.ggpht.com/kent.boogaart/SAncu-6Vs7I/AAAAAAAAArk/pDAveytmClc/P4130183_thumb%5B1%5D.jpg?imgmax=800" width="200" border="0" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/kent.boogaart/SAncwO6Vs8I/AAAAAAAAArs/fcizONkqYqo/s1600-h/P4130179%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="200" alt="P4130179" src="http://lh5.ggpht.com/kent.boogaart/SAncwu6Vs9I/AAAAAAAAAr0/uTv5mjIH9JE/P4130179_thumb%5B1%5D.jpg?imgmax=800" width="260" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The people in Berlin were very nice, and the weather was perfect. Overall it was a great weekend, although we would have liked more time to fully appreciate it.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-4221870483049382901?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/4221870483049382901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=4221870483049382901' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4221870483049382901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/4221870483049382901'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/04/berlin.html' title='Berlin'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/kent.boogaart/SAncK-6VsXI/AAAAAAAAAnA/j_N79MGhMmY/s72-c/P4120023_thumb%5B2%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-2327539582876441659</id><published>2008-04-18T18:19:00.001+01:00</published><updated>2008-04-18T18:19:55.138+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='SCSFContrib'/><category scheme='http://www.blogger.com/atom/ns#' term='SCSF'/><title type='text'>SCSFContrib 1.5</title><content type='html'>&lt;p&gt;Admittedly, it has been far too long, but the &lt;a href="http://www.codeplex.com/scsfcontrib"&gt;SCSFContrib&lt;/a&gt; team have finally released version 1.5. The highlights of this release are:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;New Features&lt;/b&gt;      &lt;ul&gt;       &lt;li&gt;All solution and projects migrated to &lt;b&gt;Visual Studio 2008&lt;/b&gt; and &lt;b&gt;.NET Framework 3.5&lt;/b&gt;. &lt;/li&gt;        &lt;li&gt;&lt;b&gt;DockPanelWorkspace&lt;/b&gt; and &lt;b&gt;FormWorkspace&lt;/b&gt; added to &lt;b&gt;SCSFContrib.CompositeUI.WinForms&lt;/b&gt; project. &lt;/li&gt;        &lt;li&gt;&lt;b&gt;Action Catalog Service&lt;/b&gt; added to &lt;b&gt;SCSFContrib.Services&lt;/b&gt; project. &lt;/li&gt;        &lt;li&gt;Added Visual Studio templates and Installer for &lt;b&gt;Trusted&lt;/b&gt; and &lt;b&gt;Untrusted&lt;/b&gt; modules in the WPF/CAB Shell. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;b&gt;New Samples&lt;/b&gt;      &lt;ul&gt;       &lt;li&gt;&lt;b&gt;BankTeller&lt;/b&gt; implementation using a pure WPF application. &lt;/li&gt;        &lt;li&gt;&lt;b&gt;Demo Application&lt;/b&gt; with its &lt;b&gt;Demo Script&lt;/b&gt; that provides step-by-step instructions to create a SC-SF application. &lt;/li&gt;        &lt;li&gt;&lt;b&gt;OrdersManager&lt;/b&gt; application that demonstrates how to integrate the CAB and SC-SF with Windows Workflow Foundation. &lt;/li&gt;        &lt;li&gt;&lt;b&gt;TestSuite&lt;/b&gt; reference application showing DockPanelWorkspace usage. &lt;/li&gt;        &lt;li&gt;&lt;b&gt;WPF CAB Shell&lt;/b&gt; sample application (source code, libs and unit tests). &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;You can head over to the &lt;a href="http://www.codeplex.com/scsfcontrib"&gt;SCSFContrib CodePlex site&lt;/a&gt; to download. Enjoy!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7162298-2327539582876441659?l=kentb.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kentb.blogspot.com/feeds/2327539582876441659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7162298&amp;postID=2327539582876441659' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2327539582876441659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7162298/posts/default/2327539582876441659'/><link rel='alternate' type='text/html' href='http://kentb.blogspot.com/2008/04/scsfcontrib-15.html' title='SCSFContrib 1.5'/><author><name>Kent Boogaart</name><uri>http://www.blogger.com/profile/06987380257555679530</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7162298.post-6182618041958689942</id><published>2008-04-02T20:26:00.001+01:00</published><updated>2008-04-02T20:26:04.205+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='System.AddIn'/><title type='text'>How to Waste 3 Hours on a Wednesday Afternoon</title><content type='html'>&lt;p&gt;I'm playing around with the new to 3.5 &lt;code&gt;System.AddIn&lt;/code&gt; stack at the moment. In short, it allows you to provide version tolerance between components. This is commonly used in with add-ins.&lt;/p&gt;  &lt;p&gt;Anyways, the thing that sits between the host and add-ins is called the pipeline. It consists of a bunch of assemblies - a host view, host adapter, contracts, add-in adapter and add-in view. If the stars are aligned and the gods bestow you with grace, you will eventually get these assemblies to work.&lt;/p&gt;  &lt;p&gt;Experiencing this pain, you may look to &lt;a href="http://www.codeplex.com/clraddins/Wiki/View.aspx?title=Pipeline%20Builder&amp;amp;referringTitle=Home"&gt;Pipeline Builder&lt;/a&gt;, a tool that helps to generate the views and adapters from the contract. That's what I did anyway. But I found that the lack of control over the generated code was causing me headaches (using templates would be nice), and the limitations of the tool mean that you'll end up with some generated code and some manually written. This wound up being way too painful to troubleshoot and maintain and I'd rather just have full control over the code for now.&lt;/p&gt;  &lt;p&gt;Sound like a plan, Stan? Since I was taking full control over the code I thought I'd go the whole hog and refactor common functionality into helper classes. Instead of an adapter that looked like this:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;IAddInContractToViewAddInAdapter&lt;/span&gt; : Contracts.AddInViews.IAddIn
{
    &lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; Contracts.IAddInContract _contract;
    &lt;span style="color: rgb(0,0,255)"&gt;private&lt;/span&gt; System.AddIn.Pipeline.ContractHandle _handle;
    &lt;span style="color: rgb(0,0,255)"&gt;static&lt;/span&gt; IAddInContractToViewAddInAdapter()
    {
    }
    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; IAddInContractToViewAddInAdapter(Contracts.IAddInContract contract)
    {
        _contract = contract;
        _handle = &lt;span style="color: rgb(0,0,255)"&gt;new&lt;/span&gt; System.AddIn.Pipeline.ContractHandle(contract);
    }
    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Initialize(Contracts.AddInViews.IHost host)
    {
        _contract.Initialize(Contracts.AddInSideAdapters.IHostAddInAdapter.ViewToContractAdapter(host));
    }
    &lt;span style="color: rgb(0,0,255)"&gt;internal&lt;/span&gt; Contracts.IAddInContract GetSourceContract()
    {
        &lt;span style="color: rgb(0,0,255)"&gt;return&lt;/span&gt; _contract;
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;After a bit of refactoring, I ended up with this:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;class&lt;/span&gt; &lt;span style="color: rgb(43,145,175)"&gt;ContractToViewAdapter_IAddIn&lt;/span&gt; : &lt;span style="color: rgb(43,145,175)"&gt;ContractToViewAdapterBase&lt;/span&gt;&amp;lt;&lt;span style="color: rgb(43,145,175)"&gt;IAddInContract&lt;/span&gt;&amp;gt;, &lt;span style="color: rgb(43,145,175)"&gt;IAddIn
&lt;/span&gt;{
    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; ContractToViewAdapter_IAddIn(&lt;span style="color: rgb(43,145,175)"&gt;IAddInContract&lt;/span&gt; contract)
        : &lt;span style="color: rgb(0,0,255)"&gt;base&lt;/span&gt;(contract)
    {
    }

    &lt;span style="color: rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0,0,255)"&gt;void&lt;/span&gt; Initialize(&lt;span style="color: rgb(43,145,175)"&gt;IHost&lt;/span&gt; host)
    {
        SourceContract.Initialize(&lt;span style="color: rgb(43,145,175)"&gt;Adapt&lt;/span&gt;.ToContract&amp;lt;&lt;span style="color: rgb(43,145,175)"&gt;IHost&lt;/span&gt;, &lt;span style="color: rgb(43,145,175)"&gt;IHostContract&lt;/span&gt;, &lt;span style="color: rgb(43,145,175)"&gt;ViewToContractAdapter_IHost&lt;/span&gt;&amp;gt;(host));
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Nice. The &lt;code&gt;ContractToViewAdapterBase&amp;lt;TContract&amp;gt;&lt;/code&gt; class provides all the functionality around exposing the source contract and maintaining the &lt;code&gt;ContractHandle&lt;/code&gt;. I also have a generic &lt;code&gt;Adapt&lt;/code&gt; class that takes on the task of converting views to contracts and vice-versa. The Pipeline Builder generates a separate class for every contract - yuck.&lt;/p&gt;

&lt;p&gt;Once I had taken complete control of the code I managed to reduce it in size and complexity significantly. Problem is, it didn't work. All I got was this warning:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;No usable HostAdapter parts could be found in assembly &amp;quot;...HostSideAdapters.dll&amp;quot;.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Um, right. My host adapter was definitely in the assembly and definitely marked with the &lt;code&gt;HostAdapter&lt;/code&gt; attribute. So what was going on?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;System.AddIn&lt;/code&gt; does its very best to make your life a living hell when something doesn't work. There's no trace statements, meaningful exceptions are suppressed, and if you're lucky enough to get a warning message it's usually cryptic and unhelpful. Oh, and the source and symbols for &lt;code&gt;System.AddIn&lt;/code&gt; are not available yet, so you're on your own there, too.&lt;/p&gt;

&lt;p&gt;After pulling some hair out I managed to figure out why my adapters weren't being found. It's because they inherit from a generic type. Yep, that's right. Even though the adapter itself is a closed type, &lt;code&gt;System.AddIn&lt;/code&gt; spits it because I inherited
