Archive for the ‘csharp’ Category.

How to configure the WPF RadioButton’s circle bullet top aligned when there are multiple lines of text?

Today I had to solve a problem that appeared quite difficult, but turned out to not be so hard if I let Expression Blend do most the work and finish it up in the XAML. I ended up having to completely recreate the default template style and then modify it.

Note: This article could also be titled: How to change the default template style of a standard control?

I had a RadioButton with text that wraps and it wasn’t displaying exactly how my team wanted. Here is the XAML.

<Window x:Class="RadioButtonTopAligned.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <RadioButton GroupName="RadioButtonList">
            <Label>
                <AccessText TextWrapping="Wrap" Text="_This is a very long radio button control line of text that should wrap." MaxWidth="300"/>
            </Label>
        </RadioButton>
    </Grid>
</Window>

The problem is that the circle bullet is center aligned like this:

Notice how the circle bullet is aligned in between the two lines of text. I need it to be top aligned like this:

Notice how the circle bullet is aligned with the top line of text. I need to get WPF to do this.

From a Visual Studio 2010 point of view, there is no easy way to do this. At first I thought it would be a simple dependency property, but it isn’t. An quick internet search led me to realize that I have to pretty much re-style the whole RadioButton. This sounds really hard and in fact, in Visual Studio, without help, it would be really hard. You would have to have the code for the default template style for the RadioButton control memorized.

Here is an forum post I found from MSDN: How do I make a RadioButton’s Bullet align top

While the post is exactly what I was looking for and has an answer, I didn’t at first grasp the answer. I wasn’t sure what was going on until one of my co-workers, Shawn, who is more skilled in Expression Blend, showed me. Now that I understand, I want to make sure the next person who finds the same forum post on MSDN can understand even easier by writing this article and adding it to the forum post.

This is where Expression Blend comes in. If you don’t have Expression Blend, don’t worry, you can still get through this article as I will include the the default style code that Expression Blend created for me right here in my post.

In Expression Blend, this is what to do.

  1. Create a blank WPF project in Expression Blend.
  2. Add a RadioButton.
  3. Right-click on the RadioButton and choose Edit Template | Edit a Copy…
  4. Click OK on the Create Style Resource window.

Here is what happens to your XAML and you can do this to the XAML in you project manually if you don’t have Expression Blend.

  1. The following reference is added to the project: PresentationFramework.Aero
  2. The same is referenced in the XAML (See line 4 of the XAML below)
  3. The default RadioButton style is copied to your XAML under the Window.Resources element.  (See lines 10-48 in the XAML below)
  4. The RadioButton is assigned the style created. (See line 51 in the XAML below)
<Window
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
	x:Class="RadioButtonTopAligned_EB.MainWindow"
	x:Name="Window"
	Title="MainWindow"
	Width="640" Height="480">

	<Window.Resources>
		<SolidColorBrush x:Key="CheckBoxStroke" Color="#8E8F8F"/>
		<Style x:Key="CheckRadioFocusVisual">
			<Setter Property="Control.Template">
				<Setter.Value>
					<ControlTemplate>
						<Rectangle Margin="14,0,0,0" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
					</ControlTemplate>
				</Setter.Value>
			</Setter>
		</Style>
		<Style x:Key="RadioButtonStyle1" TargetType="{x:Type RadioButton}">
			<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
			<Setter Property="Background" Value="#F4F4F4"/>
			<Setter Property="BorderBrush" Value="{StaticResource CheckBoxStroke}"/>
			<Setter Property="BorderThickness" Value="1"/>
			<Setter Property="Template">
				<Setter.Value>
					<ControlTemplate TargetType="{x:Type RadioButton}">
						<BulletDecorator Background="Transparent">
							<BulletDecorator.Bullet>
								<Microsoft_Windows_Themes:BulletChrome BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" IsChecked="{TemplateBinding IsChecked}" IsRound="true" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}"/>
							</BulletDecorator.Bullet>
							<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
						</BulletDecorator>
						<ControlTemplate.Triggers>
							<Trigger Property="HasContent" Value="true">
								<Setter Property="FocusVisualStyle" Value="{StaticResource CheckRadioFocusVisual}"/>
								<Setter Property="Padding" Value="4,0,0,0"/>
							</Trigger>
							<Trigger Property="IsEnabled" Value="false">
								<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
							</Trigger>
						</ControlTemplate.Triggers>
					</ControlTemplate>
				</Setter.Value>
			</Setter>
		</Style>
	</Window.Resources>

	<Grid x:Name="LayoutRoot">
		<RadioButton GroupName="RadioButtonList" Style="{DynamicResource RadioButtonStyle1}">
			<Label>
				<AccessText TextWrapping="Wrap" Text="_This is a very long radio button control line of text that should wrap." MaxWidth="300"/>
			</Label>
		</RadioButton>
	</Grid>
</Window>

Now we can edit the XAML. Below is the same XAML as above with the following edits:

  1. Inside the BulletDecorator.Bullet element on line 30, create a DockPanel around the BulletChrome element.
  2. The ControlPresenter is moved to be inside the DockPanel.
  3. Add the following XAML atrributes to the BulletChrome element:
    VerticalAlignment=”Top” Margin=”0,8,0,0″ Height=”{TemplateBinding FontSize}” Width=”{TemplateBinding FontSize}”

    Note: If you change the font of the text content in the RadioButton, you should change the Margin in the style as well. I haven’t figured out how to make it always match the top line without manually tweaking it when you change the font. Also, if you don’t want the BulletChrome element to be the same size as the font, you will have to tweak Width and Height too.

<Window
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
	x:Class="RadioButtonTopAligned_EB.MainWindow"
	x:Name="Window"
	Title="MainWindow"
	Width="640" Height="480">

	<Window.Resources>
		<SolidColorBrush x:Key="CheckBoxStroke" Color="#8E8F8F"/>
		<Style x:Key="CheckRadioFocusVisual">
			<Setter Property="Control.Template">
				<Setter.Value>
					<ControlTemplate>
						<Rectangle Margin="14,0,0,0" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
					</ControlTemplate>
				</Setter.Value>
			</Setter>
		</Style>
		<Style x:Key="RadioButtonStyle1" TargetType="{x:Type RadioButton}">
			<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
			<Setter Property="Background" Value="#F4F4F4"/>
			<Setter Property="BorderBrush" Value="{StaticResource CheckBoxStroke}"/>
			<Setter Property="BorderThickness" Value="1"/>
			<Setter Property="Template">
				<Setter.Value>
					<ControlTemplate TargetType="{x:Type RadioButton}">
						<BulletDecorator Background="Transparent">
							<BulletDecorator.Bullet>
								<DockPanel>
									<Microsoft_Windows_Themes:BulletChrome VerticalAlignment="Top" Margin="0,8,0,0" Height="{TemplateBinding FontSize}" Width="{TemplateBinding FontSize}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" IsChecked="{TemplateBinding IsChecked}" IsRound="true" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" />
									<ContentPresenter RecognizesAccessKey="True" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
								</DockPanel>
							</BulletDecorator.Bullet>
							</BulletDecorator>
						<ControlTemplate.Triggers>
							<Trigger Property="HasContent" Value="true">
								<Setter Property="FocusVisualStyle" Value="{StaticResource CheckRadioFocusVisual}"/>
								<Setter Property="Padding" Value="4,0,0,0"/>
							</Trigger>
							<Trigger Property="IsEnabled" Value="false">
								<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
							</Trigger>
						</ControlTemplate.Triggers>
					</ControlTemplate>
				</Setter.Value>
			</Setter>
		</Style>
	</Window.Resources>

	<Grid x:Name="LayoutRoot">
		<RadioButton GroupName="RadioButtonList" Style="{DynamicResource RadioButtonStyle1}">
			<Label>
				<AccessText TextWrapping="Wrap" Text="_This is a very long radio button control line of text that should wrap." MaxWidth="300"/>
			</Label>
		</RadioButton>
	</Grid>
</Window>

I hope this posts clarifies how to completely recreate a template style for a default control to modify something that at first doesn’t appear modifiable.

WPF NavigationService blanks PasswordBox.Password, which breaks the MVVM PasswordHelper

I am using three things that are just not friends:

  • Pages and NavigationService
  • Model-View-ViewModel design
  • The PasswordBox control

Problem 1 – PasswordBox.Password is not a DependencyProperty

First off, Model-View-ViewModel is design centered around data binding. But PasswordBox.Password is not a DependencyProperty and therefore does not support binding. That is ok, a PasswordBoxAssistant (alternately I have seen it named PasswordHelper or PasswordBoxHelper) as described originally here and also here fixes seems to fix this.

That is, it fixes it unless you are using the NavigationService.

Problem 2 – NavigationService blanks PasswordBox.Password

See when the NavigationService navigates to another page, it somehow know that the current page has a PasswordBox and if it finds a PasswordBox, it blanks the password out.  So since we are using PasswordBoxHelper to make MVVM and data binding work, the value is blanked in the ViewModel and Model as well.

For now, I happen to be using a custom button for navigation so I can simply do this in my ViewModel:

String tempPw = MyPassword;
NavigationService.Navigate(NewPage);
MyPassword = tempPw;

However, this is not the best solution. What if there were multiple links and different ways to navigate?

I think the best solution would be to figure out how to make PasswordBoxAssistant handle this. But I am not sure how or if there is anyway to tell that the password was blanked by the NavigationService and to ignore binding in this instance.

Resource:
http://social.msdn.microsoft.com/Forums/en/wpf/thread/d91aec90-1476-41c0-a925-7661745094c5

