Monday, December 15, 2008

WPF Designer Woes - "could not create an instance of type..."

December 15, 2008 Posted by Jason Irwin , , , 1 comment

If you've delved into WPF since its inception a couple of years ago you will undoubtedly have run into...hmm, lets say...idiosyncrasies...with the WPF designer. Visual Studio 2008 certainly improved on the VS2005 plugin, but now and again bugs till pop up...

What is really frustrating is receiving an error message in the designer despite a project that successfully builds and runs...Today I received the following error message:

"could not create an instance of type UserSelect"

The designer refused to reload and the design time error pointed to the following lines of code in my MainWindow.xaml file. My 'usr' namespace was defined and correctly referenced but no amount of rebuilding fixed my problem.

  1:         <Canvas Name="UserCanvas" Height="38" VerticalAlignment="Top" HorizontalAlignment="Left" Width="150">
  2:             <pat:UserSelect x:Name="myUserSelect" Margin="0,0,0,0" Canvas.Left="50" Canvas.Top="10" HorizontalAlignment="Left" VerticalAlignment="Top" Width="450" />                    
  3:         </Canvas

After a little (manual) investigation I realized that the root of the issue was a remoting call which could not be evaluated at design time. The initialized event of the UserSelect class contained a call to a PopulateUsers method. This method contains a further call to a remoting object on a remote server used to connect to a database and retrieve a list of users visible to the users whose ID is passed to the method.

  1: _userId = Environment.UserName
  2: PopulateUsers(GetUserListByUserID(_userId))

As is usual the solution itself was 10% of the work (90% having been expended on the investigation). Using the GetIsInDesignMode function (link) a clause was added providing different logic for run and design modes. Running the logic through at run time resulted in the second execution path being taken,the remote object returning a list users and the dropdownlist being populated accordingly.

More importantly, execution of the code in the designer resulted in the first execution path being followed. Rather than calling the remote method, designer specific code was added, populating the dropdownlist with a single dummy record (John Smith).

  1:  Private Sub UserSelect_Initialized(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Initialized
  2:         If ComponentModel.DesignerProperties.GetIsInDesignMode(Application.Current.MainWindow) Then
  3:             ' Designer Logic
  4:             ' Manually add record to combobox
  5:             Me.cmbUsers.Items.Add(New User(123456, "John Smith"))
  6:         Else
  7:             ' Production logic
  8:             _userId = Environment.UserName          
  9:             PopulateUsers(GetUserListByUserID(_userId))
 10:         End If      
 11: End Sub

Following a rebuild of the UserSelect component and a reload of the MainWindow designer (I did not close this window before rebuilding, therefore a reload was necessary and prompted for) the issue was resolved and the error message no longer appeared.