Author Archives: admin

XAML editor crashes Visual Studio 2008 SP1

0
Filed under Uncategorized

A week or so ago, I decided to try my hand at a little XAML, so I loaded up VS2008, started up a simple project and created a few forms (or whatever they’re called in WPF speak).

Anyway, I hadn’t gotten but maybe 10 minutes in when VS crashed. Hard crash. No error message, or dialog of any sort, just closed out.

I reloaded the project and tried again. Immediate crash as soon as I loaded up any XAML file.

I let it sit over Thanksgiving (I believe it’s always good to give a system a chance to think about what it’s doing before you really lay into it<g>) and tried again today.

No joy.

So I started researching the issue and came across a pretty active thread about just this problem.

Long story short, uninstall Power Commands for Visual Studio 2008 if you’ve got it installed and have VS2008 SP1. It doesn’t look like PowerCommands has changed since April and there definitely seems to be issues with it and SP1.

Command Line Email

0
Filed under EMail, Utilities

Every once in a while, I’ve run into the need to send an email via the command line. Often, this is during make scripts, or other long processing batch jobs. I’ve almost always ended up succumbing to “net send” and being done with it, but that’s not an option anymore with Vista. The good ol’ (and much maligned) Messenger service is no more under Vista and Server 2008.

So, I need to send an email via command line.

There’s piles of little email apps like this floating around, but most don’t support TLS, secure sockets or authenticated smtp access, which, for better or worse, is what GMail requires now.

After a good deal of searching, I ended up coming across the very nice (and free), MailSend utility by Muhammad A Muquit.

Sending email from the command line is a simple (albeit a tad long winded) command, all on one line of course:

mailsend -from you@gmail.com -to someone@domain.com +cc +bc -d gmail.com 
    -smtp smtp.gmail.com -v -starttls -auth-plain -user you@gmail.com -pass "yourpassword" 
    -sub "Test Subject" -M "This is the body of a test message"

Quite handy.

Shared Class Members or Modules?

0
Filed under .NET, Rants, VB Feng Shui

I ran into a chunk of code today that threw me.

The code was contained within a particular class definition.

Every member (properties and methods) were marked Shared.

Public Shared Sub MyMethod()
blah....
End Sub

The net effect was a class that, even if you could instantiate it, wouldn’t have any purpose as in instance. Its sole use was to provide essentially a dumping ground for a bunch of general purpose library routines.

At first, I just wrote this off as odd and continued on.

But, on further reflection, this just doesn’t seem right. As Scott Hanselman might say, it’s got a rather nasty Code Smell.

So, I did what any reasonable person would do; I googled it.

Apparently, there are more than a few people out there contemplating the same thing. What’s scary though, is that usually, the arguments end up along these lines:

  1. Modules in VB.Net are a throwback, a hack, and a nod to compatibility and should be avoided.
  2. Modules can’t be accessed from other .NET languages.
  3. Other .Net Languages don’t have modules, so you’re better off using shared members on a class definition.
  4. Modules aren’t OOP. Classes are. Use classes.

It’s already been proven that, internally, VB.Net modules compile to exactly the same code as a Class with shared methods. Further, the modules have been documented as a first class feature of VB.Net, the language, not some soon-to-be-deprecated nod to VB6 compatibility. And Modules CAN be accessed from other languages. So I’m not going to bother with any of those bits again.

Personally, I think in comes down to two simple concepts, syntactics and semantics.

The Syntactics

Syntactically, defining members in a Module allows them to be accessed without  qualifying the member with the module name. So, given this Module definition:

Public Module MyModule
   Public Shared Sub MyMethod()
      blah....
   End Sub
End Module

I can access the method MyMethod by simply invoking the name MyMethod(); I don’t have to qualify it, as in MyModule.MyMethod().

This is a minor issue, except that it effectively allows you to extend the VB language. You can add your own RIGHT() function or LEFT() function, etc. This can be a fantastic aid to code readability when used appropriately.

The Semantics

However, I believe the even bigger argument is semantics. A class, is, by its very definition, the definition of an object that can be instantiated. Even singleton classes can be instantiated at least once. But a class of shared methods is a class that has no reason to be instantiated. And that really isn’t a class, it’s just a set of loosely related, if even related at all, functions. And that is the definition of a Module!

Do you regularly create an integer type variable when what you really need is a DATE? Then why collect a bunch of shared functions in a class when a module is specifically intended for such purposes?

Discoverability

The only rational I can come up with is discoverability. Forcing developers to prefix shared methods with the class name provides a means (through Intellisense) of discovering the capabilities of that class. But, you can optionally prefix module members in exactly the same way, so again, shouldn’t we be using the features of the language as they’re intended?

Why Shared Members at all?

Given this, what benefit is there of using shared members at all?  I’ve seen a few examples for defining singleton objects where you retrieve the single instance via a shared member of the class. That certainly makes logical sense, but from a coding perspective, it seems ugly to me. Why ask the class for the single available instance of itself? Shouldn’t you ask something else for that instance? It also makes for some odd-reading code:

Dim TheOneInstance = MySingletonClass.GetTheOneInstance

And other than singletons, what other purpose is there for shared members?

(UPDATE 10/29/08: After further experiments and reading, it turns out that, as far as I can tell, the ONLY way to truly get a singleton object is to use a shared method within the object itself. Nasty, but that appears to be the only way to do it).

I know the .NET framework uses them extensively, but are they used effectively?

For example, take the String class. It exposes quite a few shared members, such as Compare and Copy. But in practice, using those shared members doesn’t quite make sense. If I’m comparing two strings, the object-oriented thinker in me naturally gravitates to:

If OneString.Compare(OtherString) Then

Not

If String.Compare(OneString, OtherString) then