Navigation and Pages using Model-View-ViewModel (MVVM)

I am working on a project at work that is a navigation application.

I wanted to use MVVM. I also wanted to document for others how I designed this, as there wasn’t much online about using MVVM with Navigation and Pages.

Here is my project. I will post an explanation of this project as soon as I can get to it, so look for it.

Project Download – Small: Navigation-Pages-MVVM.zip

Project Download – More complete: Navigation-Pages-MVVM 2.0

Installing the latest version of Mono on FreeBSD or How to install and use portshaker?

Mono is basically the .NET Framework on FreeBSD or other open source platforms. This allows development in C# on FreeBSD.  C# is an extremely popular language that is not slowing down.  It’s popularity stems from that fact that this language and its features allows for rapid development that is much faster than many other languages.

The version of Mono available in the ports tree is not the latest version available. Just like FreeBSD has a release version and a development version, Mono has a release version and a development version.  The development version is so much newer that it is hard not to recommend it over the release version.

Step 1 – Install the latest ports

This is already documented here:

How to install ports on FreeBSD?

Step 2 – Install portshaker and portshaker-config

The team at BSD# have a tool called portshaker that adds mono ports to the ports tree.  Install it as follows.

#
#
cd /usr/ports/ports-mgmt/portshaker-config
make BATCH=yes install

Note: Notice I didn’t just install portshaker, I installed portshaker-config which has portshaker as a dependency, so you get both installed with one command.

Step 3 – Configure portshaker

The example portshaker.conf.example is configured correctly for default configurations, so all we need to do is copy it.

# cp /usr/local/etc/portshaker.conf.example /usr/local/etc/portshaker.conf

Step 4 – Run portshaker

Yes, it is that easy.  Simply run portshaker.

# portshaker

Note: You may be prompted to merge a few files. I diffed and chose either install or continue each time.

Note: Running portshaker uses subversion to download so if you need to use an HTTP proxy, you have to configure subversion to use an HTTP proxy as it doesn’t use the FreeBSD HTTP_PROXY environment variable.

Your ports tree is now updated by portshaker.

Step 5 – Install mono

The mono port should now be updated to the latest version.

#
#
cd /usr/ports/lang/mono
make BATCH=yes install

Mono is now installed on your system.

There is an example of building a hello world app here:

C# (Mono) on FreeBSD

Expression + Sketch Flow for prototyping

I have historically done mock-ups in two ways:

  1. Just code it up
  2. Paint.NET

Neither are really good solutions.  But as a developer for an enterprise product, the above tools just are not sufficient.

So I have recently introduced to SketchFlow. This is a tool for quickly mocking up your UI.  It has some features that are quite nice and I am impressed.  I can create a UI very quickly and maybe even faster than I could with Paint.NET on the first try.  After using SketchFlow for a while, it will be a lot faster.

There are three features that make SketchFlow an amazing tool for UI prototyping.

  1. The ability to map and design at the same time
  2. The ability to package it for a demo
  3. The ability to export the prototype to word.

These features make it so that for the same or less work that we have to do anyway to provide sample screens, we also get 1) a Map that we otherwise would have had to spend extra time creating in Visio or elsewhere, 2) A packaged demo that we can send to customers for feed back early on before development so we develop it right the first time, and 3) Stub documentation with all the screens and topical guides exported to word in seconds.

All three of these features are demonstrated in this Video.

Get Microsoft Silverlight

Note: For my FreeBSD readers...this might not be for you though it would be interesting to see if Moonlight can load this video.

Using Path.Combine in C# to eliminate bugs with concatenation

I read a post about the C# function called Path.Combine() today.

Use Path.Combine instead of Concatenating Paths

I love finding these little functions that I didn’t know about before. These are so simple and yet so efficient. I combine paths all the time and I have to spend time making sure that I have all the slashes where they need to be and this is just more work than it should be.  Sure enough, if you use the Path.Combine function, it does this for you.

See Path.Combine on MSDN.

WPF and Localization in the XAML with String.Format()

I had a localization issue today.

I was trying to get our product running in Spanish to show decimals as a comma (,) instead of a period (.).

Here is the XAML snippet I have.

        <StackPanel Orientation="Horizontal" Margin="0,0,0,5" >
            <Image Source="{Binding Image}" Width="24" Height="24" />
            <Label>
                <TextBlock>
                  <TextBlock.Text>
                         <MultiBinding StringFormat="{}{0} ({1}:) - {2} {3:F} GB, {4} {5:F} GB, {6} {7:F} GB">
                            <Binding Path="Drive.VolumeLabel" />
                            <Binding Path="Drive.DriveLetter" />
                            <Binding Source="{x:Static p:Resources.Required}" />
                            <Binding Path="Drive.TotalRequiredSpace.Gigabyte" />
                            <Binding Source="{x:Static p:Resources.Recommended}" />
                            <Binding Path="Drive.TotalRecommendedSpace.Gigabyte" />
                            <Binding Source="{x:Static p:Resources.Available}" />
                            <Binding Path="Drive.AvailableSpace.Gigabyte" />
                         </MultiBinding>
                  </TextBlock.Text>
                </TextBlock>
            </Label>
            <Image Source="{Binding DriveSpaceStatusImage}" Width="24" Height="24" Margin="15,0" />
        </StackPanel>

The Drive.TotalRequiredSpace object is a DataMeasurement object (which I have posted code for in a previous post).

The Gigabyte parameter is a Double.  These Double’s displayed the decimal separator using a period (.) character even though I was testing on a Spanish version of Windows Server 2008 R2.

I located the answer on another blog.
WPF Data Binding Cheat Sheet Update – The Internationalization Fix

He was using Date’s which like Double’s require decimals, and was seeing the same issue.  The solution is the same though.

Add the following code somewhere before your first WPF window opens.

System.Windows.FrameworkElement.LanguageProperty.OverrideMetadata
(
    typeof(System.Windows.FrameworkElement),
    new System.Windows.FrameworkPropertyMetadata(
        System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)
    )
);

I am pretty sure this is a poor oversight and a bug in my opinion. Even though there is a one line fix, it was a costly fix, as I had to spend time troubleshooting and researching to find this one line solution which should be the default behavior.

A WPF XAML DataBinding Cheat Sheet

I found this Cheat Sheet and thought I would link to it as it could be very useful.

WPF XAML Data Binding Cheat Sheet

Binding Visibility to a bool value in WPF

Please go here for updates to this post:

Binding Visibility to a bool value in WPF

I was putting code in my ViewModel that returns Visibility but I didn’t really like that very much. If the UI is created with something other than WPF, that is really not going to work. Since I intend to do cross compile my code in Mono, which doesn’t have WPF but uses either Forms or GTK#, I have already encountered this issue. What I really want to use is bool.

The solution is IValueConverter. If you just want the code and don’t want to read this post, just scroll to the bottom and grab the

IValueConverter is part of PresentationFramework (in PresentationFramework.dll) so it isn’t available in Mono, but that is OK because you don’t instantiate it in the ViewModel, you use it in the View so it will only be used when the GUI is part of WPF. So if you are separating your View into a separate DLL, this would be included in the View DLL, that way when you compile everything else, with say a different GUI that uses GTK#, you won’t get a compiler error because PresentationFramework doesn’t exist in Mono.

BooleanToVisibilityConverter

Well, there is an object already created for you called BooleanToVisibilityConverter, but it is limited. True is converted Visibility.Visible. False is converted to Visibility.Collapsed.

Here we see a problem. Visibility has three possible values but a Boolean only has two.

Boolean Visibility
True Visible
False Collapsed
Hidden

This will cover many of the scenarios, but not all.

Here is how it would be used.

For this example, I have this Person class.

    public class Person
    {
        public Person() { }
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String Age { get; set; }
    }

Here is a simple View for this object. It has a Grid that has a Label and TextBox for each property in the Person object. It also has a CheckBox. The CheckBox gives us a easy bool value, IsChecked. This works similar to a bool property in a ViewModel.

<Window x:Class="TestBooleanToVisibilityConverter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestBooleanToVisibilityConverter"
        Title="MainWindow"
        SizeToContent="WidthAndHeight"
        >
    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid Name="PersonViewGrid">
            <Grid.Resources>
                <BooleanToVisibilityConverter x:Key="BoolToVisConverter"/>
            </Grid.Resources>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Label Content="First Name:" Grid.Column="0" Grid.Row="0" />
            <TextBox Grid.Column="1" Grid.Row="0" Name="firstNameTextBox"
                     Text="{Binding Path=FirstName, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" MinWidth="175" />
            <Label Content="Last Name:" Grid.Column="0" Grid.Row="1" />
            <TextBox Grid.Column="1" Grid.Row="1" Name="lastNameTextBox"
                     Text="{Binding Path=LastName, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" MinWidth="175" />
            <Label Content="Age:" Grid.Column="0" Grid.Row="2"
                   Visibility="{Binding IsChecked, ElementName=ShowAgeCheckBox, Converter={StaticResource BoolToVisConverter}}"/>
            <TextBox Grid.Column="1" Grid.Row="2" Name="ageTextBox"
                     Text="{Binding Path=Age, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" MinWidth="175"
                   Visibility="{Binding IsChecked, ElementName=ShowAgeCheckBox, Converter={StaticResource BoolToVisConverter}}"/>
        </Grid>
        <Grid Grid.Row="1">
            <CheckBox Name="ShowAgeCheckBox" Content="Show Age" />
        </Grid>
    </Grid>
</Window>

