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.

Sharing an Interface (What not to do)

Have you ever had a class library that uses an Interface?  How about two or more libraries that need to use the same Interface?  For instance, ClassLibrary1 and ClassLibrary2 need to implement ISomeInterface below:

Interface1

Instead of copying ISomeInterface.vb to both ClassLibrary projects or adding a project reference, you can add a link to ISomeInterface.vb and have access to ISomeInterface:

Interface2

Interface3

Now you’ll notice that ISomeInterface.vb is part of ClassLibrary1 as a linked file:

Interface3

Now we can implement ISomeInterface in ClassLibrary1:

Interface4

The benefit of adding the Interface file as a link is that you can maintain the Interface in one location.  You don’t have to worry about having to copy new versions if you decide to change your contract.