Wednesday, June 9, 2010

VS2008 to VS2010 Upgrade Notes

UPDATE 6/23/2010:

The issue with one of our setup project builds has been successfully resolved with a workaround that I thought didn’t work at first.  It turns out our Microsoft contact couldn’t reproduce the issue.  It was the end of the day so I decided to shelve this issue until this morning.  I tried running the setup project from my XP machine with the workaround and it worked.  More importantly, I ran it on our build machine and it worked!  The thing that threw me off was that it failed on my Windows 7 development machine, which is where I initially tested the issue.  I suspect it might have to do with the fact that the interop assemblies were actually built on my old XP development environment and that something isn’t jiving now when I use the same assemblies to build on my Windows 7 machine.  In any case, copying the interop dlls to the same path as the vdproj file works like a charm.

 

 

Using the latest and greatest development environment is always fun.  However, upgrading from a previous version isn’t always easy.  When we converted our dev environment from VS2005 to VS2008, there were a number of headaches to get everything working properly.  So far, upgrading to VS2010 from VS2008 is proving no different.  Since we’re still on TFS2008, we used this workaround to build VS2010 solutions on our Build machines. 

So after our build machines had VS2010 installed and the above MSBuildPath workaround was applied, I ran my first build.  It was a ClickOnce build and it actually ran without any issues.  The application compiled and everything got copied over to our drop location…Cool!  So then I tried running our MSI build for the same project.  I was expecting it to build fine since the ClickOnce build is a little bit more complex, but the MSI build failed.  After thoroughly checking all settings in the Setup project, I couldn’t figure out why it was failing.  The only reason in the BuildLog.txt was EXEC : error : Unable to update the dependencies of the project.  Could the message be a bit more vague, please?

After searching the web, it seemed others were having the same problem.  The workarounds suggested on that page didn’t work for us.  So instead of waiting around, we decided to open up a support ticket, which our contact at Microsoft is currently looking into.  I had a feeling that Interop assemblies in our project might be causing the problem, but it wasn’t until today that my suspicion was gaining ground.  We have a few projects that have MSI builds, so I went ahead and converted and built those out.  What do you know?  The MSI builds that don’t have Interop assemblies build fine on our build machine.  We’re still waiting for a real solution to this problem, until then, we’re building the MSI package locally for that one project.

Another one of our builds has unit tests.  I ran this project’s build without the unit tests first and it completed.  I then ran the build with the unit tests and 99.9% of the unit tests failed, but not all of them, which was weird to me.  These unit tests passed completely when we were using VS2008, so maybe the MSTest reference needed to be updated or something.  I searched MSDN and found this post about the same exact issue we were having.  I tried the solutions suggested, but they didn’t work.  There were some other odd issues with the build with the unit tests, so I just decided to delete the workspace associated with that build.  After I did this, the unit tests passed and everything looked good.

I hope when we upgrade our TFS2008 to TFS2010, that there aren’t going to be more issues.  I have my fingers crossed…

Monday, April 5, 2010

Running an Interactive Application Through a Windows Service

Have a need to run an interactive application through a Windows Service?  I do and I did a LOT of searching on the Internet and the answer I found was that it can’t be done anymore ever since Windows Vista was released.

A lot of people on MSDN asked this question, but couldn’t seem to get it to work either.  I just assumed that it couldn’t be done since nobody else couldn’t get it to work either. 

Luckily, I asked this question myself on one of the MSDN forums and a MSFT moderator was able to point me to this blog: http://asprosys.blogspot.com/2009/03/allow-service-to-interact-with-desktop.html

Thankfully, Stephen Martin was able to get the problem solved and even has some sample code to show you that it does work as it should.  It’s in C#, but you can always translate it to VB if you need to.  I personally used a converter found here: http://dotnetspider.com/codeconvert/Default.aspx.  The converter isn’t perfect, but it only had a few things that needed to be fixed.

One issue I had though was with running a .cmd file (I imagine the same issue would happen for .com/.bat files also).  For some reason, running the CreateProcessAsUser would show the command window then disappear.  My .cmd file was a long file name with spaces so I thought maybe that had something to do with it.  I included double quotes around my command string like this:  cmd.exe /c “C:\This Is a Long Path\command.cmd”  The .cmd file would not run. 