I am not using MVVM for this example, but instead there is a just a single object created in the code behind for demo purposes.

using System;
using System.Windows;

namespace TestBooleanToVisibilityConverter
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent(); Person p = new Person() { FirstName = "Michael", LastName = "Michaels", Age = "33" };
            PersonViewGrid.DataContext = p;
        }

    }
}

Ok, now build the project and you will see that the Label and TextBox for Age are hidden until you check the box.

Writing your own Bool to Visibility Converter

Sometimes you may need to write you own Converter.  For example, in the above project, it is annoying how the CheckBox moves up and down in position because Visibility.Collapsed is used instead of Visibility.Hidden.  You may want to use Visibility.Hidden instead.

You can write your own Converter that returns Visibility.Hidden instead of Visibility.Collapsed.

BooleanToVisibleOrHidden.cs

using System;
using System.Windows.Data;
using System.Windows;

namespace TestBooleanToVisibilityConverter
{
    class BoolToVisibleOrHidden : IValueConverter
    {
        #region Constructors
        /// <summary>
        /// The default constructor
        /// </summary>
        public BoolToVisibleOrHidden() { }
        #endregion

        #region IValueConverter Members
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool bValue = (bool)value;
            if (bValue)
                return Visibility.Visible;
            else
                return Visibility.Hidden;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Visibility visibility = (Visibility)value;

            if (visibility == Visibility.Visible)
                return true;
            else
                return false;
        }
        #endregion
    }
}

Here we do the conversion ourselves and now we have a different conversion table.

Boolean Visibility
True Visible
Collapsed
False Hidden

Now replace the Converter object in your XAML.  We only change Line 15.

      <local:BoolToVisibleOrHidden x:Key="BoolToVisConverter"/>

This works, but it could be improved. This still leaves us having to choose between two objects.

Creating a Converter that supports a choice of Hidden or Collapsed.

Here we will provide a property that determines if we should collapse or not.

Add a property called Collapse and return the appropriate Visibility based on that property. Here is the new object. As you see, the code changes to add this feature is really just an empty bool property and an if statement that used the bool property.

using System;
using System.Windows.Data;
using System.Windows;

namespace TestBooleanToVisibilityConverter
{
    class BoolToVisibleOrHidden : IValueConverter
    {
        #region Constructors
        /// <summary>
        /// The default constructor
        /// </summary>
        public BoolToVisibleOrHidden() { }
        #endregion

        #region Properties
        public bool Collapse { get; set; }
        #endregion

        #region IValueConverter Members
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool bValue = (bool)value;
            if (bValue)
            {
                return Visibility.Visible;
            }
            else
            {
                if (Collapse)
                    return Visibility.Collapsed;
                else
                    return Visibility.Hidden;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Visibility visibility = (Visibility)value;

            if (visibility == Visibility.Visible)
                return true;
            else
                return false;
        }
        #endregion
    }
}

Now in your XAML you have the option to do nothing, which uses the bool default value false, or to set the Collapse property to true as shown below.

      <local:BoolToVisibleOrHidden x:Key="BoolToVisConverter" Collapse="True"/>

We now support either feature with the following table. We probably at this point would rename the object to BooleanToVisibilityConverter, but Microsoft already took that object name so I will leave it named as is.

Boolean Visibility
True Visible
False – Collapse=True Collapsed
False – Collapse=False Hidden

We are starting to get a little more usability from one object.

Adding the Reverse feature so False is Visible and True is Collapsed or Hidden

Lets say we want to change the CheckBox so that instead of saying “Show Age” it says “Hide Age”.

            <CheckBox Name="ShowAgeCheckBox" Content="Hide Age" />

Now we have to reverse the mapping. If Reverse=”True” we want the mapping to be like this:

Boolean Visibility
False Visible
True – Collapse=True Collapsed
True – Collapse=False Hidden

This is also quite simple. We add another bool property called Reverse. Then key of that in another if statement.

using System;
using System.Windows.Data;
using System.Windows;

namespace TestBooleanToVisibilityConverter
{
    class BoolToVisibleOrHidden : IValueConverter
    {
        #region Constructors
        /// <summary>
        /// The default constructor
        /// </summary>
        public BoolToVisibleOrHidden() { }
        #endregion

        #region Properties
        public bool Collapse { get; set; }
        public bool Reverse { get; set; }
        #endregion

        #region IValueConverter Members
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool bValue = (bool)value;

                if (bValue != Reverse)
                {
                    return Visibility.Visible;
                }
                else
                {
                    if (Collapse)
                        return Visibility.Collapsed;
                    else
                        return Visibility.Hidden;
                }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Visibility visibility = (Visibility)value;

                if (visibility == Visibility.Visible)
                    return !Reverse;
                else
                    return Reverse;
        }
        #endregion
    }
}

Now you can reverse this very easily in the XAML.

      <local:BoolToVisibleOrHidden x:Key="BoolToVisConverter" Collapse="True" Reverse="True" />

And now you have a much more full featured converter.

Additional Thoughts

I have to wonder why the developers didn’t do this originally with the BooleanToVisibilityConverter object. It is so simple. This is a perfect example of where Microsoft would benefit from Open Sourcing some of their code. A dozen people would have contributed this change by now if they had and all Microsoft would have to do is look at the submitted code, approve, and check it in.

Handling a custom name space (xmlns) in an XML with Xml Serialization

I have an xml that has a name space. This gave me to problems I had to resolve.

  1. How do I deserialize this xml with that name space value?
  2. How do I serialize the object to only have this one name space?

Deserializing an Xml with a Name Space

Below is an Xml file. Notice that the PrimaryNode has a name space that isn’t the default.

<?xml version="1.0" encoding="utf-8"?>
<PrimaryNode xmlns="http://some/random/namespace/example>
  <SecondaryNode>
    <TertiaryNode />
    <TertiaryNode />
  </SecondaryNode>
</PrimaryNode>

I had an object created as follows.

using System;
using System.Xml.Serialization;
using System.Collections.ObjectModel;

namespace XmlNameSpaceTest.Model
{
    [Serializable()]
    public class PrimaryNode
    {
        private ObservableCollection<SecondaryNode> _Children;

        public PrimaryNode() { }

        [XmlElement("SecondaryNode")]
        public ObservableCollection<SecondaryNode> Children
        {
            get
            {
                if (_Children == null)
                    _Children = new ObservableCollection<SecondaryNode>();
                return _Children;
            }
        }
    }
}

I used this static class for the serialization

using System;
using System.IO;
using System.Xml.Serialization;

namespace XmlNameSpaceTest.Model
{
    public class Serializer
    {
        #region Functions
        public static void SerializeToXML<T>(T t, String inFilename)
        {
            XmlSerializer serializer = new XmlSerializer(t.GetType());
            TextWriter textWriter = new StreamWriter(inFilename);
            serializer.Serialize(textWriter, t);
            textWriter.Close();
        }

        public static T DeserializeFromXML<T>(String inFilename)
        {
            XmlSerializer deserializer = new XmlSerializer(typeof(T));
            TextReader textReader = new StreamReader(inFilename);
            T retVal = (T)deserializer.Deserialize(textReader);
            textReader.Close();
            return retVal;
        }
        #endregion
    }
}

But it failed to deserialize because of the name space. It gave me this exception (which I trimmed to only show the important parts as it was very long).

System.InvalidOperationException was unhandled
  Message=There is an error in XML document (2, 2).
  Source=System.Xml
  StackTrace:
       <-- snipped -->
  InnerException: System.InvalidOperationException
       Message=<PrimaryNode xmlns='http://some/random/namespace/example'> was not expected.
       Source=bgwwvhdx
       StackTrace:
            at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderPrimaryNode.Read7_PrimaryNode()

The solution was simple. I had to add the XmlRoot tag above the class.

    [Serializable()]
    [XmlRoot(Namespace="http://some/random/namespace/example")]
    public class PrimaryNode
    {
        ... snipped...
    }

This solved problem 1. The Xml now deserialized just fine.

Serializing an Xml so it only contains a single Name Space

When I serialized the object, there were two default name spaces, but neither were the custom name space that the Xml needed.

<?xml version="1.0" encoding="utf-8"?>
<PrimaryNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <SecondaryNode>
    <TertiaryNode />
    <TertiaryNode />
  </SecondaryNode>
</PrimaryNode>

Here is what I had to do.

1. Add a XmlSerializerNamespaces property with only the one name space added.

    [Serializable()]
    [XmlRoot(Namespace="http://some/random/namespace/example")]
    public class PrimaryNode
    {
        ... snipped...

        private XmlSerializerNamespaces _Namespaces;

        public XmlSerializerNamespaces NameSpaces
        {
            get
            {
                if (_Namespaces == null)
                {
                    _Namespaces = new XmlSerializerNamespaces();
                    _Namespaces.Add("", "http://schemas.microsoft.com/wix/2006/wi");
                }
                return _Namespaces;
            }
        }
    }

2. Then I had to change my Serializer class. I needed to overload the Serialize function by adding a version of it that accepts the XmlSerializerNamespaces object as the third parameter.

        public static void SerializeToXML<T>(T t, String inFilename, XmlSerializerNamespaces namespaces)
        {
            XmlSerializer serializer = new XmlSerializer(t.GetType());
            TextWriter textWriter = new StreamWriter(inFilename);
            serializer.Serialize(textWriter, t, namespaces);
            textWriter.Close();
        }

3. Then, you’ve probably realized already, when serializing the object to Xml, we use this new function and pass it the PrimaryNode.NameSpaces as the third parameter.

This solved the second problem.

