WPF - skinning the ComboBox moving the DropDown Menu around

A couple of days ago a friend of mine asked for some help in skinning a WPF ComboBox control, he had a special need in which the dropdown menu items list of the control had to be aligned to the right side of the ComboBox and had to expand in the left direction (instead of the usual visual appearance, which has the opposite behavior: it is anchored to the left side of the control and expands to the right).

I asked him to build a very simple test project containing the control and its current skin and pass it to me, this is a picture of what he obtained at that time.

SkinningComboboxDropDown1

I have to admit I’m not a very good designer nor a graphic expert so I got the basic control template extracting it using Blend and I looked at it, here is a snippet of the original XAML from the template:

<ControlTemplate TargetType="{x:Type ComboBox}">
	<Grid x:Name="MainGrid" SnapsToDevicePixels="true">
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="*"/>
			<ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
		</Grid.ColumnDefinitions>
		<Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
			<Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}">
				<Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
					<ScrollViewer CanContentScroll="true">
						<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
					</ScrollViewer>
				</Border>
			</Microsoft_Windows_Themes:SystemDropShadowChrome>
		</Popup>
		<ToggleButton BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ComboBoxReadonlyToggleButton2}"/>
		<ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
	</Grid>
	<ControlTemplate.Triggers>
		<Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
			<Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5"/>
			<Setter Property="Color" TargetName="Shdw" Value="#71000000"/>
		</Trigger>
		<Trigger Property="HasItems" Value="false">
			<Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
		</Trigger>
		<Trigger Property="IsEnabled" Value="false">
			<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
			<Setter Property="Background" Value="#FFF4F4F4"/>
		</Trigger>
		<Trigger Property="IsGrouping" Value="true">
			<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
		</Trigger>
	</ControlTemplate.Triggers>
</ControlTemplate>

WP7 - Backup Service

I hate when I loose my application data and there are times when developing a Windows Phone 7 Application that your IsolatedStorage data gets simply discarded when deploy an application from Visual Studio.

This usually happens when you perform a solution cleanup or a complete rebuild; when you deploy you application again on the phone all your previously saved data are simply wiped out. This happens because under these circumstances Visual Studio performs a complete uninstall of your application before installing the new version.

In order to prevent (better to say...to limit) this scenario and to give the applications the ability to backup/restore their data I’ve created a solution project that you can use to create dump images of all the IsolatedStorage data that are tied with your application.

The concept idea is nothing new really: have a WCF service you can use to stream your files back and forth between your WP7 and PC. It is actually the easiest way you can solve this problem; it has been suggested in various resources along the internet but I wasn’t able to find a complete working solution, so I took the weekend and put on my own project on the road.

Let’s start with some project requirements:

  • The backup/restore service must be generic: that is it must be suitable for any kind of applications and not built for a specific scenario in mind.
  • The backup service should be able to handle more than a single application; we will identify the different application with an Application string tag.
  • It should support different backup set for the same application (ideally you would be able to create multiple backup/restore points), each backup set will be identified by a given name.
  • It should preserve the folders and file structure your application have created on the IsolatedStorage (we just want to dump all the files, so we can inspect and edit them if needed before restoring the state).
  • The WCF service should be self hosted inside a WPF application, I do not want to force people to configure it in IIS, they just have to launch an exe on their PC (using administrative rights).

What I wasn’t worried about in this version:

  • The backup/restore operation isn’t protected against ‘tombstoning’, if your process gets interrupted in the middle you will likely have to start it over again. It is a SAFE procedure anyway, we are reading all the files while backing up, nothing gets (or should) altered at this stage. And if the process is interrupted during the restore stage, just start it all over again (you have a working copy of your data on the disk anyway).
  • Lack of progress notification, you will just get an event raised when the operations are completed.