Scratching my head, I put the above string in the Windows Run and tried to run it.  It wouldn’t run here either… I then tried putting the .cmd file in the root of my C:\ and tried running it like this: cmd.exe /c “C:\command.cmd”  This ran fine.  I figured that since both CreateProcessAsUser and Windows Run were having the same issue, it was a good thing. 

After much playing around with the string and a lot of frustration, I tried the following: cmd.exe /c “”C:\This Is a Long Path\command.cmd”  This worked… I’m not too sure why the double quotes are needed twice before the long file name though…  This also works with the .cmd file that was in the root of my C:\ like this: cmd.exe /c “”C:\command.cmd”

Thursday, March 11, 2010

WinForms/WPF Interop ElementHost Not Drawing The WPF Control!

<Edit>

It turns out it wasn’t externalizing the WPF control that solved the issue, but rather changing my build configuration to Release instead of Debug.  When I added the externalized assembly, I set the configuration to Release.  I’m not sure exactly why a debug build would cause this behavior…

</Edit>

<Edit 2>

It seems to work properly on Windows XP regardless of the build configuration.  Might be a Windows 7 thing…

</Edit 2>

I’ve been doing a lot of WPF work lately and a lot of it has been with WinForms interoperating with WPF.  Today I noticed some odd behavior when I tried to add a WPF control to a WinForms ElementHost object…

Usually I put the WPF control in a separate assembly, but today I thought I didn’t need to since it was just a very simple control.  Immediately I saw that the WPF control wouldn’t draw itself properly for some reason.  It would only draw itself sometimes, but if i clicked on the WPF control and somehow hit a Button or ComboBox, the control would show up.

I then decided to try and put the simple control in its own assembly and that solved the problem… It looks like there’s some issues with including a WPF control in a WinForms project directly, in my case anyway.  I’m using Visual Studio 2008 on Win7 x86 and if anybody else has this type of issue, try doing what I did to resolve the issue.

Wednesday, December 9, 2009

Visual Studio IDE Tab Spacing

Don’t you hate it when you get some source code and the tab spacing is different than yours?  I know I do.  You could go line by line and press backspace, which is not the smartest way to do it (I was guilty of this).

Here’s the much simpler way to get the tabs aligned:

tabspacing

Wednesday, November 18, 2009

TFS folders and the evil “&”

So I tried to make a folder within TFS called “R&D and it let me.  No surprises…yet.  After moving a project into this folder, I ran the project to make sure all paths/references were still intact.  The project ran fine so things seemed okay. 

It wasn’t until I tried opening a form up in Designer view that I got a weird error:

DesignerError

How is it that the project can build and run fine, but I’m seeing this?  XML?  I don’t have anything related to XML in the form code, so what gives?  After doing some searching on the internet, it seems that the “&” character anywhere in the path causes this issue.  Since my project was in the “R&D” folder, I was having this issue.  I renamed the folder and the problem went away…

Thursday, October 29, 2009

WPF Data Binding – ComboBox Items List

As I learn WPF I’m running into quite a few roadblocks, but I’m enjoying the fact that it’s a challenge and something new.  One of the things I’m trying to get used to is Data Binding to the WPF UI.  I’m also trying to learn WPF the MVVM way.  There are a lot of examples on how to do this on the web so I’ll just get to what got me stuck for a bit on ComboBox items binding.  Here’s some of my UI XAML and my code behind:

<DockPanel Margin="0" Height="42" Name="TopDockPanel" Width="auto" DockPanel.Dock="Top" LastChildFill="true">
<Grid Height="auto" Name="Grid1" Width="266" DockPanel.Dock="Left">
<Label Margin="7,7,0,9" HorizontalAlignment="Left" Width="71">Combo1:</Label>
<ComboBox ItemsSource="{Binding ComboList1}" Margin="84,9,22,13" SelectionChanged="Combo1_SelectionChanged" />
</Grid>
<Grid Height="auto" Name="Grid2" Width="281">

<Label HorizontalAlignment="Left" Margin="6,7,0,9" Width="89">Combo2:</Label>
<ComboBox ItemsSource="{Binding ComboList2}" Margin="101,9,20,13" IsEditable="False" />
</Grid>
<Grid Height="auto" Name="Grid3" Width="auto" />
</DockPanel>