I hope this post helps you.

WPF Label, TextBox, and Mnemonics

Hello. Today I had to get mnemonic to work. Mnemonic is the ability to navigate to a control using a key stroke combination. One of the most common mnemonics is Alt + F. Alt + F usually navigates to the File drop down menu in any Window, and most everyone is familiar with this mnemonic.

In WPF, to get mnemonics, you pretty much just put an underscore in front of a word. For example, for Alt + F, you would enter: _File

Well, in WPF I needed to do the Label, TextBox matching, so that the mnemonics is on a Label but the key strokes navigate the keyboard focus to the TextBox.

Lets say you have a simple form in WPF like this:

The XAML to make these work together using mnemonics is simple. The important property is Target.

<Window x:Class="Mnemonics.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" >
    <Grid FocusManager.FocusedElement="{Binding ElementName=textBoxFirstName}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Label Target="{Binding ElementName=textBoxFirstName}" HorizontalContentAlignment="Right">
            <AccessText TextWrapping="WrapWithOverflow">First _Name:</AccessText>
        </Label>
        <TextBox Name="textBoxFirstName" Width="200" Height="20" Grid.Column="1"/>
        <Label Target="{Binding ElementName=textBoxLastName}" HorizontalContentAlignment="Right" Grid.Row="1">
            <AccessText TextWrapping="WrapWithOverflow">_Last Name:</AccessText>
        </Label>
        <TextBox Name="textBoxLastName" Width="200" Height="20" Grid.Row="1" Grid.Column="1"/>
    </Grid>
</Window>

Lets discuss the code above briefly.

  1. Notice line 5 first.  Here I am setting the FocusManager.FocusedElement to the first text box so that you can immediately type in the first field when arriving at the window.
  2. Notice the use of AccessText instead of TextBlock (lines 15, 19).  You don’t have to do it this way.  You could have just set the Content property on the label. You don’t need the AccessText at all unless you want to wrap.  If you want to wrap, you have to do it this way.
  3. Notice the use of Target (lines 18,14) and how it is bound to the element that should receive focus when the mnemonic keys are pressed.

Hope this helps you.

www.wpftutorial.net – just found a new WPF Tutorial site

I just found http://www.wpftutorial.net.

Just another resource for WPF information.

C# DataMeasurement object for comparing, converting, and adding or substracting data sizes

I created a C# DataMeasurement object a while ago but recently really started to use it. I wrote unit tests for it and fixed comparison and add/substract of nulls and wrote Unit tests for it.

The intent of the object is to be able to use any Data size and do the following:

  1. Convert it to any other data size type, 1 GB converts to 1024 MB.
  2. Compare it to any other data size type, 1 GB = 1024 MB.
  3. Add any other data size type and have it add correctly, 1 GB + 1024 MB = 2GB.

So you can easily compare things like 12343 bytes.

You can create the object in a lot of different ways as I have multiple constructors, and it is easy to add your own constructor.

Here is the object:

using System;
using System.Collections.Generic;
using System.Text;

namespace LANDesk.Install.Common
{
    public class DataMeasurement
    {
        #region Member Variables
        // This is the size in the current type. For example, 1 GB = 1.0. But
        // if you convert the Type to Megabyte, the value should change to 1024.0;
        protected Double _DataSize;  
        protected DataType _DataType;
        #endregion

        #region Constructors

        /// <summary>
        /// The default constructor.  This initializes and object with a
        /// DataSize of 0 and a DataType of Byte.
        /// </summary>
        public DataMeasurement()
        {
            _DataSize = 0;
            _DataType = DataType.Byte;
        }

        /// <summary>
        /// This constructor takes a value and assumes the data measurement
        /// type is in bytes.
        /// </summary>
        /// <param name="inValue">The measurement value as a ulong.</param>
        public DataMeasurement(UInt64 inSizeInBytes)
        {
            _DataType = DataType.Byte;
            _DataSize = inSizeInBytes * 8;
        }

        /// <summary>
        /// This constructor takes a value and a data measurement type.
        /// </summary>
        /// <param name="inValue">The measurement value as a ulong.</param>
        /// <param name="inType">The measurement type.</param>
        public DataMeasurement(UInt64 inValue, DataType inType)
        {
            _DataType = inType;
            _DataSize = inValue;
        }

        /// <summary>
        /// This constructor takes a double value and defaults to megabyte.
        /// </summary>
        /// <param name="inValue"></param>
        public DataMeasurement(double inValue)
        {
            _DataType = DataType.Megabyte;
            _DataSize = inValue;
        }

        /// <summary>
        /// This constructor takes a value and a data measurement type.
        /// </summary>
        /// <param name="inValue">The measurement value as a double.</param>
        /// <param name="inType">The measurement type.</param>
        public DataMeasurement(double inValue, DataType inType)
        {
            _DataType = inType;
            _DataSize = inValue;
        }

        /// <summary>
        /// This constructor takes a value and a data measurement type.
        /// </summary>
        /// <param name="inValue">The measurement value as a double.</param>
        /// <param name="inType">The measurement type as a string, "GB", "Gigabyte".</param>
        public DataMeasurement(UInt64 inValue, String inType)
        {
            _DataSize = inValue;
            GetDataTypeFromString(inType);
        }

        /// <summary>
        /// This constructor takes a string representation of a data measurement.
        /// </summary>
        /// <param name="inValueAndType">The measurement value and type in a  
        /// single string such as "49 GB" or "49 GBSI" or "49 Gigabyte". There
        /// must be a space as it is used to split the value from the type, so 
        ///  "49GB" is invalid because there is no space delimeter.</param>
        public DataMeasurement(String inValueAndType)
        {
            char[] split = { ' ' };
            String[] data = inValueAndType.Split(split);
            _DataSize = Convert.ToUInt64(data[0]);
            GetDataTypeFromString(data[1]);
        }
        #endregion

        #region Properties
        public Double Size
        {
            get { return _DataSize; }
            set { _DataSize = value; }
        }

        public DataType DataSizeType
        {
            get { return _DataType; }
            set { _DataType = value; }
        }

        public ShortName DataSizeTypeShortName
        {
            get { return (ShortName)_DataType; }
            set { _DataType = (DataType)value; }
        }

        public ulong Bit
        {
            get { return (ulong)ConvertToType(DataType.Bit, false); }
            set
            {
                _DataType = DataType.Bit;
                _DataSize = value;
            }
        }

        public Double Byte
        {
            get { return ConvertToType(DataType.Byte, false); }
            set
            {
                _DataType = DataType.Byte;
                _DataSize = value;
            }
        }

        public Double KilobitSI
        {
            get { return ConvertToType(DataType.KilobitSI, false); }
            set
            {
                _DataType = DataType.KilobitSI;
                _DataSize = value;
            }
        }

        public Double Kilobit
        {
            get { return ConvertToType(DataType.Kilobit, false); }
            set
            {
                _DataType = DataType.Kilobit;
                _DataSize = value;
            }
        }
        public Double KilobyteSI
        {
            get { return ConvertToType(DataType.KilobyteSI, false); }
            set
            {
                _DataType = DataType.KilobyteSI;
                _DataSize = value;
            }
        }

        public Double Kilobyte
        {
            get { return ConvertToType(DataType.Kilobyte, false); }
            set
            {
                _DataType = DataType.Kilobit;
                _DataSize = value;
            }
        }

        public Double MegabitSI
        {
            get { return ConvertToType(DataType.MegabitSI, false); }
            set
            {
                _DataType = DataType.MegabitSI;
                _DataSize = value;
            }
        }

        public Double Megabit
        {
            get { return ConvertToType(DataType.Megabit, false); }
            set
            {
                _DataType = DataType.Megabit;
                _DataSize = value;
            }
        }
        public Double MegabyteSI
        {
            get { return ConvertToType(DataType.MegabyteSI, false); }
            set
            {
                _DataType = DataType.MegabyteSI;
                _DataSize = value;
            }
        }

        public Double Megabyte
        {
            get { return ConvertToType(DataType.Megabyte, false); }
            set
            {
                _DataType = DataType.Megabyte;
                _DataSize = value;
            }
        }

        public Double GigabitSI
        {
            get { return ConvertToType(DataType.GigabitSI, false); }
            set
            {
                _DataType = DataType.GigabitSI;
                _DataSize = value;
            }
        }

        public Double Gigabit
        {
            get { return ConvertToType(DataType.Gigabit, false); }
            set
            {
                _DataType = DataType.Gigabit;
                _DataSize = value;
            }
        }
        public Double GigabyteSI
        {
            get { return ConvertToType(DataType.GigabyteSI, false); }
            set
            {
                _DataType = DataType.GigabyteSI;
                _DataSize = value;
            }
        }

        public Double Gigabyte
        {
            get { return ConvertToType(DataType.Gigabyte, false); }
            set
            {
                _DataType = DataType.Gigabyte;
                _DataSize = value;
            }
        }

        public Double TerabitSI
        {
            get { return ConvertToType(DataType.TerabitSI, false); }
            set
            {
                _DataType = DataType.TerabitSI;
                _DataSize = value;
            }
        }

        public Double Terabit
        {
            get { return ConvertToType(DataType.Terabit, false); }
            set
            {
                _DataType = DataType.Terabit;
                _DataSize = value;
            }
        }
        public Double TerabyteSI
        {
            get { return ConvertToType(DataType.TerabyteSI, false); }
            set
            {
                _DataType = DataType.TerabyteSI;
                _DataSize = value;
            }
        }