The bottom line is, if I’m comparing two strings or copying a string, I’ll always be working with an instance of a string, so why shouldn’t those methods be instance methods and not shared methods?

I suppose String.Format() is a passable example, but even that would seem to make more sense as:

dim x = "Insert a parameter here {0}".Format(Arg0)

Do you have a good use for shared methods that you’d like to, uh, share?

Let me know!

Simplified VB.Net Configuration

0
Filed under .NET, Code Garage

image I really liked the idea of a built-in configuration management framework with .NET. That is, until I actually tried to use it.

I wrote about the configuration functions in .NET here. My specific words were:

If your sideline utility needs to save a few settings, use the .NET configuration…

Ugh, I’m sorry I said that…

What’s Wrong

The .NET configuration namespace is powerful, no doubt about that. But, that comes at a huge cost. The thing is enormous. And the available documentation and examples just aren’t that good.

Honestly, though. The docs don’t bother me that much. What bothers me is that even though the existing framework will probably do everything I want it to, discovering how is just too dang hard and non-intuitive.

For instance:

  • Why the hell should I have to create a new ExeConfigurationFileMap object just to change the path of where the system reads its config file? Sorry, but that’s about as intuitive as a car you accelerate by yodeling.
  • What on earth were they smoking when they came up with those ludicrous guid/hash/hex based folder names where your user level config files are stored by default? Facilitate upgrades? Yeah, maybe, but pretty much nothing else. That’s one that I guarantee will go down with the registry and DCOM as a bad idea.
  • Registering ConfigurationSection handlers? Huh? Why should I have to write the full class names of classes internal to my application into my configuration file so that .NET can read them?

What Would Be Nice

What I was looking for was a simple way to create a class like so:

Public Sub MySettingClass
   Public Setting1 as string = ""
   Public Setting2 as Integer = 0
End Class

No need to explicitly use properties unless you need them. No need for attributes. Heck, you shouldn’t even have to declare the class <Serializable>, though that’s a minor point.

In lieu of coexisting within the My.Settings space, it should be able to persist itself to a config file, and then de-persist itself back when asked, like this:

Settings = New MySettingsClass
Settings.Load
...
Settings.Save

Accessing your settings should be completely early bound, with all that sweet Intellisense goodness baked right in:

x = Settings.Setting1
y = Setting.Setting2

Further, I should be able to easily persist sub-objects or collections made accessible off this root settings object. For example, to save a form’s current position and size, and then restore it, should take code similar to:

Settings.FormPositions.Save(MyForm)
Settings.FormPositions.Restore(MyForm)
Debug.print "Form position is " & Settings.FormPositions(0).Position

And a few additional requirements.

  • First, having no initial configuration file shouldn’t be a problem. The entire collection of settings should easily default to some “built in” default values when no config file exists.
  • Second, I should be able to go from 0-60 in no time. In other words, I should be able to take the .VB file for a settings base class, drop it in my application, add a settings class with the properties I need to persist, as well as a .LOAD and a .SAVE at the appropriate points in my project, and be off. No “presetting” my config file, no tweaks to anything, no registering this or that, mucking with the GAC, etc, etc.

Research

The available Microsoft documentation on the configuration system was so confusing, I believe I knew less about it after I finished reading the docs than I did when I started.

I did turn up a very good article on CodeProject by Jon Rista called Cracking the Mysteries of .NET 2.0 Configuration. Definitely worth a read if you’re diving into this stuff.

While Jon gives several samples of code, nothing really illustrated exactly what I was looking for. However, there was more than enough info in the article to kick-start things for me.

Long story short, it turns out that the Configuration system in .NET is, in typical MS fashion, more than capable but ultra-overkill for many small-app type scenarios.

My Solution

While this is definitely still a work in progress, it’s proved quite useful so far, so I thought others might find it handy too.

The system consists of one file, SettingsBase.vb. It defines two classes, SettingsBase and SettingsBaseDictionary.

SettingsBaseDictionary is just a simple extension to the normal generic Dictionary class that allows it to be serialized. This is something I found on the web and is so handy with respect to settings that I just include it directly in the file.

SettingsBase is a MustInherit class, meaning it’s abstract. To use it, you must create your own settings class (call it whatever you like) that inherits from SettingsBase:

Public Class Settings
   Inherits SettingsBase

   Public Name As String = ""
   Public Phone As String = ""
End Class

When you want to load your settings, just instantiate your Settings object and invoke Settings.Load. To change settings, set the object’s properties as you normally would.

To save your settings, invoke Settings.Save.

Finally, you’ll need to add a reference to System.Configuration. Directly accessing the ConfigurationManager and EXEConfigurationFileMap objects requires it.

The sample project I’ve zipped up shows several examples of this, from ridiculously simple to moderately sophisticated. I even threw in a really simple example of DataBinding to a setting property (in this case, a Dictionary of contacts).

The Code

If you don’t want to download the sample, I’ve included the source to the SettingBase.VB file here. Note that this also includes the source to the SettingBaseDictionary, but if you don’t want it, you can simply delete it.

Imports System.Configuration
Imports System.IO
Imports System.Text
Imports System.Xml
Imports System.Xml.Serialization