Class SomeClass
Private _SomeClassVM As SomeClassViewModel = Nothing

Sub New()

' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
_SomeClassVM = New SomeClassViewModel
Me.DataContext = _SomeClassVM
End Sub

Private Sub Combo1_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs)
_SomeClassVM.Combo1Changed(sender)

End Sub
End Class


Nothing complicated, a simple MVVMish implementation (ish because there’s event handler code in the code behind file, I’ll be refactoring this as I go on).  My View Model implements the INotifyPropertyChanged Interface so that the UI can be notified of any property changes and update any data bindings as needed.  My View Model also exposes a couple of Public Properties: ComboList1 and ComboList2 which are List (Of String) objects:

Public Class SomeClassViewModel
Implements INotifyPropertyChanged

Private _ComboList1 As List(Of String)
Private _ComboList2 As List(Of String)

Public ReadOnly Property ComboList1() As List(Of String)
Get
Return _ComboList1
End Get
End Property

Public ReadOnly Property ComboList2() As List(Of String)
Get
Return _ComboList2
End Get
End Property

Sub New()
_ComboList1 = New List(Of String)

For Each item As String In ItemsList 'this is just a list of strings from anywhere
_ComboList1.Add(item)
Next

OnPropertyChanged("SQLServerList")

_ComboList2 = New List(Of String)

End Sub

Public Sub Combo1Changed(ByVal sender As System.Object)
_ComboList2.Clear()

For Each item As String In SomeOtherList 'this is just list of string from another place
_ComboList2.Add(sqlDatabase)
Next

OnPropertyChanged("ComboList2")
End Sub

Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

Private Sub OnPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class


Now, I thought that clearing and adding items to my ComboList2 object would suffice in propagating change notifications up to the UI…WRONG.  It seems there’s more to it than just clearing/adding to the list and raising the PropertyChanged event.  This implementation only notified the UI that ComboList2 changed once at the first time I changed ComboBox1’s selected item instead of each time.  What gives?

After some fiddling I found that I couldn’t use the current _ComboList2 object reference.  I had to actually set the _ComboList2 object to a new List for the UI to update:

Public Sub Combo1Changed(ByVal sender As System.Object)
Dim NewList As New List(Of String)

For Each item As String In SomeOtherList 'this is just list of string from another place
NewList.Add(item)
Next

_ComboList2 = NewList
OnPropertyChanged("ComboList2")
End Sub

There’s a more elegant way to solve the issue I had, which is to use an ObservableCollection instead of List (Of String) objects:

Public Class SomeClassModel

Private _ComboList1 As ObservableCollection(Of String) = Nothing
Private _ComboList2 As ObservableCollection(Of String) = Nothing

Public ReadOnly Property ComboList1() As ObservableCollection(Of String)
Get
Return _ComboList1
End Get
End Property

Public ReadOnly Property ComboList2() As ObservableCollection(Of String)
Get
Return _ComboList2
End Get
End Property

Sub New()
_ComboList1 = New ObservableCollection(Of String)

For Each item As String In ItemsList 'this is just a list of strings from anywhere
_ComboList1.Add(item)
Next

_ComboList2 = New ObservableCollection(Of String)

End Sub

Public Sub Combo1Changed(ByVal sender As System.Object)
_ComboList2.Clear

For Each item As String In SomeOtherList 'this is just list of string from another place
_ComboList2.Add(item)
Next

End Sub
End Class

You’ll notice a couple of things.  The first being that the View Model no longer needs INotifyPropertyChanged.  This is because ObservableCollection implements INotifyPropertyChanged (and INotifyCollectionChanged).  You’ll also notice that I was able to just clear/add to _ComboList2 without having to raise any events.  The UI updated as expected and I suspect it’s because when clearing or adding items to the ObservableCollection, properties such as count raise the PropertyChanged event properly.

Tuesday, October 13, 2009

Error in last post. Think of it as a what not to do :)

It turns out that pointing to a file with an Interface inside of it doesn’t work as intended (oops! :/).  Although you can implement the Interface, problems arise when you try to cast it since they’re interfaces in different namespaces…  It looks like you will have to point all libraries that need the interface to a single project that has the Interface you need.