        public Double Terabyte
        {
            get { return ConvertToType(DataType.Terabyte, false); }
            set
            {
                _DataType = DataType.Terabyte;
                _DataSize = value;
            }
        }

        public Double PetabitSI
        {
            get { return ConvertToType(DataType.PetabitSI, false); }
            set
            {
                _DataType = DataType.PetabitSI;
                _DataSize = value;
            }
        }

        public Double Petabit
        {
            get { return ConvertToType(DataType.Petabit, false); }
            set
            {
                _DataType = DataType.Petabit;
                _DataSize = value;
            }
        }
        public Double PetabyteSI
        {
            get { return ConvertToType(DataType.PetabyteSI, false); }
            set
            {
                _DataType = DataType.PetabyteSI;
                _DataSize = value;
            }
        }

        public Double Petabyte
        {
            get { return ConvertToType(DataType.Petabyte, false); }
            set
            {
                _DataType = DataType.Petabyte;
                _DataSize = value;
            }
        }

        public Double ExabitSI
        {
            get { return ConvertToType(DataType.ExabitSI, false); }
            set
            {
                _DataType = DataType.ExabitSI;
                _DataSize = value;
            }
        }

        public Double Exabit
        {
            get { return ConvertToType(DataType.Exabit, false); }
            set
            {
                _DataType = DataType.Exabit;
                _DataSize = value;
            }
        }

        public Double ExabyteSI
        {
            get { return ConvertToType(DataType.ExabyteSI, false); }
            set
            {
                _DataType = DataType.ExabyteSI;
                _DataSize = value;
            }
        }

        public Double Exabyte
        {
            get { return ConvertToType(DataType.Exabyte, false); }
            set
            {
                _DataType = DataType.Exabyte;
                _DataSize = value;
            }
        }
        #endregion

        #region Functions
        /// <summary>
        /// Writes the DataMeasurement to string, such as "1 GB" or "1024 KB".
        /// It always uses the DataSize and DataType values.
        /// </summary>
        override public string ToString()
        {
            return String.Format("{0} {1}", _DataSize, ((ShortName)_DataType).ToString());
        }

        /// <summary>
        /// Writes the DataMeasurement to string, such as "1 GB" or "1024 KB".
        /// However, it does so in the DataType that you specify.
        /// </summary>
        /// <param name="inDataType">The type to output to string. For example
        /// If the measurement is "4 Gigabyte" but you pass in Megabyte, it 
        /// will output "4096 MB".</param>
        /// <returns></returns>
        public string ToString(DataType inDataType)
        {
            Double size = ConvertToType(inDataType, false);
            return String.Format("{0} {1}", size, ((ShortName)inDataType).ToString());
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            DataMeasurement right = obj as DataMeasurement;
            if ((object)right == null)
                return false;

            return this == right;
        }

        private void GetDataTypeFromString(String inType)
        {
            if (inType.Length == 2 || inType.Length == 4)
            {   // Short name was used so get the ShortName and case it to a DataType
                // KB and Kb are not the same, so case is Important
                _DataType = (DataType)Enum.Parse(typeof(ShortName), inType, false);
            }
            else
            {   // Long name was used so get 
                // We can ignore case because Kilobit and Kilobyte are different.
                _DataType = (DataType)Enum.Parse(typeof(DataType), inType, true);
            }
        }

        /// <summary>
        /// This function converts the stored measurement from its current
        /// value to a new value using the new DataType.
        /// </summary>
        /// <param name="inNewType">The new DataType. For example If the
        /// measurement is "4 Gigabyte" but you pass in Megabyte, it will
        /// change the value to "4096 Megabyte".</param>
        /// <returns>The new DataSize for the new type is returned.</returns>
        public Double ConvertToType(DataType inNewType)
        {
            return ConvertToType(inNewType, true);
        }

        /// <summary>
        /// This function converts the stored measurement from its current
        /// value to a new value using the new DataType.
        /// </summary>
        /// <param name="inNewType">The new DataType. For example If the
        /// measurement is "4 Gigabyte" but you pass in Megabyte, it will
        /// change the value to "4096 Megabyte".</param>
        /// <param name="inChangeObjectMeasurementType">A bool value that
        /// specifies whether to change the whole object.</param>
        /// <returns>The new DataSize for the new type is returned.</returns>
        public Double ConvertToType(DataType inNewType, bool inChangeObjectMeasurementType)
        {
            double ret = 0;
            bool isSet = false;
            if (inNewType == _DataType)
            {
                ret = _DataSize;
                isSet = true;
            }
            else if (inNewType == DataType.Bit)
            {
                ret = (ulong)_DataType * _DataSize * 8;
                isSet = true;
            }
            else if (_DataType == DataType.Bit)
            {
                ret = _DataSize / 8 / (ulong)inNewType;
                isSet = true;
            }
            
            if (!isSet)
                ret = (ulong)_DataType * _DataSize / (ulong)inNewType;

            if (inChangeObjectMeasurementType)
            {
                _DataType = inNewType;
                Size = ret;
            }

            return ret;
        }
        #endregion

        #region Operator Override Functions
        public static bool operator ==(DataMeasurement left, DataMeasurement right)
        {
            if (null == (object)left && null == (object)right)
                return true;
            if (null == (object)right || null == (object)left)
                return false;

            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size == right.Size;
            }
            else
            {
                return left.Byte == right.Byte;
            }
        }

        public static bool operator !=(DataMeasurement left, DataMeasurement right)
        {
            if (null == (object)left && null == (object)right)
                return false;
            if (null == (object)right || null == (object)left)
                return true;

            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size != right.Size;
            }
            else
            {
                return left.Byte != right.Byte;
            }
        }

        public static bool operator >(DataMeasurement left, DataMeasurement right)
        {
            if (null == (object)left && null == (object)right)
                return false;
            if (null == (object)right)
                return true;
            if (null == (object)left)
                return false;

            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size > right.Size;
            }
            else
            {
                return left.Byte > right.Byte;
            }
        }

        public static bool operator >=(DataMeasurement left, DataMeasurement right)
        {
            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size >= right.Size;
            }
            else
            {
                return left.Byte >= right.Byte;
            }
        }

        public static bool operator <(DataMeasurement left, DataMeasurement right)
        {
            if (null == (object)left && null == (object)right)
                return false;
            if (null == (object)right)
                return false;
            if (null == (object)left)
                return true;
            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size < right.Size;
            }
            else
            {
                return left.Byte < right.Byte;
            }
        }

        public static bool operator <=(DataMeasurement left, DataMeasurement right)
        {
            if (left.DataSizeType == right.DataSizeType)
            {
                return left.Size <= right.Size;
            }
            else
            {
                return left.Byte <= right.Byte;
            }
        }

        public static DataMeasurement operator +(DataMeasurement left, DataMeasurement right)
        {
            return left + right.ConvertToType(left.DataSizeType, false);
        }

        public static DataMeasurement operator +(DataMeasurement left, double right)
        {
            if ((null == (object)left && null == (object)right) || null == (object)right)
                return left;
            if (null == (object)left)
                return new DataMeasurement(right);
            return new DataMeasurement(left.Size + right, left.DataSizeType);
        }

        public static DataMeasurement operator -(DataMeasurement left, DataMeasurement right)
        {
            return left - right.ConvertToType(left.DataSizeType, false);
        }

        public static DataMeasurement operator -(DataMeasurement left, double right)
        {
            if ((null == (object)left && null == (object)right) || null == (object)right)
                return left;
            if (null == (object)left)
                return new DataMeasurement(right);
            return new DataMeasurement(left.Size - right, left.DataSizeType);
        }
        #endregion

        #region Enums
        public enum ShortName : ulong
        {
            b = 0, // Bit must be handled special
            // Everything after is in bytes
            B = 1,
            KbSI = 125,
            Kb = 128,
            KBSI = 1000,
            KB = 1024,
            MbSI = 125000,
            Mb = 131072,
            MBSI = 1000000,
            MB = 1048576,
            GbSI = 125000000,
            Gb = 134217728,
            GBSI = 1000000000,
            GB = 1073741824,
            TbSI = 125000000000,
            Tb = 137438953472,
            TBSI = 1000000000000,
            TB = 1099511627776,
            PbSI = 125000000000000,
            Pb = 140737488355328,
            PBSI = 1000000000000000,
            PB = 1125899906842624,
            EbSI = 125000000000000000,
            Eb = 144115188075855872,
            EBSI = 1000000000000000000,
            EB = 1152921504606846976
        }

        public enum DataType : ulong
        {
            Bit = 0, // Bit must be handled special
            // Everything after is in bytes
            Byte = 1,
            KilobitSI = 125,
            Kilobit = 128,
            KilobyteSI = 1000,
            Kilobyte = 1024,
            MegabitSI = 125000,
            Megabit = 131072,
            MegabyteSI = 1000000,
            Megabyte = 1048576,
            GigabitSI = 125000000,
            Gigabit = 134217728,
            GigabyteSI = 1000000000,
            Gigabyte = 1073741824,
            TerabitSI = 125000000000,
            Terabit = 137438953472,
            TerabyteSI = 1000000000000,
            Terabyte = 1099511627776,
            PetabitSI = 125000000000000,
            Petabit = 140737488355328,
            PetabyteSI = 1000000000000000,
            Petabyte = 1125899906842624,
            ExabitSI = 125000000000000000,
            Exabit = 144115188075855872,
            ExabyteSI = 1000000000000000000,
            Exabyte = 1152921504606846976
        }
        #endregion
    }
}

I could probably do a better job of testing this. Here is a test class that succeeds. If you want more testing add it.