I will not discuss every aspect of the project, because it isn’t really complex (and you will also have the full source code to check and use, just mention me if you do  Smile), so without further ado here is the solution structure:

  • WP7BackupService - this project holds the WPF application that hosts the WCF service, it defines the basic interface and classes you use to interact with the service.
  • WP7BackupServicePhone - this is the WP7 project holds reference to the WCF service and exposes the helper class you will use to initialize the backup sets and perform the backup and restore operations.

WP7BackupService

This project is quite straightforward, so I won’t dig into it too much, I’ll just report some of the interfaces and classes that are used to define the WCF service and its interactions with the outside world.

/// <summary>
/// A class that defines the file to upload
/// </summary>
[DataContract]
public class FileUploadInfo
{
	/// <summary>
	/// the specific application for which we are storing the file
	/// </summary>
	[DataMember]
	public string Application;

WP7 - A DataContractSerializer Bug ?

As we saw in the previous article the DataContractSerializer is able to serialize and deserialize class hierarchies, let’s review the example again:

[DataContract]
public class Entity
{
	public int M1;

WP7 - Understanding Serialization

While I was learning and writing my first WP7 application I realized that understanding the serialization mechanism is vital if you want to write a WP7 application. You will probably end up using it when persisting data to the isolated storage and (implicitly) when you save the application state to the page state or to the global application state object.

So I’m writing this post as a reminder to myself and to summarize some of the key points of the matter.

WP7 actually supports two different types of serialization:

  • Binary Serialization - this is the fastest and most compact form of serialization, but it’s also the less flexible one. 
    (as correctly pointed out by Greg Finzer there's no built-in binary serialization in WP7, you need to write your own).
  • Xml Serialization.
  • DataContract Serialization - this is the default method used by the framework when it serializes and deserializes objects to the different application state dictionaries.

I will not dig into every detail of them because there is already a lot of documentation around (especially in MSDN). The rest of the post will mainly deal with DataContract serialization.

To be able to use the DataContractSerializer effectively you have to remind that:

  • You can serialize public types, fields and properties; your properties must have a getter and a setter in order to be serialized (you will incur in an exception if you try to serialize a public property without a getter).
  • DataContractSerializer works with an opt-in philosophy, which means that you need to specify what you want to serialize using [DataContract] (for classes) and [DataMember] (for field and properties) attributes.
  • If you do not specify the [DataContract] and [DataMember] attributes and your type is a public type, any public property and field will be serialized.
  • You can ‘break the rule’ and persist an internal class or internal members if you mark the assemblies containing your types with the [InternalsVisibleTo] attribute with something like:
    [assembly: InternalsVisibleTo("System.Runtime.Serialization")]

    but this isn’t recommended and the documentation explicitly says that this attribute should not be used directly in our code. If you do not specify that attribute you will get a SecurityException when trying to serialize an internal class.
  • During deserialization the object Constructor will not be called. So if you have part of you object initialization logic in the constructor do not expect it to be called during deserialization. You will need to refactor it to a method and call it after the object deserialize. The following code snippet shows an example:
    [DataContract]
    public class EntityWithConstructor
    {
    	public string M1;
    
    

Visual Studio 2010 designer error: Value cannot be null. Parameter name: objectType

It’s a fact that the Visual Studio 2010 Designer has some problems when dealing with inherited windows forms with a very very deep inheritance hierarchy (inheritance level > 2).

Working on one of my legacy project I converted from VS2008 to VS2010, I had to edit some forms and when I tried to open them in the designer I got the following error:

Value cannot be null. Parameter name: objectType
at System.ComponentModel.TypeDescriptor.TypeDescriptionNode.GetRuntimeType(Type objectType)
at System.ComponentModel.TypeDescriptionProvider.GetRuntimeType(Type reflectionType)
at Microsoft.VisualStudio.Design.MultiTargetingContextProvider.GetRuntimeType(Type objectType)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.HandlesClauseManager.GetFieldType(String fieldName, Type documentBaseType)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.HandlesClauseManager.GetReferencedComponentType(String componentName, CodeTypeDeclaration codeTypeDecl, ITypeResolutionService loader, IDictionary& cache)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.HandlesClauseManager.ParseHandlesClauses(CodeTypeDeclaration codeTypeDecl, Boolean updateCache)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomParser.OnMethodPopulateStatements(Object sender, EventArgs e)
at System.CodeDom.CodeMemberMethod.get_Statements()
at System.ComponentModel.Design.Serialization.TypeCodeDomSerializer.Deserialize(IDesignerSerializationManager manager, CodeTypeDeclaration declaration)
at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager manager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager serializationManager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.DeferredLoadHandler.Microsoft.VisualStudio.TextManager.Interop.IVsTextBufferDataEvents.OnLoadCompleted(Int32 fReload)

My first reaction was: Panic! sometimes the problem was there and sometimes (very few times to be honest) I could open the forms and edit them correctly.

The designer offer us the choice to ignore the error and go on editing...using that I had two possible results:

  1. The form opens up correctly in the designer without altering the code.
  2. A complete environment crash.

Having these crashes is not acceptable and time loosing, I had to find the cause of this problem. So I gave an in-depth look at what Visual Studio is telling me with this error: walking the stack trace you can find that the HandlesClauseManager class is actually the source of all problems. The name of the class and the fact that the project was written in Visual Basic rang a bell, so I started to comment out all the ‘handles eventname’ clauses on every WithEvents variable on the target form, save and reopen the form in the designer designer and everything seemed to work properly.

Once you find the cause of the problem, the next step is to reproduce the issue in a new empty test project; so far I’ve been able to reproduce this problem in two different ways:

- Adding a control to the form, attaching some handlers with the designer and then remove the control. if some of the function event handlers remain on the code with the ‘handles eventname’ there you have your error, because the Designer is trying to attach the events to a non existing object. A build of the project will however spot the problem.

- Using inherited forms: I declared a protected WithEvents variable on the base form:

Public Class Form1
	Protected WithEvents bmb As CurrencyManager

NHibernate Mapping Explorer Preview 2

In the past week I had the chance to make some improvements and fixes to my NHibernate ConfORM Mapping Explorer utility (more info on my previous post: http://www.primordialcode.com/blog/post/nhibernate-conform-mapping-explorer), so here are some of the ‘hot spots’ of this release:

  • You can now safely use ANY version of NHibernate 3 and ConfORM when exploring your own mappings, the utility will default to the bundled ones only if it cannot find your specific copies of the DLLs in the directory under probing.
  • You can specify any Driver and Dialect that will be used to generate the database scripts (even your custom provided ones), if nothing is specified the default values are SqlDriver and MsSql2005Dialect.
  • The NHibernate logging interception code has been fixed to work even if you do not have the log4net.dll inside the probing directory.
  • A new way to discover the DomainMapper has been added: for those that use MEF and .Net Framework 4 you can now export the domain mapper using the following attribute: [Export("IDomainMapper")] instead of declaring the IDomainMapper interface. However you still need to implement the two properties that expose the mappings to the outside world (HbmMapping and HbmMappings, see my previous article).
  • Some minor fixes to the UI code in general.

I’m not a good designer so the UI isn’t changed much...but here’s how it looks like now:

ConfOrmToolBox2

Figure 1 - The mapping explorer in action showing the ConfORM generated mappings for Dexter Blog Engine.

If any of you have some ideas or some WPF theme that I can take and customize to improve the UI and the UX a bit...I’m open minded to any suggestion, so don’t hesitate to contact me directly Open-mouthed smile. Any help is always appreciated!

You can get the updated version here:

What’s for the next versions ?  I’d like to find time to work more on this utility and provide the need for only one function to export all the mappings, extend it to support other mapping engines (like Fluent NHibernate) and provide a better navigation experience between the mapped classes.

Related Content