''' <summary>
''' Base Class that will allow you to easily persist
''' a "settings" object via the .net configuration management framework
''' 
''' By Darin Higgins
''' Sept 2008
''' You are free to use this class in your own projects.
''' But please, keep the attributions as to the source.
''' </summary>
''' <remarks>
''' Be sure to add a reference to System.Configuration
''' </remarks>
''' <editHistory></editHistory>
Public MustInherit Class SettingsBase
#Region " Constants"
   '---- just some names of constants used in the class
   Private Const DEFAULTSETTINGFILENAME = "Settings.config"
   Private Const ROOTSECTION = "general"
   Private Const ROOTITEM = "settings"
#End Region


#Region " Properties"
   Private rFilename As String = DEFAULTSETTINGFILENAME
   ''' <summary>
   ''' The Settings filename (name only, no path)
   ''' </summary>
   ''' <value></value>
   ''' <remarks></remarks>
   Public Property FileName() As String
      Get
         Return rFilename
      End Get
      Set(ByVal value As String)
         rFilename = value
      End Set
   End Property


   Private rCompanyName As String = My.Application.Info.CompanyName
   ''' <summary>
   ''' The CompanyName used when creating a path to the settings store
   ''' </summary>
   ''' <value></value>
   ''' <remarks></remarks>
   Public Property CompanyName() As String
      Get
         Return rCompanyName
      End Get
      Set(ByVal value As String)
         rCompanyName = value
      End Set
   End Property


   Private rAppName As String = My.Application.Info.ProductName
   ''' <summary>
   ''' The AppName used when creating a path to the settings store
   ''' </summary>
   ''' <value></value>
   ''' <remarks></remarks>
   Public Property AppName() As String
      Get
         Return rAppName
      End Get
      Set(ByVal value As String)
         rAppName = value
      End Set
   End Property


   ''' <summary>
   ''' Retrieves the full path and filename to the settings store
   ''' Normally \Docs and Settings\All Users\Application Data\CompanyName\AppName\Settings.config
   ''' </summary>
   ''' <value></value>
   ''' <remarks></remarks>
   Private ReadOnly Property pAppConfigFilename() As String
      Get
         '---- Don't use My.Computer.FileSystem.SpecialDirectories 
         '     because the commonappdata folder returned will always have
         '     the version in it and it will automatically be created
         '     but I don't want that here
         Dim path = System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)

         '---- as is pretty standard practice, our app settings
         '     go in a CompanyName\Appname folder in the CommonAppData folder
         If Me.CompanyName.Length > 0 Then
            path = System.IO.Path.Combine(path, Me.CompanyName)
            If Not My.Computer.FileSystem.DirectoryExists(path) Then
               My.Computer.FileSystem.CreateDirectory(path)
            End If
         End If
         If Me.AppName.Length > 0 Then
            path = System.IO.Path.Combine(path, Me.AppName)
            If Not My.Computer.FileSystem.DirectoryExists(path) Then
               My.Computer.FileSystem.CreateDirectory(path)
            End If
         End If

         Dim Filename = System.IO.Path.Combine(path, Me.FileName)
         Return Filename
      End Get
   End Property


   ''' <summary>
   ''' Creates an ExeConfigurationFileMap object to properly
   ''' locate the config files we'll use
   ''' </summary>
   ''' <value></value>
   ''' <remarks></remarks>
   Private ReadOnly Property pAppConfigMap() As ExeConfigurationFileMap
      Get
         Dim filemap = New ExeConfigurationFileMap
         filemap.ExeConfigFilename = Me.pAppConfigFilename
         Return filemap
      End Get
   End Property


   ''' <summary>
   ''' Creates a Configuration object mapped to 
   ''' the proper settings files
   ''' Sets up several internal setting elements and sections
   ''' so we can persist the host object
   ''' </summary>
   ''' <value></value>
   ''' <remarks></remarks>
   Private ReadOnly Property pConfig() As Configuration
      Get
         Static cfg As Configuration

         '---- cache the config object so we can reuse it
         If cfg Is Nothing Then
            cfg = ConfigurationManager.OpenMappedExeConfiguration(Me.pAppConfigMap, ConfigurationUserLevel.None)
         End If
         If Not cfg.HasFile Then
            '---- force a file to be created
            '     This settings is just general purpose placeholder
            '     not really intended to be used
            cfg.AppSettings.Settings.Add("version", My.Application.Info.Version.ToString)
            cfg.Save()
         End If

         Dim bDirty As Boolean = False
         If cfg.HasFile Then
            '---- no need for groups in this case
            '     but this sample code illustrates how you'd create a ConfigGroup if necessary
            'If cfg.SectionGroups(ROOTSECTION) Is Nothing Then
            '   cfg.SectionGroups.Add(ROOTSECTION, New ConfigurationSectionGroup)
            '   bDirty = True
            'End If
            'If cfg.SectionGroups(ROOTSECTION).Sections("options") Is Nothing Then
            '   cfg.SectionGroups(ROOTSECTION).Sections.Add("options", New ClientSettingsSection)
            '   bDirty = True
            'End If
            Dim sect As ClientSettingsSection = cfg.Sections(ROOTSECTION)
            If cfg.Sections(ROOTSECTION) Is Nothing Then
               sect = cfg.Sections(ROOTSECTION)
               cfg.Sections.Add(ROOTSECTION, sect)
               bDirty = True
            End If
            Dim element = sect.Settings.Get(ROOTITEM)
            If element Is Nothing Then
               element = New SettingElement(ROOTITEM, SettingsSerializeAs.Xml)
               sect.Settings.Add(element)
               bDirty = True
            End If
            If element.Value.ValueXml Is Nothing Then
               '---- make sure element contains something
               element.Value.ValueXml = New Xml.XmlDocument().CreateElement("value")
               bDirty = True
            End If

            If bDirty Then cfg.Save()
         End If
         Return cfg
      End Get
   End Property


   ''' <summary>
   ''' If you would like to use the built in ConfigurationStringsSection
   ''' just add a readonly property that exposes this property
   ''' Doing it this way, you can expose this property anywhere you want
   ''' in your Setting object heirarchy.
   ''' 
   ''' </summary>
   ''' <value></value>
   ''' <remarks></remarks>
   Protected ReadOnly Property ConnectionStrings() As ConnectionStringsSection
      Get
         Return pConfig.ConnectionStrings
      End Get
   End Property


   ''' <summary>
   ''' Since this is essentially a key/value pair collection
   ''' there's not much benefit to exposing it, but I've included it
   ''' for completeness.
   ''' 
   ''' These kinds of sections are particularly useful when config merging
   ''' is used heavily, but that's not the point of this base class
   ''' </summary>
   ''' <value></value>
   ''' <remarks></remarks>
   Protected ReadOnly Property AppSettings() As AppSettingsSection
      Get
         Return pConfig.AppSettings
      End Get
   End Property
#End Region


#Region " Methods"
   ''' <summary>
   ''' Persist the host object to the configuration file
   ''' </summary>
   ''' <remarks></remarks>
   Public Sub Save()
      With Me.pConfig
         '---- not using configgroups right now, but keeping this for reference
         'Dim sect = TryCast(.SectionGroups(ROOTSECTION).Sections("options"), ClientSettingsSection)
         'If sect.Settings.Get(ROOTITEM) Is Nothing Then
         '   element = New SettingElement(ROOTITEM, SettingsSerializeAs.Xml)
         '   element.Value.ValueXml = New Xml.XmlDocument().CreateElement("value")
         '   sect.Settings.Add(element)
         'Else
         '   element = sect.Settings.Get(ROOTITEM)
         'End If
         Dim sect = TryCast(.Sections(ROOTSECTION), ClientSettingsSection)
         Dim element = sect.Settings.Get(ROOTITEM)

         '---- Create a serializer to serial our superclass
         Dim s = New XmlSerializer(Me.GetType)
         Using ms = New MemoryStream
            '---- serialize it
            s.Serialize(ms, Me)
            '---- rewind and convert the stream to a string
            ms.Seek(0, SeekOrigin.Begin)
            Dim myutf As UTF8Encoding = New UTF8Encoding()
            '---- load it up into an xml doc
            Dim xml = New XmlDocument
            xml.LoadXml(myutf.GetString(ms.GetBuffer()))
            '---- and push into the settings "value"
            '     stripping out the XML header stuff
            element.Value.ValueXml.InnerXml = xml.DocumentElement.OuterXml
         End Using

         '---- Force the save, because we won't otherwise trigger
         '     the dirty condition
         sect.SectionInformation.ForceSave = True
         .Save()
      End With
   End Sub


   ''' <summary>
   ''' Reload the superclass's properties from configuration
   ''' </summary>
   ''' <remarks></remarks>
   Public Sub Load()
      With Me.pConfig
         Dim sect = TryCast(.Sections(ROOTSECTION), ClientSettingsSection)
         Dim element As SettingElement = sect.Settings.Get(ROOTITEM)

         '---- if we've got the required element...
         If Len(element.Value.ValueXml.InnerXml) Then
            '---- deserialize the xml
            Dim s = New XmlSerializer(Me.GetType)
            Dim myutf As UTF8Encoding = New UTF8Encoding()
            Using ms = New MemoryStream(myutf.GetBytes(element.Value.ValueXml.InnerXml))
               '---- just get a generic object
               '     and we'll use reflection to 
               '     update the properties and fields of THIS object
               Dim o As Object = Nothing
               Try
                  o = s.Deserialize(ms)
               Catch ex As Exception
                  Debug.Print("Problem")
               End Try

               If o IsNot Nothing Then
                  '---- now need to refresh our values from 
                  '     this deserialized object
                  For Each Field In Me.GetType().GetFields
                     If Field.IsPublic Then
                        '---- BaseSettings has no fields, so 
                        '     we don't need to check if the field
                        '     is defined the the base object
                        Try
                           Field.SetValue(Me, Field.GetValue(o))
                        Catch
                        End Try
                     End If
                  Next

                  '---- now copy over any properties
                  For Each Prop In Me.GetType().GetProperties
                     '---- first, check that the property
                     '     isn't one of the BaseSettings properties
                     '     we don't want to depersist those!
                     Dim n = Prop.Name
                     Dim query As IEnumerable(Of System.Reflection.PropertyInfo) = Me.GetType.BaseType.GetProperties.Where(Function(Prop2) Prop2.Name = n)
                     If query.Count = 0 Then
                        '---- this is not a property on BaseSettings
                        If Prop.CanWrite Then
                           If Prop.GetIndexParameters.Count = 0 Then
                              '---- handle non-indexed properties
                              Try
                                 Prop.SetValue(Me, Prop.GetValue(o, Nothing), Nothing)
                              Catch
                              End Try
                           Else
                              '---- not handling indexed properties yet
                           End If
                        End If
                     End If
                  Next
               End If
            End Using
         End If
      End With
   End Sub
#End Region


#Region " SettingsBaseDictionary"
   ''' <summary>
   ''' A simple serializable dictionary class I pulled off the web.
   ''' 
   ''' Originally at http://www.playswithcomputers.com/SGDCollection.aspx
   ''' 
   ''' I've included it here because very often settings collections
   ''' need to be keyed for access, and lists/bindinglists (which will
   ''' persist just fine) don't make that especially straightforward
   ''' like a dictionary.
   ''' 
   ''' However, you can also use a generic List or BindingList for properties
   ''' and they seem to be persisted just fine, they just aren't quite 
   ''' as easy to perform keyed lookups on.
   ''' 
   ''' </summary>
   ''' <remarks></remarks>
   ''' <editHistory>
   ''' </editHistory>
   <XmlRoot("dictionary", IsNullable:=True)> _
   Public Class SettingsBaseDictionary(Of TKey, TValue)
      Inherits Generic.Dictionary(Of TKey, TValue)
      Implements IXmlSerializable

      Private Const ITEMNAME = "item"
      Private Const KEYNAME = "key"
      Private Const VALUENAME = "value"

      Public Function GetSchema() As System.Xml.Schema.XmlSchema Implements IXmlSerializable.GetSchema
         Return Nothing
      End Function


      Public Sub New()
         MyBase.New()
      End Sub
      Public Sub New(ByVal capacity As Integer)
         MyBase.New(capacity)
      End Sub
      Public Sub New(ByVal comparer As System.Collections.Generic.IEqualityComparer(Of TKey))
         MyBase.New(comparer)
      End Sub
      Public Sub New(ByVal capacity As Integer, ByVal comparer As System.Collections.Generic.IEqualityComparer(Of TKey))
         MyBase.New(capacity, comparer)
      End Sub
      Public Sub New(ByVal dictionary As Generic.IDictionary(Of TKey, TValue))
         MyBase.New(dictionary)
      End Sub
      Public Sub New(ByVal dictionary As Generic.IDictionary(Of TKey, TValue), ByVal comparer As System.Collections.Generic.IEqualityComparer(Of TKey))
         MyBase.New(dictionary, comparer)
      End Sub
      Public Sub New(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext)
         MyBase.New(info, context)
      End Sub


      ''' <summary>
      ''' Read a Serialized XML Dictionary of generic objects
      ''' </summary>
      ''' <param name="reader"></param>
      ''' <remarks></remarks>
      Public Sub ReadXml(ByVal reader As System.Xml.XmlReader) Implements IXmlSerializable.ReadXml
         Dim keySerializer As XmlSerializer = New XmlSerializer(GetType(TKey))
         Dim valueSerializer As XmlSerializer = New XmlSerializer(GetType(TValue))
         Dim wasEmpty As Boolean = reader.IsEmptyElement
         reader.Read()
         If wasEmpty Then Return

         Do While (reader.NodeType <> System.Xml.XmlNodeType.EndElement)
            reader.ReadStartElement(ITEMNAME)
            reader.ReadStartElement(KEYNAME)

            Dim key As TKey = DirectCast(keySerializer.Deserialize(reader), TKey)
            reader.ReadEndElement()

            reader.ReadStartElement(VALUENAME)
            Dim value As TValue = DirectCast(valueSerializer.Deserialize(reader), TValue)
            reader.ReadEndElement()

            Me.Add(key, value)

            '---- finish reading this element and move to the next
            reader.ReadEndElement()
            reader.MoveToContent()
         Loop
         reader.ReadEndElement()
      End Sub


      ''' <summary>
      ''' Write the XML Serialization of a dictionary of generic objects
      ''' </summary>
      ''' <param name="writer"></param>
      ''' <remarks></remarks>
      Public Sub WriteXml(ByVal writer As System.Xml.XmlWriter) Implements IXmlSerializable.WriteXml
         Dim keySerializer As XmlSerializer = New XmlSerializer(GetType(TKey))
         Dim valueSerializer As XmlSerializer = New XmlSerializer(GetType(TValue))

         For Each key As TKey In Me.Keys
            writer.WriteStartElement(ITEMNAME)

            writer.WriteStartElement(KEYNAME)
            keySerializer.Serialize(writer, key)
            writer.WriteEndElement()

            writer.WriteStartElement(VALUENAME)
            valueSerializer.Serialize(writer, DirectCast(Me(key), TValue))
            writer.WriteEndElement()
            writer.WriteEndElement()
         Next
      End Sub
   End Class
#End Region

End Class

Points of Interest

  • Your settings file will, by default, be written to the CommonApplicationData folder, and in there, in a folder named the same as the CompanyName in your assembly information screen, and in there, in a folder named the same as the Application Name in the assembly information screen.

image 

So, for the above app, under Windows XP, you’ll find the default setting file in

c:\Documents and Settings\All Users\Application Data\One Nifty Company\SettingsTest\Settings.config

and under Vista

c:\Program Data\One Nifty Company\SettingsTest\Settings.config

This is pretty standard practice for config files, but if you want to change it, you’ve got the source<g>.

  • You can change the setting filename, the Company Name and the Product Name used by simply changing the associated  properties of your setting object (these properties are all inherited from the SettingsBase object).
  • Although you can use fields in your base Settings object, you won’t be able to use any DataBinding support with them. This is a limitation of the .NET Databinding support, and not with the Settings class. Quite frankly, it sucks. Sometimes full blown properties make sense, but in this case, properties are just a lot more work for the same net effect.
    If you want to use Databinding with your settings class, you’re probably best off declaring all persistent elements of your settings class as properties to begin with, and just avoid using fields at all.
  • The SettingsBase object doesn’t even try to provide access to configuration “sections” or “section groups”. You can easily break settings down into groups or sections by using “sub objects” off your main settings object (the one that inherits from SettingsBase). I illustrate this is the sample app.
  • There’s no merging (at least not intentionally anyway). I’m still not completely sure of how that works, and I haven’t needed it yet. 
  • As I indicated earlier, much of this could be accomplished by creating a custom ConfigurationSection class, and registering it in your config file, but from what I can tell so far, that mean you have to manually add gunk to your config file. To me, that’s got a code smell akin to that guy in the next cube that burns patchouli all day. It doesn’t stink, per se, but it sure makes your eyes water if you’re around it long enough.

<configSections>
    <section name="sampleSection"
    type="System.Configuration.MySectionHandler" />
</configSections>

 

What’s Next

  • Really, this should be wrappable in a custom ConfigurationSection handler. My only gripes with that approach is that it doesn’t resolve the folder naming problem, and it requires the goofy registration of the section handler. I’m betting there’s ways around both those issues, though. I just haven’t found them yet.
  • In the same vein, I’d really love to figure a way to accommodate what I’m looking for, AND still use the My.Settings namespace as it’s currently automatically defined by Visual Studio. Again, I’m working on that, but this simple approach works for the short and sweet utility apps I’ve needed to turn out recently.

Check it out and let me know what you think!

Home Theater

0
Filed under Media

image I’m a big Home Theater fan. Ok, maybe not in the sense of being fond of having one, but I certainly do admire some of the installations and techniques that are being used out there. Installations like the one here just blow my mind.

Funny how just about anyone I’ve ever talked to, though, that actually has a setup like this (ok, maybe not quite this nice), ends up rarely using it.

While it’s a nice thought, and, for a hobbyist, could definitely chew up some free weekends, plus a pile of cash, dedicating an entire room to a home theater has always seemed like a bit of a waste to me.

Take this setup here. What else could you possibly do in this room? Play video games? Ok. Anything else? When the extended family comes in for the holidays, are they going to gather in there? Is the family going to gather in there to watch Dr Who before going to bed?

It just doesn’t seem like someplace that would foster a good family experience. Maybe I’m wrong. I also am of a school of thought that says there’s no need for more than one TV in a house. 3 PC’s per person, sure, but just the one TV. I know, I know. How quaint<g>.

But I do admit, for that one TV, I like it to be a good one. I picked up a 36″ Mitsubishi tube TV back in ’94, when such behemoths weren’t all too commonplace. Now, a 36″ TV is, um, quaint.

When our family watches TV, we want to do it on a big screen, so the only decent alternative I saw was a projector/screen combo. And since I didn’t want to dedicate an entire room to a home theater, the equipment needed to be unobtrusive and disappear if we weren’t using it, as only a projector/screen can.

imageIn the end, I went with a Draper motorized tab-tensioned screen (craigslist) and a Panasonic AE900U projector (ebay). I was really looking for an AX200U (the next up model number), but when a 900U came up at a really good price, I couldn’t walk away from the deal.

Besides, from reading the specs (www.ProjectorCentral.com is an excellent resource for those), the two units are virtually identical, with the 200 supporting 1080P being the major difference.

This projector has turned out to be utterly fantastic. Contrast is great and the picture is terrifically bright, even with all the lights on and the windows open (though, admittedly, the windows are shaded by trees outside).

And if I turn down the lights, even a bit, the picture really pops.

What’s better, the Panasonic units (both the 900 and 200) have one of the best picture positioning systems around. Not only can you move the image without moving the projector (so you can tweak things once the projector is mounted), the zoom lens allows for a very wide range of positioning the projector from the screen. It’s one of the few reasonably priced projectors that can do an 80″ image from over 17′ away.

Now then, my audio gear pales. Ah, next project…

What’s next with Reflector

0
Filed under .NET, Utilities

One of my favorite .NET tools is about to transition in an unknown way.

“After more than eight years of working on .NET Reflector, I have decided it is time to move on and explore some new opportunities.”

So begins the email I just received from Lutz Roeder, the man behind Reflector, an almost scarily powerful tool for .NET development.

Eight years? Wow. Just doesn’t seem that long. But I can completely understand the desire to move on.

Unfotunately, the following passage gives a little clue as to what might be next.

“Red Gate will continue to provide the free community version and is looking for your feedback and ideas for future versions.”

Ah… So there will be a community version and then something else. The thing is, Reflector seems to be one of those tools that’s incredibly useful, to an incredibly small audience. And almost useless to everyone else. A bit like the SysInternals tools I’ve mentioned before. So successfully “productizing” it might be a pretty good challenge.

The thing is, even for me, and even though Reflector has been quite useful, I’m not sure I’d have paid for it, to be brutally honest.

But I have to applaud Mr. Roeder for what he’s accomplished and congratulate him in moving forward.

Tooltips for Disabled Controls

3
Filed under .NET, Code Garage, VB Feng Shui

We recently got into a discussion where I work about the best way to explain to a user why a control is disabled.

One person argued that it made sense to leave the “disabled” controls enabled, and, when a user tried to click/use the control, pop up a messagebox explaining why it won’t work in this instance.

To me, that seemed to go against everything I’d ever learned about UI design and controls, namely, if a control is disabled, it ought to look disabled on screen and it shouldn’t do anything if you poke at it.

Still, I’d had plenty of experience myself with apps where controls were disabled and I had no idea why they were disabled, much less how to go about getting that functionality enabled. That can certainly make for a frustrating time.

Then someone suggested a tooltip or a status bar message. If you tried to click the disabled control, or hovered your mouse over it, you’d get a little, innocuous message somewhere telling you why that control was disabled.

Awesome idea!

Only one problem.

Tooltips don’t work for disabled controls. Actually, they do for menus, toolbars and likely a few others, but that’s another story.

And you don’t get MouseOver events on disabled controls.

Sigh.

Well, I couldn’t just walk away from this.

A quick google turned up a few bits:

  • There was this from Roy Auchterlounie, but it’s MFC.
  • But then there was this nugget from a post by Linda Lui, apparently with MS Support. It’s in C#, but it’s relatively easy to translate to VB.

The only thing was, Lui’s solution was not exactly what I’d call an encapsulated solution.  As Scott Hanselman would say, dropping snippets of code like this all over my forms just doesn’t have a wonderfully fragrant code smell.

I’d messed around with Control Extenders under ASP.NET some time ago, and this seemed like the perfect excuse to try it out on a good ol’ WinForms app.

A little refactoring later, and I’ve ended up with the “Disabled Tool Tip” Extender Control. It directly inherits from the out-of-the-box tooltip in VS2008. As a result, there’s not a lot of code here. Also, it should work with VS2005, but I’m not guaranteeing as much.

Add this class to your project, recompile, then drop one onto a form.

Zip! Boom! Pow! Every control on your form should now have a “ToolTip on DisabledToolTip” property. You simply set this new property to the tooltip you want to show when the control is disabled and you’re done.

image

(my test rig, she is much fine, no?<g>)

A few notes about this class.

One significant issue I ran into immediately, was how do you retrieve a reference to the containing form if you’re a component sited on that form. All the obvious stuff didn’t work. There’s gotta be a more straightforward way to do it, but I failed to find it, at least with respect to a Component type control (one of those that isn’t actually sited ON the form, but rather in that little area at the bottom of the designer).

I ended up caching an instance of some control during the SetToolTip method, since this method is called during the form initialization by any control on the form that had a tooltip set for it via the designer.

   Public Shadows Sub SetToolTip(ByVal control As Control, ByVal caption As String)
      MyBase.SetToolTip(control, caption)

      '---- if we don't have the parent form yet...
      If rParentForm Is Nothing Then
         '---- attempt to get it from the control
         rParentForm = control.FindForm
         '---- if that doesn't work
         If rParentForm Is Nothing Then
            '---- cache the control for use a little later
            rControl = control
         End If
      End If
   End Sub

But, you can’t use the FindForm method here, necessarily, because if the form is still being initialized, you’ll get back nothing.

So, I ended up implementing the ISupportInitialize interface, and, during the EndInit method, if I have a cached control reference, I use it at this point to retrieve the parent form via FindForm.

   Public Sub EndInit() Implements ISupportInitialize.EndInit
      '---- if we weren't able to retrieve the form from the control
      '     before, we should be able to now
      If rControl IsNot Nothing Then
         rParentForm = rControl.FindForm
      End If
   End Sub

Roundabout, yes, but it seems to work in a very stable way, and it means I don’t have to resort to MFC style subclassing and the like. I can just monitor events on the parent form via a simple WithEvents variable reference.

Anyway, the full code for the class is here. It’s short enough that I’m not going to bother with a ZIP file at this point.

And finally, as with any code you pick up off the net, I’m making no guarantees of any sort. If it works for you, great. If not. Well, I’ll certainly do my best to help if you let me know. It works for me, but it is necessarily full on, battle tested, bulletproof stuff? Uh. No.

Enjoy! If you see any improvements to be made, please share!

And please, if you post it elsewhere, give me (and Linda Lui) proper credit!

Imports System.ComponentModel

''' <summary>
''' Custom ToolTip Component that is based on a normal tooltip component but tracks tips 
''' for disabled controls
''' Note that the because this is a separate extender, all the controls on a form
''' can have an "Enabled" tip (as normal) AND a "disabled" tip.
''' 
''' By Darin Higgins 2008
''' Based on a code example by Linda Lui (MSFT)
'''
''' </summary>
''' <remarks></remarks>
''' <editHistory></editHistory>
Public Class DisabledToolTip
   Inherits ToolTip
   Implements ISupportInitialize

   '---- hold onto a reference to the host form
   '     to monitor the mousemove
   Private WithEvents rParentForm As System.Windows.Forms.Form

   Private _rbActive As Boolean = True
   ''' <summary>
   ''' Active for the Disabled ToolTip has a slightly different meaning
   ''' than "Active" for a regular tooltip
   ''' </summary>
   ''' <value></value>
   ''' <remarks></remarks>
   <DefaultValue(True)> _
   Public Shadows Property Active() As Boolean
      Get
         Return _rbActive
      End Get
      Set(ByVal value As Boolean)
         If _rbActive <> value Then
            _rbActive = value
         End If
      End Set
   End Property



   '---- hold on to a control temporarily while we wait for things to 
   '     settle
   Private rControl As Control

   ''' <summary>
   ''' Shadow the settooltip function so we can intercept and save a control
   ''' reference. NOTE: the form MIGHT not be setup yet, so the control
   ''' might not know what it's parent is yet, so we cache the the first control
   ''' we get, and use it later, if necessary
   ''' </summary>
   ''' <param name="control"></param>
   ''' <param name="caption"></param>
   ''' <remarks></remarks>
   Public Shadows Sub SetToolTip(ByVal control As Control, ByVal caption As String)
      MyBase.SetToolTip(control, caption)

      '---- if we don't have the parent form yet...
      If rParentForm Is Nothing Then
         '---- attempt to get it from the control
         rParentForm = control.FindForm
         '---- if that doesn't work
         If rParentForm Is Nothing Then
            '---- cache the control for use a little later
            rControl = control
         End If
      End If
   End Sub


   Public Sub BeginInit() Implements ISupportInitialize.BeginInit
      '---- Our base tooltip is disabled by default
      '     because we don't want to show disabled tooltips when
      '     a control is NOT disabled!
      MyBase.Active = False
   End Sub


   ''' <summary>
   ''' Supports end of initialization phase tasks for this control
   ''' </summary>
   ''' <remarks></remarks>
   Public Sub EndInit() Implements ISupportInitialize.EndInit
      '---- if we weren't able to retrieve the form from the control
      '     before, we should be able to now
      If rControl IsNot Nothing Then
         rParentForm = rControl.FindForm
      End If
   End Sub


   Public Sub New(ByVal IContainer As IContainer)
      MyBase.New(IContainer)
   End Sub


   ''' <summary>
   ''' Monitor the MouseMove event on the host form
   ''' If we see it move over a disabled control
   ''' Check for a tooltip and show it
   ''' If the cursor moved off the control we're displaying
   ''' a tip for, hide the tip.
   ''' </summary>
   ''' <param name="sender"></param>
   ''' <param name="e"></param>
   ''' <remarks></remarks>
   Private Sub rParentForm_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles rParentForm.MouseMove
      Static ctrlWithToolTip As Control = Nothing

      Dim ctrl = rParentForm.GetChildAtPoint(e.Location)

      If ctrl IsNot Nothing Then
         If Not ctrl.Enabled Then
            If ctrlWithToolTip IsNot Nothing Then
               If ctrl IsNot ctrlWithToolTip Then
                  '---- if we're not over the control we last showed
                  '     a tip for, close down the tip
                  Me.Hide(ctrlWithToolTip)
                  ctrlWithToolTip = Nothing
                  MyBase.Active = False
               End If
            End If
            If ctrlWithToolTip Is Nothing Then
               Dim tipstring = Me.GetToolTip(ctrl)
               If Len(tipstring) And Me.Active Then
                  '---- only enable the base tooltip if we're going to show one
                  MyBase.Active = True
                  Me.Show(tipstring, ctrl, ctrl.Width / 2, ctrl.Height / 2)
                  ctrlWithToolTip = ctrl
               End If
            End If

         ElseIf ctrlWithToolTip IsNot Nothing Then
            '---- if we're over an enabled control
            '     the tip doesn't apply anymore
            Me.Hide(ctrlWithToolTip)
            ctrlWithToolTip = Nothing
            MyBase.Active = False
         End If
      ElseIf ctrlWithToolTip IsNot Nothing Then
         '---- if we're not over a control at all, but we've got a
         '     tip showing, hide it, it's no longer applicable
         Me.Hide(ctrlWithToolTip)
         ctrlWithToolTip = Nothing
         MyBase.Active = False
      End If
   End Sub
End Class

Another VS Programming Font

1
Filed under .NET, Fonts

I blogged about fonts quite a while back here.

But I thought I’d add a reference to a new font I just stumbled across by DamienG on his blog, called Envy Code R.

I especially like his italics as bold trick that enables you to have Italics comments in Visual Studio even though VS only has an option for bold, even in VS2008.

image Envy Code R Pretty good, but a bit compressed, note the small M. To me, the verticals are so close together, they blur a bit. It’s also a tad taller than Consolas.

Even if you don’t care for the font, his VS color schemes, particularly Humane, are definitely worth a try.

Very nice.

Consolas with his bold-italics trick would be a very nice VS2008 font indeed. Hmmm.

A Great Little Headset

0
Filed under Hardware

image I’ve got a Uniden TX-860 Two Line expandable 5.8 ghz phone system at the house that’s great for a home office setup. The battery life is excellent, sound is as clear as a wired set, it has distinctive rings (so office calls don’t get confused with personal calls), and a headset jack, plus it’s expandable to 8 or 10 phones.

The only downside is that it’s been very  difficult to find a headset that works well with it.

I’ve gone through literally a dozen plus headsets and all of them (except the one that came with the phone) make my voice to the other party sound like I’m yelling from across a football field.

But the one that came with the phone… Well…

image

No volume, no mute, big, clunky. It works, but that’s about all you can say for it.

I even checked out the highly-rated TheBoom and the Etymotic sets, but they weren’t any better.

I actually tried several Plantronics sets from time to time, but none of them gave a good voice level either. Then I ran into the Plantronics MX500C, one that I hadn’t tried before. It was cheap so I figured I’d give it a shot.

image

Awesome little gizmo. My voice sounds loud and clear to my callee, it’s got a volume control (mic and earpiece) and a mute, plus it’s lightweight and comfortable to boot. For 19.99 at Fry’s, it’s the best companion to my phones I’ve found yet.

No More Simulated Multithreading

0
Filed under .NET, VB Feng Shui

Way back in the wild west days of VB6, if you wanted a long running utility to ALSO pop up a progress bar, be cancelable, and be nicely encapsulated in a reusable class, you didn’t have a lot of options.

The first was to actually use VB6’s multithreading support via a thread per object ActiveX exe. It worked, but it wasn’t a trivial exercise.

One trick I used on a number of occasions was the modal form callback.

Essentially, it works like this.

  • You call into a class to “start” the long running process.
  • The class opens an associated progress form, and passes itself to the form.
  • The Progress form stores a WithEvents reference to the class, so it can be notified of progress as the class does its work.
  • Then, the form shows itself modally, and in the Activate event, calls back into the class to actually start the processing.
  • The class then starts it’s long running processing, raising progress events as appropriate, and yielding via DOEVENTS at appropriate times.

It’s a tad complex, to be sure, but certainly less complex than some of the alternatives and it still yields a nicely responsive UI that the user can easily cancel out of.

Fast forward to today. I had a similar requirement for a little VB.NET utility, so I figured, what the hey, might as well use that old trick.

After a bit of coding, I run the app and am rewarded with this:

image

Huh? I wasn’t “Attempting to call into managed code without transitioning out first.” Heck, there wasn’t even any API calls in this mix, Much less “Low Level extensibility points”!

Of course, the VS help for this message proved utterly useless, so I start googling.

Equally useless. Surely, I’m not the only guy out there to get this treat, right?

Anyway, eventually, I decided that maybe, just maybe, something about the reentrancy into the class from a modal dialog was causing the problem, though I still don’t have concrete proof of that.

I reworked the class to cooperate with the BackgroundWorker component (a nifty little bit of new .NET goodness), and everything’s back on track.

The only bit of nastiness left is that my background worker class raises several events, which my progress form monitors and presents, but doing anything within those events directly resulted in an exception about accessing UI objects from a thread other than the one they were created on.

The VS Help was helpful for this though, and adding code like this to the event handlers…

   Delegate Sub ScanningFileCallback(ByVal FileName As String, ByVal Count As Integer)
   Private WithEvents MyClass As MyClass

   Private Sub MyClass_ScanningFile(ByVal FileName As String, ByVal Count As Integer) Handles MyClass.ScanningFile
      If Me.prgProgress.InvokeRequired Then
         Dim d As New ScanningFileCallback(AddressOf MyClass_ScanningFile)
         Me.Invoke(d, New Object() {FileName, Count})
      Else
         me.prgProgress.Maximum = MyClass.FileCount
         me.prgProgress.Value = Count
      End If
   End Sub

worked around that problem nicely, although it’d be nice if the background worker class could somehow handle this transition itself. Hmmm….