Hopefully this helps you out.

using LANDesk.Install.Common;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;

namespace LANDesk.Install.Common.Tests
{
    /// <summary>
    ///This is a test class for DataMeasurementTest and is intended
    ///to contain all DataMeasurementTest Unit Tests
    ///</summary>
    [TestClass()]
    public class DataMeasurementTest
    {
        List<DataMeasurement> sizes = new List<DataMeasurement>();

        [TestMethod()]
        public void DataMeasurementTestAdditionAndGreaterThanLessThan()
        {
            DataMeasurementEqualityTest();
            DataMeasurement OneGB = new DataMeasurement("1 GB");
            DataMeasurement OneGBinMB = new DataMeasurement("1024 MB");
            DataMeasurement twoGB = new DataMeasurement(2, DataMeasurement.DataType.Gigabyte);
            DataMeasurement twoGBadded = OneGB + OneGBinMB;
            TestEqualValues(twoGB, twoGBadded);

            foreach (DataMeasurement dm in sizes)
            {
                TestLeftIsGreater(twoGB, dm);
                TestRightIsGreater(dm, twoGB);
            }
        }

        [TestMethod()]
        public void DataMeasurementTestSubtractionAndGreaterThanLessThan()
        {
            DataMeasurementEqualityTest();
            DataMeasurement tenGB = new DataMeasurement(10, DataMeasurement.DataType.Gigabyte);
            DataMeasurement NineGB = new DataMeasurement(9, DataMeasurement.DataType.Gigabyte);
            DataMeasurement NineGBbySubtraction = tenGB - sizes[0];
            TestEqualValues(NineGB, NineGBbySubtraction);
            TestLeftIsGreater(tenGB, NineGB);
            TestLeftIsGreater(tenGB, NineGBbySubtraction);
            TestRightIsGreater(NineGB, tenGB);
            TestRightIsGreater(NineGBbySubtraction, tenGB);
        }
        
        [TestMethod()]
        public void TestConversion()
        {
            DataMeasurement dm = new DataMeasurement("4 GB");
            dm.ConvertToType(DataMeasurement.DataType.Megabyte);
            Assert.IsTrue(dm.Size == (double)4096);
            Assert.IsTrue(dm.ToString() == "4096 MB");            
        }

        [TestMethod()]
        public void DataMeasurementOtherTest()
        {
            sizes = new List<DataMeasurement>();
            int i = -1;

            // Test 1 - Check that conversion is working
            i++;
            sizes.Add(new DataMeasurement("1024 bit"));
            Assert.IsTrue(sizes[i].Bit == 1024, "Test 1, to Bit.");
            Assert.IsTrue(sizes[i].Byte == 1024 / 8, "Test 1, to Byte.");
            double expected = 1024 / 8 / 1024.0;
            Assert.IsTrue(sizes[i].Kilobyte == expected, "Test 1, " + sizes[i].Kilobyte + " should equal " + expected);

            // Test 2 - Check that conversion is working
            i++;
            sizes.Add(new DataMeasurement(4, DataMeasurement.DataType.Gigabyte));
            Assert.IsTrue(sizes[i].Bit == 34359738368, "Test 2, to bit.");
            Assert.IsTrue(sizes[i].Byte == 4294967296, "Test 2, to Byte.");
            Assert.IsTrue(sizes[i].Kilobyte == 4 * 1024 * 1024, "Test 2, to Kilobyte.");
            expected = 4.0 / 1024;
            Assert.IsTrue(sizes[i].Terabyte == expected, "Test 2, " + sizes[i].Terabyte + " should equal " + expected);

            // Test 3 - Comparisons
            Assert.IsTrue(sizes[i - 1] < sizes[i], "Test 3, " + sizes[i - 1] + " is less than " + sizes[i]);
            Assert.IsTrue(sizes[i - 1] <= sizes[i], "Test 3, " + sizes[i - 1] + " is less than or equal to " + sizes[i]);
            Assert.IsFalse(sizes[i - 1] > sizes[i], "Test 3, " + sizes[i - 1] + " is greater than " + sizes[i]);
            Assert.IsFalse(sizes[i - 1] >= sizes[i], "Test 3, " + sizes[i - 1] + " is greater than or equal to " + sizes[i]);
            Assert.IsFalse(sizes[i - 1] == sizes[i], "Test 3, " + sizes[i - 1] + " is equal to " + sizes[i]);
            Assert.IsTrue(sizes[i - 1] != sizes[i], "Test 3, " + sizes[i - 1] + " is not equal to " + sizes[i]);
        }

        public void DataMeasurementEqualityTest()
        {
            DataMeasurement last = null;
            DataMeasurement OneGB = new DataMeasurement("1 GB");
            foreach (DataMeasurement.DataType dt in Enum.GetValues(typeof(DataMeasurement.DataType)))
            {
                DataMeasurement next = new DataMeasurement(OneGB.ConvertToType(dt, false), dt);
                sizes.Add(next);
                if (last != null)
                    TestEqualValues(next, last);
                last = next;
            }
        }

        private void TestEqualValues(DataMeasurement left, DataMeasurement right)
        {
            Assert.IsFalse(left > right);
            Assert.IsFalse(left < right);
            Assert.IsTrue(left >= right);
            Assert.IsTrue(left <= right);
            Assert.IsTrue(left == right);
            Assert.IsFalse(left != right);
            Assert.IsTrue(left.Equals(right));
        }

        private void TestLeftIsGreater(DataMeasurement left, DataMeasurement right)
        {
            Assert.IsTrue(left > right);
            Assert.IsFalse(left < right);
            Assert.IsTrue(left >= right);
            Assert.IsFalse(left <= right);
            Assert.IsFalse(left == right);
            Assert.IsTrue(left != right);
        }

        private void TestRightIsGreater(DataMeasurement left, DataMeasurement right)
        {
            Assert.IsFalse(left > right);
            Assert.IsTrue(left < right);
            Assert.IsFalse(left >= right);
            Assert.IsTrue(left <= right);
            Assert.IsFalse(left == right);
            Assert.IsTrue(left != right);
        }
    }
}

I hope this object helps save you time.

How to read the 64 bit registry from a 32 bit application or vice versa

I found out that I needed to read the 64 bit registry from a 32 bit app today.

Why you might ask?

Well, I need to get the RegisteredOrganization value from HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion and unfortunately Microsoft has a bug where the WOW6432 version of this key always says Microsoft, so a 32 bit application would always return Microsoft as the RegisteredOrganization, regardless of what the user entered when they installed the OS. This is hardly desired.

Note: This is also why all Visual Studio projects created in Windows 7 64 bit have Microsoft in the project’s Assembly Information. Change the WOW6432 version of the RegisteredOrganization and you fix this Visual Studio issue.
Well, turns out C# doesn’t have functionality until .NET 4, so prior to .NET 4, to choose the 64 bit hive when running a 32 bit app, so we have to do use a DLLImport and use RegOpenKeyEx, RegCloseKey, and RegQueryValueEx.

I don’t have this well commented, and it is not very newbie proof, but here are three different ways to do this. Hopefully you can understand one or more of these.

Example 1 – .NET 4 Example

Here is how to do this in .NET 4.

using Microsoft.Win32;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = string.Empty;
            string value32 = string.Empty;

            RegistryKey localKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);
            localKey = localKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
            if (localKey != null)
            {
                value64 = localKey.GetValue("RegisteredOrganization").ToString();
            }
            RegistryKey localKey32 = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry32);
            localKey32 = localKey32.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
            if (localKey32 != null)
            {
                value32 = localKey32.GetValue("RegisteredOrganization").ToString();
            }
        }
    }
}

.NET 3.5 SP1 and Prior

This can also be done in .NET 3.5 and prior but it is not easy.
We have to do use a DLLImport and use RegOpenKeyEx, RegCloseKey, and RegQueryValueEx. Here are some examples.

Example 1 – A console application to read the 64 bit registry from a 32 bit application or vice versa

Here is the code in a simple one file project:
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
            Console.WriteLine(value64);
            string value32 = GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
            Console.WriteLine(value32);
        }

        public enum RegSAM
        {
            QueryValue = 0x0001,
            SetValue = 0x0002,
            CreateSubKey = 0x0004,
            EnumerateSubKeys = 0x0008,
            Notify = 0x0010,
            CreateLink = 0x0020,
            WOW64_32Key = 0x0200,
            WOW64_64Key = 0x0100,
            WOW64_Res = 0x0300,
            Read = 0x00020019,
            Write = 0x00020006,
            Execute = 0x00020019,
            AllAccess = 0x000f003f
        }

        public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
        public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);

        #region Member Variables
        #region Read 64bit Reg from 32bit app
        [DllImport("Advapi32.dll")]
        static extern uint RegOpenKeyEx(
            UIntPtr hKey,
            string lpSubKey,
            uint ulOptions,
            int samDesired,
            out int phkResult);

        [DllImport("Advapi32.dll")]
        static extern uint RegCloseKey(int hKey);

        [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
        public static extern int RegQueryValueEx(
            int hKey, string lpValueName,
            int lpReserved,
            ref uint lpType,
            System.Text.StringBuilder lpData,
            ref uint lpcbData);
        #endregion
        #endregion

        #region Functions
        static public string GetRegKey64(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName);
        }

        static public string GetRegKey32(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName);
        }

        static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                uint lpType = 0;
                uint lpcbData = 1024;
                StringBuilder AgeBuffer = new StringBuilder(1024);
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
                string Age = AgeBuffer.ToString();
                return Age;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }
        #endregion
    }
}

Example 2 – A static class to read the 64 bit registry from a 32 bit application or vice versa

Or if you want this in its own separate class, here is a static class you can add to your project.
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Read64bitRegistryFrom32bitApp
{
    public enum RegSAM
    {
        QueryValue = 0x0001,
        SetValue = 0x0002,
        CreateSubKey = 0x0004,
        EnumerateSubKeys = 0x0008,
        Notify = 0x0010,
        CreateLink = 0x0020,
        WOW64_32Key = 0x0200,
        WOW64_64Key = 0x0100,
        WOW64_Res = 0x0300,
        Read = 0x00020019,
        Write = 0x00020006,
        Execute = 0x00020019,
        AllAccess = 0x000f003f
    }

    public static class RegHive
    {
        public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
        public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
    }

    public static class RegistryWOW6432
    {
        #region Member Variables
        #region Read 64bit Reg from 32bit app
        [DllImport("Advapi32.dll")]
        static extern uint RegOpenKeyEx(
            UIntPtr hKey,
            string lpSubKey,
            uint ulOptions,
            int samDesired,
            out int phkResult);

        [DllImport("Advapi32.dll")]
        static extern uint RegCloseKey(int hKey);

        [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
        public static extern int RegQueryValueEx(
            int hKey, string lpValueName,
            int lpReserved,
            ref uint lpType,
            System.Text.StringBuilder lpData,
            ref uint lpcbData);
        #endregion
        #endregion

        #region Functions
        static public string GetRegKey64(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName);
        }

        static public string GetRegKey32(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName);
        }

        static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                uint lpType = 0;
                uint lpcbData = 1024;
                StringBuilder AgeBuffer = new StringBuilder(1024);
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
                string Age = AgeBuffer.ToString();
                return Age;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }
        #endregion

        #region Enums
        #endregion
    }
}
Here is an example of using this class.
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
            string value32 = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
        }
    }
}

Example 3 – Adding extension methods to the managed RegistryKey object that read the 64 bit registry from a 32 bit application or vice versa

You know what else is a cool idea? Making it an extension class to the normal managed registry C# code. So you can create a regular managed RegistryKey and then just call an extension function off it.
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32;

namespace Read64bitRegistryFrom32bitApp
{
    /// <summary>
    /// An extension class to allow a registry key to allow it to get the
    /// registry in the 32 bit (Wow6432Node) or 64 bit regular registry key
    /// </summary>
    public static class RegistryWOW6432
    {
        #region Member Variables
        #region Read 64bit Reg from 32bit app
        public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
        public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);

        [DllImport("Advapi32.dll")]
        static extern uint RegOpenKeyEx(
            UIntPtr hKey,
            string lpSubKey,
            uint ulOptions,
            int samDesired,
            out int phkResult);

        [DllImport("Advapi32.dll")]
        static extern uint RegCloseKey(int hKey);

        [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
        public static extern int RegQueryValueEx(
            int hKey, 
            string lpValueName,
            int lpReserved,
            ref RegistryValueKind lpType,
            StringBuilder lpData,
            ref uint lpcbData);

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegQueryValueEx")]
        private static extern int RegQueryValueEx(
            int hKey,
            string lpValueName,
            int lpReserved,
            ref RegistryValueKind lpType,
            [Out] byte[] lpData,
            ref uint lpcbData);
        #endregion
        #endregion

        #region Functions
        public static string GetRegKey64(this RegistryKey inKey, String inPropertyName)
        {
            string strKey = inKey.ToString();
            string regHive = strKey.Split('\\')[0];
            string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
            return GetRegKey64(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_64Key, inPropertyName);
        }

        public static string GetRegKey32(this RegistryKey inKey, String inPropertyName)
        {
            string strKey = inKey.ToString();
            string regHive = strKey.Split('\\')[0];
            string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
            return GetRegKey64(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_32Key, inPropertyName);
        }

        public static byte[] GetRegKey64AsByteArray(this RegistryKey inKey, String inPropertyName)
        {
            string strKey = inKey.ToString();
            string regHive = strKey.Split('\\')[0];
            string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
            return GetRegKey64AsByteArray(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_64Key, inPropertyName);
        }

        public static byte[] GetRegKey32AsByteArray(this RegistryKey inKey, String inPropertyName)
        {
            string strKey = inKey.ToString();
            string regHive = strKey.Split('\\')[0];
            string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
            return GetRegKey64AsByteArray(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_32Key, inPropertyName);
        }

        private static UIntPtr GetRegHiveFromString(string inString)
        {
            if (inString == "HKEY_LOCAL_MACHINE")
                return HKEY_LOCAL_MACHINE;
            if (inString == "HKEY_CURRENT_USER")
                return HKEY_CURRENT_USER;
            return UIntPtr.Zero;
        }

        static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                RegistryValueKind lpType = 0;
                uint lpcbData = 1024;
                StringBuilder strBuffer = new StringBuilder(1024);
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, strBuffer, ref lpcbData);
                string value = strBuffer.ToString();
                return value;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }

        static public byte[] GetRegKey64AsByteArray(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                RegistryValueKind lpType = 0;
                uint lpcbData = 2048;

                // Just make a big buffer the first time
                byte[] byteBuffer = new byte[1000];
                // The first time, get the real size
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, byteBuffer, ref lpcbData);
                // Now create a correctly sized buffer
                byteBuffer = new byte[lpcbData];
                // now get the real value
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, byteBuffer, ref lpcbData);

                return byteBuffer;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }
        #endregion

        #region Enums
        public enum RegSAM
        {
            QueryValue = 0x0001,
            SetValue = 0x0002,
            CreateSubKey = 0x0004,
            EnumerateSubKeys = 0x0008,
            Notify = 0x0010,
            CreateLink = 0x0020,
            WOW64_32Key = 0x0200,
            WOW64_64Key = 0x0100,
            WOW64_Res = 0x0300,
            Read = 0x00020019,
            Write = 0x00020006,
            Execute = 0x00020019,
            AllAccess = 0x000f003f
        }
        #endregion
    }
}
Here is an example of using these extension functions.
using Microsoft.Win32;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = string.Empty;
            string value32 = string.Empty;

            byte[] byteValue64 = new byte[1024];
            byte[] byteValue32 = new byte[1024];
            RegistryKey localKey = Registry.LocalMachine;
            
            localKey = localKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
            if (localKey != null)
            {
                value32 = localKey.GetRegKey32("RegisteredOrganization");
                value64 = localKey.GetRegKey64("RegisteredOrganization");

                // byteValue32 = localKey.GetRegKey32AsByteArray("DigitalProductId"); // Key doesn't exist by default in 32 bit
                byteValue64 = localKey.GetRegKey64AsByteArray("DigitalProductId");
            }
        }
    }
}
If anything is confusing please comment.
Resources:
  • RegOpenKeyEx Function – http://msdn.microsoft.com/en-us/library/ms724897%28v=VS.85%29.aspx
  • RegQueryValueEx Function – http://msdn.microsoft.com/en-us/library/ms724911%28VS.85%29.aspx
  • http://www.pinvoke.net/default.aspx/advapi32/RegQueryValueEx.html
  • http://www.pinvoke.net/default.aspx/advapi32/RegOpenKeyEx.html
  • http://www.pinvoke.net/default.aspx/advapi32/RegCreateKeyEx.html
  • http://www.pinvoke.net/default.aspx/advapi32/RegCloseKey.html
  • http://stackoverflow.com/questions/1470770/accessing-registry-using-net
  • http://connect.microsoft.com/VisualStudio/feedback/details/400597/registeredorganization-reg-key-on-x64-vista-7

Copyright ® Rhyous.com – Linking to this post is allowed without permission and as many as ten lines of this page can be used along with this link. Any other use of this page is allowed only by permission of Rhyous.com.

C# Random Password Generator

BSD#

I needed to generate a random password in C# and I wanted to do it right.

I consulted a security expert and he mentioned that I should use a seed created with RNGCryptoServiceProvider so I did a search and quickly found this blog entry that had a good start.
http://eyeung003.blogspot.com/2010/09/c-random-password-generator.html

However, I needed three enhancements to this code.

  1. Store the password as a SecureString.
  2. Make upper case and lower case characters separate options.
  3. Guarantee that each character option would be used.

So I added these enhancements. Here are some notes about the enhancements:

  • SecureString – Since most password code requires strings instead of secure strings, even code such as a SQL connection strings, I cannot fault the original writer for leaving the password as a string. However, passwords should be stored as SecureString objects as much as possible. With my enhancements, it still flips back and forth between secure string and string, but hopefully is a SecureString as often as possible.
  • I include the ability to convert the SecureString to a string, because of the issue mentions in the previous bullet point.
  • I separated the character options. I also added back the characters that were listed as confusing. If someone thinks these are confusing, use a font where they are not confusing or remove them again.
  • Using all options – I guarantee that each option is used. The first characters in the password are chosen, one from each option, in a random order. I still didn’t like that, I created a scramble but in order to create the scramble, I had pull the password out as a string to get each character to scramble.
  • I also added some exception objects to make exceptions clear if there are any.
  • I also tested this on C# (Mono) on FreeBSD and it works.

Ok, here is the new version that includes my enhancements to the original code.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;

namespace System.Security
{
    public enum CharacterTypes : byte
    {
        Alpha_Lower = 1,
        Alpha_Upper = 2,
        Alpha_Upper_and_Lower = 3,
        Digit = 4,
        AlphaLowerNumeric = Digit + Alpha_Lower,        //  5 (4+1)
        AlphaUpperNumeric = Digit + Alpha_Upper,        //  6 (4+2)
        AlphaNumeric = Alpha_Upper_and_Lower + Digit,   //  7 (4+3)
        Special = 8,
        // You could add more character types here such as Alpha_Lower  + Special, but why?
        AlphaNumericSpecial = AlphaNumeric + Special    // 15 (8+7)
    }

    public class RandomPasswordGenerator
    {
        // Define default password length.
        private static int DEFAULT_PASSWORD_LENGTH = 16;

        private static PasswordOption AlphaLC = new PasswordOption() { Characters = "abcdefghijklmnopqrstuvwxyz", Count = 0 };
        private static PasswordOption AlphaUC = new PasswordOption() { Characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", Count = 0 };
        private static PasswordOption Digits = new PasswordOption() { Characters = "0123456789", Count = 0 };
        private static PasswordOption Specials = new PasswordOption() { Characters = "!@#$%^&*()~<>?", Count = 0 };

        #region Overloads

        /// <summary>
        /// Generates a random password with the default length.
        /// </summary>
        /// <returns>Randomly generated password.</returns>
        public static SecureString Generate()
        {
            return Generate(DEFAULT_PASSWORD_LENGTH,
                            CharacterTypes.AlphaNumericSpecial);
        }

        /// <summary>
        /// Generates a random password with the default length.
        /// </summary>
        /// <returns>Randomly generated password.</returns>
        public static SecureString Generate(CharacterTypes option)
        {
            return Generate(DEFAULT_PASSWORD_LENGTH, option);
        }

        /// <summary>
        /// Generates a random password with the specified length.
        /// </summary>
        /// <returns>Randomly generated password.</returns>
        public static SecureString Generate(int passwordLength)
        {
            return Generate(passwordLength,
                            CharacterTypes.AlphaNumericSpecial);
        }

        /// <summary>
        /// Generates a random password.
        /// </summary>
        /// <returns>Randomly generated password.</returns>
        public static SecureString Generate(int passwordLength,
                                      CharacterTypes option)
        {
            return GeneratePassword(passwordLength, option);
        }

        #endregion

        /// <summary>
        /// Generates the password.
        /// </summary>
        /// <returns></returns>
        private static SecureString GeneratePassword(int passwordLength, CharacterTypes option)
        {
            // Password length must at lest be 1 character long
            if (passwordLength < 1)
                throw new InvalidPasswordLengthException();

            // Character type must be a valid CharacterType
            if (option < CharacterTypes.Alpha_Lower || option > CharacterTypes.AlphaNumericSpecial)
                throw new InvalidPasswordCharacterTypeException();

            PasswordOptions passwordOptions = GetCharacters(option);

            // Make sure the password is long enough.
            // For example CharacterTypes.AlphaNumericSpecial
            // requires at least 4 characters: 1 upper, 1 lower, 1 digit, 1 special
            if (passwordLength < passwordOptions.Count)
                throw new InvalidPasswordLengthException();

            SecureString securePassword = new SecureString();
            string passwordChars = String.Empty;

            foreach (PasswordOption po in passwordOptions)
            {
                passwordChars += po.Characters;
            }

            if (string.IsNullOrEmpty(passwordChars))
                return null;

            var random = RandomSeedGenerator.GetRandom();

            for (int i = 0; i < passwordLength; i++)
            {
                int index;
                char passwordChar;
                if (!passwordOptions.AllOptionsAreUsed)
                {
                    PasswordOption po = passwordOptions.GetUnusedOption();
                    index = random.Next(po.Characters.Length);
                    passwordChar = po.Characters&#91;index&#93;;
                }
                else
                {
                    index = random.Next(passwordChars.Length);
                    passwordChar = passwordChars&#91;index&#93;;
                }

                securePassword.AppendChar(passwordChar);
            }

            return securePassword;
        }

        private int GetOptionsUsed()
        {
            int ret = 0;
            foreach (CharacterTypes option in Enum.GetValues(typeof(CharacterTypes)))
            {

            }
            return ret;
        }

        /// <summary>
        /// Gets the characters selected by the option
        /// </summary>
        /// <returns></returns>
        private static PasswordOptions GetCharacters(CharacterTypes option)
        {
            PasswordOptions list = new PasswordOptions();
            switch (option)
            {
                case CharacterTypes.Alpha_Lower:
                    list.Add(AlphaLC);
                    break;
                case CharacterTypes.Alpha_Upper:
                    list.Add(AlphaUC);
                    break;
                case CharacterTypes.Alpha_Upper_and_Lower:
                    list.Add(AlphaLC);
                    list.Add(AlphaUC);
                    break;
                case CharacterTypes.Digit:
                    list.Add(Digits);
                    break;
                case CharacterTypes.AlphaNumeric:
                    list.Add(AlphaLC);
                    list.Add(AlphaUC);
                    list.Add(Digits);
                    break;
                case CharacterTypes.Special:
                    list.Add(Specials);
                    break;
                case CharacterTypes.AlphaNumericSpecial:
                    list.Add(AlphaLC);
                    list.Add(AlphaUC);
                    list.Add(Digits);
                    list.Add(Specials);
                    break;
                default:
                    break;
            }
            return list;
        }
    }

    public static class RandomSeedGenerator
    {
        /// <summary>
        /// Gets a random object with a real random seed
        /// </summary>
        /// <returns></returns>
        public static Random GetRandom()
        {
            // Use a 4-byte array to fill it with random bytes and convert it then
            // to an integer value.
            byte[] randomBytes = new byte[4];

            // Generate 4 random bytes.
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            rng.GetBytes(randomBytes);

            // Convert 4 bytes into a 32-bit integer value.
            int seed = (randomBytes[0] & 0x7f) << 24 |
                        randomBytes&#91;1&#93; << 16 |
                        randomBytes&#91;2&#93; << 8 |
                        randomBytes&#91;3&#93;;

            // Now, this is real randomization.
            return new Random(seed);
        }
    }

    public class PasswordOption
    {
        public int Count { get; set; }
        public String Characters { get; set; }
    }

    public class PasswordOptions : List<PasswordOption>
    {
        public bool AllOptionsAreUsed
        {
            get
            {
                foreach (PasswordOption po in this)
                {
                    if (po.Count < 1)
                        return false;
                }
                return true;
            }
        }

        public PasswordOption GetUnusedOption()
        {
            PasswordOptions options = new PasswordOptions();
            foreach (PasswordOption po in this)
            {
                if (po.Count < 1)
                    options.Add(po);
            }
            if (options.Count < 1)
                return null;

            var random = RandomSeedGenerator.GetRandom();
            int optionIndex = random.Next(options.Count);
            return options&#91;optionIndex&#93;;
        }
    }

    public class InvalidPasswordLengthException : ArgumentException { }
    public class InvalidPasswordCharacterTypeException : ArgumentException { }

    public static class SecureStringExtender
    {
        public static string ConvertToPlainTextString(this SecureString securePassword)
        {
            if (securePassword == null)
                throw new ArgumentNullException("securePassword");

            IntPtr unmanagedString = IntPtr.Zero;
            try
            {
                unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
                return Marshal.PtrToStringUni(unmanagedString);
            }
            finally
            {
                Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
            }
        }

        public static SecureString Scramble(this SecureString securePassword)
        {
            SecureString retSS = securePassword;
            Random random = RandomSeedGenerator.GetRandom();
            int moves = random.Next(securePassword.Length, securePassword.Length * 2);
            for (int i = 0; i < moves; i++)
            {
                int origIndex = random.Next(securePassword.Length);
                int newIndex = random.Next(securePassword.Length);
                char c = retSS.GetAt(origIndex);
                retSS.InsertAt(newIndex, c);
            }
            return retSS;
        }

        public static Char GetAt(this SecureString securePassword, int index)
        {
            if (securePassword.Length < index)
                throw new ArgumentException("The index parameter must not be greater than the string's length.");
            if (index < 0)
                throw new ArgumentException("The index must be 0 or greater.");
            return securePassword.ConvertToPlainTextString().Substring(index, 1).ToCharArray()&#91;0&#93;;
        }
    }
}
&#91;/sourcecode&#93;

Now if you want to make a simple command line executable that uses the code above, just create a new console project and call this line:

<code>Console.WriteLine(RandomPasswordGenerator.Generate().ConvertToPlainTextString());</code>

I added more code to handle command line parameters.

[sourcecode language="csharp"]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;

namespace ConsoleApplication2
{
    class Program
    {
        private static int PasswordLength;
        private static String Characters;

        static void Main(string[] args)
        {
            if (args.Length > 2)
            {
                ShowArgs();
                return;
            }

            if (args.Length > 0)
            {
                foreach (char c in args[0])
                {
                    if (char.IsDigit(c))
                    {
                        ShowArgs();
                        return;
                    }
                }
                PasswordLength = Convert.ToInt32(args[0]);
            }

            if (args.Length == 2)
                Characters = args[1];

            Console.WriteLine(RandomPasswordGenerator.Generate().ConvertToPlainTextString());
        }

        private static void ShowArgs()
        {
            String fullExeNameAndPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
            String ExeName = System.IO.Path.GetFileName(fullExeNameAndPath);

            Console.WriteLine("Usage: " + ExeName + " [int] [string]");
            Console.WriteLine("[int] - The length of the password.  By default it is 11.");
            Console.WriteLine("[string] - The characters to use for the password.  By default it is alphanumeric case sensitive.");
        }
}

Hope you find this helpful. If you find flaws, please comment!