Rhyous

December 10, 2010

C# (Mono) on FreeBSD

Filed under: C# (C-Sharp),Mono,Mono Develop,Visual Studio — J. Abram barneck @ 6:21 am

C# (Mono) on FreeBSD

Well, if you have read my blog at all, you will realize that I have a developer job writing in C# on Windows, but it is my personal hobby to use FreeBSD.

I am very excited about Mono.I love the C# language. I also love FreeBSD.

I am going to go ahead and say something bold. Few people know realize this yet, but the ability to code in C# on open source platforms is going to be the single most important feature in the coming years. It will eventually be a standard library that will exist or be one of the first items installed on every system.

For more information:

http://www.mono-project.com/Mono:FreeBSD
Packaging for Mono and related applications on FreeBSD (http://www.freebsd.org) is handled by the BSD# Project. The purpose of this project is to maintain the existing Mono/C# ports in the FreeBSD ports tree, port new applications, and work on resolving FreeBSD specific issues with Mono. BSD# is entirely user supported and is not an official FreeBSD or Mono project.

For Licensing information:

http://www.mono-project.com/Licensing

Installing Mono

Mono is a port and as always a port is easy to install on FreeBSD.

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

Compiling Hello World in Mono

The mono compiler is gmcs. It is simple to compile C# code.

  1. Create a new file called hw.cs.  C# class files end in .cs.
  2. Add this text to the file:
    using System;
    
    namespace HelloWord
    {
        class HelloWord
        {
            static void Main(string[] args)
            {
                System.Console.WriteLine("Hello World");
            }
        }
    }
    
  3. Save the file.
  4. Compile the code to create an hw.exe program.
    # gmcs hw.cs

Running a Mono Program

Mono programs must be run using the “mono” command.

# mono hw.exe
Hello World

A Mono IDE: Mono Develop

There is an IDE for Mono called Mono Develop. Mono Develop is a port and as always a port is easy to install on FreeBSD.

#
#
cd /usr/ports/devel/monodevelop
make BATCH=yes install

The Mono Develop port integrated with KDE to add itself to the KDE menu under Applications | Development | MonoDevelop. So you can run it from there.

This IDE allows you to create C# solutions. It is possible to

Is It Really Cross Platform

C# and Mono are supposed to be cross platform. So I can write it in Windows using Visual Studio or I can write in FreeBSD using Mono Develop and either way it should run on both Windows and FreeBSD and any other platform that supports mono.

So here are the results of my quick tests:

Test 1 – Does the Hello World app run in Windows.

Yes.  I copied the file to a Windows 7 64 bit box and ran it.  It worked.

Test 2 – Does a GTK# 2.0 Project run in Windows

No. I created a GTK# 2.0 project on FreeBSD in Mono Develop, and didn’t add anything to it, I just compiled it. I copied the file to windows and ran it. However, it still crashed.

Test 3 – Does a Windows Form Application compiled in Visual Studio 2010 in Window 7 run on FreeBSD

Not at first. I created a basic Windows Form application, and didn’t add anything to it, I just compiled it. I copied it to FreeBSD and ran it.  It crashed. However, by default .NET 4.0 is used.

Yes, if compiled with .NET 3.5 or earlier. I changed the project to use .NET 3.5 and tried again.

Test 4 – Does a Windows Presentation Foundation project compiled in Visual Studio 2010 in Window 7 run on FreeBSD

No. There is PresentationFramework assembly so the application crashes immediately. I tried multiple .NET versions.

Note: I didn’t really test much more than the basics. I just created new projects, left them as is and tried them. It would be interesting to see a more fully developed application tested and working on both platform and to know what issues were encountered in doing this.

No WPF

Unfortunately there is no WPF and no plans for it. Of course, WPF stand for Windows Presentation Foundation, and so the who “Windows” part of that might need to be changed to something like XPF, Xorg Presentation foundation.

However since there is Moonlight, which is to Silverlight as Mono is to C# and .NET, and Silverlight is a subset of WPF, I have to assume that WPF will arrive in mono eventually, even if it is by way of Moonlight first.

November 29, 2010

WPF databinding to methods encapulated in an ICommand

Filed under: C# (C-Sharp),Visual Studio,WPF — J. Abram barneck @ 11:07 pm
Tags: , ,

Databinding in WPF allows binding the Command property to methods encapulated in an ICommand. By creating an ICommand object to hold an event function, the Command value can bind to the event function as an ICommand.

The goal of Model-View-ViewModel is to have zero code in the code behind of a WPF Control Instead, everything the WPF Control does happens using databinding.

While this article will show you how to do this, you be left a little fuzzy as to understanding of the implementation. It may take some time and research to fully understand everything this is doing. Understand that methods can be objects, and this is a process to turn a method object into an ICommand so it can be using in WPF for databinding.

Preparation and Prereqs

You should have Visual Studio 2008/2010.

In Visual Studio, create a new WPF Application project and give it a name.

Step 1 – Creating an new class that inherits from ICommand

  1. In your new project in Visual Studio, add a new class called RelayCommand.
    Note: It can be named anything, but since that is the name used by Microsoft when discussing MVVM, I will use the same name.
  2. Change the using statements to implement the following : System, System.Diagnostic, System.Windows.Input
  3. Make the new RelayComand class public.
  4. Make the new RelayCommand class implement ICommand.
  5. using System;
    using System.Windows.Input;
    
    namespace WpfDataBindingToICommand
    {
        public class RelayCommand : ICommand
        {
            #region Constructors
            public RelayCommand()
            {
            }
            #endregion
        }
    }
    
  6. Right-click on the ICommand text and choose Implement Interface | Implement Interface. This adds the following code to the bottom of your class.
            #region ICommand Members
    
            public bool CanExecute(object parameter)
            {
                throw new NotImplementedException();
            }
    
            public event EventHandler CanExecuteChanged;
    
            public void Execute(object parameter)
            {
                throw new NotImplementedException();
            }
    
            #endregion
    
  7. Create two member variables or fields that we will use to hep use inside the ICommand interface functions.
    1. Action<Object>
    2. Predicate<Object>

            #region Member Variables
            readonly Action<object> _ActionToExecute;
            readonly Predicate<object> __ActionCanExecute;
            #endregion
    
  8. Implement the CanExecute(object parameter) function.
            public bool CanExecute(object parameter)
            {
                return __ActionCanExecute== null ? true : __ActionCanExecute(parameter);
            }
    
  9. Implement the EventHandler CanExecuteChanged. In doing this the MVVM experts used the CommandManager, which might be worth reading about.
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
    
  10. Implement the Execute(object parameter) function.
            public void Execute(object parameter)
            {
                _ActionToExecute(parameter);
            }
    
  11. Create constructors that allow us to initialize the object by passing in the Action

The final class looks as follows:

using System;
using System.Windows.Input;

namespace WpfDataBindingToICommand
{
    /// <summary>
    /// This RelayCommand object is used to encapsulate function logic into an oject that inherits ICommand.
    /// </summary>
    public class RelayCommand : ICommand
    {
        #region Member Variables
        readonly Action<object> _ActionToExecute;
        readonly Predicate<object> _ActionCanExecute;
        #endregion

        #region Constructors
        /// <summary>
        /// This creates a new RelayCommand.
        /// </summary>
        /// <param name="inActionToExecute">This is the logic of the actin to execute. This objects is usually a method that returns void.</param>
        public RelayCommand(Action<object> inActionToExecute)
            : this(inActionToExecute, null)
        {
        }

        /// <summary>
        /// This creates a new RelayCommand.
        /// </summary>
        /// <param name="inActionToExecute">This is the logic of the actin to execute. This objects is usually a method that returns void.</param>
        /// <param name="inActionCanExecute">This is the logic for whether the action can execute.</param>
        public RelayCommand(Action<object> inActionToExecute, Predicate<Object> inActionCanExecute)
        {
            if (inActionToExecute == null)
                throw new ArgumentNullException("execute");

            _ActionToExecute = inActionToExecute;
            _ActionCanExecute = inActionCanExecute;
        }
        #endregion

        #region ICommand Members
        public bool CanExecute(object parameter)
        {
            return _ActionCanExecute == null ? true : _ActionCanExecute(parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            _ActionToExecute(parameter);
        }
        #endregion
    }
}

Step 2 – Creating a ViewModelBase abstract base class

This object is used to create common logic for all objects that will be using in Binding. This object will implement INotifyPropertyChanged so it only has to be implemented once.

  1. Create a new class named ViewModelBase.
  2. Change the using statements to implement the following : System, System.CompenentModel
  3. Make the new ViewModelBase class public and abstract.
  4. Make the new ViewModelBase class implement INotifyPropertyChanged.
  5. Make the constructor protected.
    
    
  6. Right-click on the INotifyPropertyChanged text and choose Implement Interface | Implement Interface. This adds the following code to the bottom of your class. Yes, it is just a one line event handler object.
            #region INotifyPropertyChanged Members
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            #endregion
    
  7. Create a function called NotifyPropertyChanged to help implement the object. Make sure it has a permission level of at least protected.
            #region Functions
            protected void NotifyPropertyChanged(String inPropertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(inPropertyName));
                }
            }
            #endregion
    
  8. Make the new ViewModelBase class public and abstract.

The final object looks as follows:

using System;
using System.ComponentModel;

namespace WpfDataBindingToICommand
{
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        #region Constructors
        public ViewModelBase()
        {
        }
        #endregion

        #region Functions
        protected void NotifyPropertyChanged(String inPropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(inPropertyName));
            }
        }
        #endregion

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }
}

Note: You may also want to implement IDisposable.

Step 3 – Creating the ViewModel and Model

We are going to have the ViewModel and business in the same object for this example, but sometimes you will have a separate ViewModel object that represents your data/business.

  1. Create a new class named SampleViewModel.
  2. Change the using statements to implement the following : System, System.Windows, System.Windows.Input
  3. Make the new SampleViewModel class public.
  4. Make the new SampleViewModel class inherit ViewModelBase.
    using System;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfDataBindingToICommand
    {
        public class SampleViewModel : ViewModelBase
        {
            #region Constructors
            public SampleViewModel()
            {
            }
            #endregion
        }
    }
    
  5. Create a string field and property and make sure to have the property’s set function call NotifyPropertyChanged.
        public class SampleViewModel : ViewModelBase
        {
            string _Message = "Hello. This is the default message.";
    
            public string Message
            {
                get { return _Message; }
                set
                {
                    _Message = value;
                    NotifyPropertyChanged("Message");
                }
            }
        }
    
  6. Create a simple function to show a MessageBox.
            public void ShowMessage(String inMessage)
            {
                MessageBox.Show(inMessage);
            }
    
  7. Create an ICommand field and property. Make sure the property returns a RelayCommand object that references the ShowMessage method. This is a read only property.
            RelayCommand _ShowMessageCommand;
    
            public ICommand ShowMessageCommand
            {
                get
                {
                    if (_ShowMessageCommand == null)
                    {
                        _ShowMessageCommand = new RelayCommand(param => this.ShowMessage(Message));
                    }
                    return _ShowMessageCommand;
                }
            }
    

    Note: Notice that in order to pass the ShowMessage method, instead of the return value of the function, into the RelayCommand objectwhich is void anyway, the param => syntax is used.

The final SampleViewModel looks as follows.

using System;
using System.Windows;
using System.Windows.Input;

namespace WpfDataBindingToICommand
{
    public class SampleViewModel : ViewModelBase
    {
        #region Member Variables
        string _Message = "Hello. This is the default message.";
        RelayCommand _ShowMessageCommand;
        #endregion

        #region Constructors
        public SampleViewModel()
        {
        }
        #endregion

        #region Properties
        public string Message
        {
            get { return _Message; }
            set
            {
                _Message = value;
                NotifyPropertyChanged("Message");
            }
        }

        public ICommand ShowMessageCommand
        {
            get
            {
                if (_ShowMessageCommand == null)
                {
                    _ShowMessageCommand = new RelayCommand(param => this.ShowMessage(Message));
                }
                return _ShowMessageCommand;
            }
        }
        #endregion

        #region Functions
        public void ShowMessage(String inMessage)
        {
            MessageBox.Show(inMessage);
        }
        #endregion

        #region Enums
        #endregion
    }
}

Step 4 – Using Databinding to Bind an ICommand to a WPF Control

Ok, so lets modify the XAML of the default MainWindow.xaml code that was auto-created with the project. We will keep it simple and have a text box and a button to pop up the message.

Note: For this simple program all the work we did to implement databinding for binding events to methods seems like an absurd burden. However, for large applications, this design will lead to a better way to manage your code. It will decouple your GUI from your code, making future refactoring of the GUI much easier. This also improves the ability to make minor changes to the GUI. It also makes the code more sustainable and more easily tested. Unit tests are more effective as the GUI layer is not required and most functions are in the business layer.

  1. Create a reference to the current namespace.
    <Window x:Class="WpfDataBindingToICommand.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfDataBindingToICommand"
            Title="MainWindow" Height="350" Width="525">
    
  2. Add a SampleViewModel StaticResource.
        <Window.Resources>
            <local:SampleViewModel x:Key="Sample" />
        </Window.Resources>
    
  3. Set the DataContext of the Grid to the SampleViewModel StaticResource.
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="50" />
            </Grid.RowDefinitions>
    
  4. Add two rows to the Grid.
        <Grid DataContext="{StaticResource ResourceKey=Sample}">
    
  5. Add a TextBox and remove the sizing and alignments. Set Margin to 5. Bind the Text property to Message.
            <TextBox Text="{Binding Message}" Name="textBoxMessage" Margin="5"/>
    
  6. Add a button. Set HorizontalAlignment to Right. Set the Width to Auto. Set Margin to 5. Bind the Command property to ShowMessageCommand.
    <Button Command="{Binding ShowMessageCommand}" Content="ShowMessage" Grid.Row="1" Height="23" Name="buttonShowMessage" HorizontalAlignment="Right" Width="Auto" Margin="5"/>
    

You are done. The final XAML is as follows:

<Window x:Class="WpfDataBindingToICommand.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfDataBindingToICommand"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:SampleViewModel x:Key="Sample" />
    </Window.Resources>
    <Grid DataContext="{StaticResource ResourceKey=Sample}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="50" />
        </Grid.RowDefinitions>
        <TextBox Text="{Binding Message}" Name="textBoxMessage" Margin="5"/>
        <Button Command="{Binding ShowMessageCommand}" Content="ShowMessage" Grid.Row="1" Height="23" Name="buttonShowMessage" HorizontalAlignment="Right" Width="Auto" Margin="5"/>
    </Grid>
</Window>

Notice that we never touched the code behind of MainWindow. The GUI and the code are as decoupled as possible. Not event the event functions are needed in the code behind. This decoupling or GUI and code is our goal.

Resources

WPF Apps With The Model-View-ViewModel Design Pattern
Understanding Routed Events and Commands In WPF


Copyright ® Rhyous.com – Linking to this page 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.

November 16, 2010

Tutorial – Binding to a member variable object

Filed under: C# (C-Sharp),Visual Studio,WPF — J. Abram barneck @ 3:40 pm

You have your WPF Window and you have an object that you don’t want to make a static resource. You want to declare it as a member variable in the code.

Example 1 – Binding two TextBox controls to a Person object

  1. Create a New WPF Application Visual Studio.
  2. Create a new Class named Person.cs.
  3. Give it FirstName and a LastName properties.
  4. Configure it to implement the INotifyPropertyChanged interface.
  5. Create a NotifyPropertyChanged function that all properties can share (to avoid duplicate code in every single property).
  6. Configure the properties to call the NotifyPropertyChanged function passing in a string that is the name of the property.

    Person.cs

    using System;
    using System.ComponentModel;
    
    namespace WPFPerson
    {
        public class Person : INotifyPropertyChanged
        {
            #region Member Variables
            String _FirstName;
            String _LastName;
            #endregion
    
            #region Constructors
            /*
    		 * The default constructor
     		 */
            public Person()
            {
            }
            #endregion
    
            #region Properties
            public String FirstName
            {
                get { return _FirstName; }
                set
                {
                    _FirstName = value;
                    NotifyPropertyChanged("FirstName");
                }
            }
    
            public String LastName
            {
                get { return _LastName; }
                set
                {
                    _LastName = value;
                    NotifyPropertyChanged("LastName");
                }
            }
            #endregion
    
            #region INotifyPropertyChanged Members
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void NotifyPropertyChanged(String info)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(info));
                }
            }
            #endregion
        }
    }
    
  7. Go back tot he MainWindow.xaml.
  8. Add two labels, and two text boxes, and a button.
  9. Change the text boxes to be populated using binding by adding the following text:
    Text=”{Binding FirstName, Mode=TwoWay}”  

    MainWindow.xaml (WPF Window)

    <Window x:Class="WPFPerson.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 Name="PersonGrid" >
            <TextBox Height="23" HorizontalAlignment="Left" Margin="173,87,0,0" Name="textBoxFirstName" VerticalAlignment="Top" Width="234" Text="{Binding FirstName, Mode=TwoWay}" />
            <TextBox Height="23" HorizontalAlignment="Left" Margin="173,116,0,0" Name="textBoxLastName" VerticalAlignment="Top" Width="234" Text="{Binding LastName, Mode=TwoWay}"/>
            <Label Content="FirstName" Height="28" HorizontalAlignment="Left" Margin="103,85,0,0" Name="labelFirstName" VerticalAlignment="Top" />
            <Label Content="LastName" Height="28" HorizontalAlignment="Left" Margin="103,114,0,0" Name="labelLastName" VerticalAlignment="Top" />
            <Button Content="Defaults" Height="23" HorizontalAlignment="Left" Margin="337,199,0,0" Name="buttonDefaults" VerticalAlignment="Top" Width="75" Click="buttonDefaults_Click" />
        </Grid>
    </Window>
    
  10. Double-click the button to create the buttonDefaults_Click event function.
    This also conveniently takes you to the Code Behind of the MainWindow.cs file.
  11. Have the buttonDefaults_Click function update to properties of your _Person object.
    _Person.FirstName = “Jared”;
    _Person.LastName = “Barneck”;
  12. Create a field/member variable using the Person object.
    private readonly Person _Person;
  13. Now in the constructor initialize the object.
    _Person = new Person();
  14. Also in the constructor, make the DataContext for each TextBox the _Person object.
    textBoxFirstName.DataContext = _Person;
    textBoxLastName.DataContext = _Person;  

    MainWindow.cs (Code Behind)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Threading;
    
    namespace WPFPerson
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            private readonly Person _Person;
    
            public MainWindow()
            {
                _Person = new Person();
                InitializeComponent();
                textBoxFirstName.DataContext = _Person;
                textBoxLastName.DataContext = _Person;
            }
    
            private void buttonDefaults_Click(object sender, RoutedEventArgs e)
            {
                _Person.FirstName = "Jared";
                _Person.LastName = "Barneck";
            }
        }
    }
    
  15. Now Now compile and make sure you don’t have any errors.

Example 2 – Forthcoming…

Example 3 – Forthcoming…

Sources:
http://www.wrox.com/WileyCDA/Section/Windows-Presentation-Foundation-WPF-Data-Binding-with-C-2005.id-305562.html

October 26, 2010

What is the equivalent of __FILE__ and __LINE__ in C#?

Filed under: C# (C-Sharp),Development,Visual Studio — J. Abram barneck @ 7:46 am

Where is __LINE__ and __FILE__ in C#?

In C++ and in PHP and other languages, a great logging feature is the ability to log the file and line number where the log occurs.

These unfortunately do not exist.  I have been searching even in the latest .NET 4.0 and haven’t found them.  If they are there, they are hidden. Having these two variables is an extremely useful feature in other languages and it appears to be a feature very overlooked by the C# developers. However, maybe they didn’t overlook it.  Maybe there is a good reason that it is not there.

Getting __LINE__ and __FILE__ in C# when in debugging mode

There were a couple of solutions floating around online but many of them only worked with debugging enabled (or in release if the pdb file is in the same directory).

Here is one example that only works in debugging (or in release if the pdb file is in the same directory).

StackHelper.cs

using System;
using System.Diagnostics;

namespace FileAndLineNumberInCSharpLog
{
    public static class StackHelper
    {

        public static String ReportError(string Message)
        {
            // Get the frame one step up the call tree
            StackFrame CallStack = new StackFrame(1, true);

            // These will now show the file and line number of the ReportError
            string SourceFile = CallStack.GetFileName();
            int SourceLine = CallStack.GetFileLineNumber();

            return "Error: " + Message + "\nFile: " + SourceFile + "\nLine: " + SourceLine.ToString();
        }

        public static int __LINE__
        {
            get
            {
                StackFrame CallStack = new StackFrame(1, true);
                int line = new int();
                line += CallStack.GetFileLineNumber();
                return line;
            }
        }

        public static string __FILE__
        {
            get
            {
                StackFrame CallStack = new StackFrame(1, true);
                string temp = CallStack.GetFileName();
                String file = String.Copy(String.IsNullOrEmpty(temp)?"":temp);
                return String.IsNullOrEmpty(file) ? "": file;
            }
        }
    }
}

Here is a little Program.cs that shows how to use it.

using System;

namespace FileAndLineNumberInCSharpLog
{
    class Program
    {
        static void Main(string[] args)
        {
            int x = 100;
            int y = 200;
            int z = x * y;
            Console.WriteLine(StackHelper.ReportError("New Error"));
        }
    }
}

Unfortunately if the above does only work in release if the pdb file is available.

Getting __LINE__ and __FILE__ in C# when in debugging mode

Well, according to this MSDN forum post, it simply cannot be done.
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/6a7b021c-ec81-47c5-8f6a-2e280d548f3f

If I ever find a way to do it, I will post it.

So for troubleshooting a production file at a customer’s site, you pretty much have to send out your pdb file to them when they need it.  There are a lot of benefits to C# and this lacking feature is one of the eye sores.

October 20, 2010

Tutorial – Binding to Resources.resx for strings in a WPF Application: A technique to prepare for localization

Filed under: C# (C-Sharp),Development,Visual Studio,WPF — J. Abram barneck @ 12:14 pm

Introduction

Ok, so if you are going to have a string visible in your WPF application and your application can be in multiple languages, you are facing the localization problem.

Usually people as themselves two questions:

  • Do I localize or not?
  • How do I localize?

The answers are usually not now and I don’t know. So no localization work is done at first.  Later, you wish you were more prepared for localization.

Well, I am here to tell you that you can at least prepare to be localized by doing a few simple steps:

  1. Centralize your strings in a publicized Resources.resx file.
  2. Add a reference to your Properties.
  3. Replacing any statically entered text with the name of the string resource.
  4. Do you best to use dynamic sizing.

Preparing your strings for localization

If you are going to have a string in your WPF application, it is a good idea to store those strings in a centralized place for localization purposes.  Usually in Visual Studio, that is in Resources.resx.

Often a string is entered directly into an the WPF XAML.  This is not recommended.  Maybe you are thinking that you don’t need to localize your application, so this is not important to you.  Ok, really what you are thinking is:

“I don’t know how to do it and if I ever get big enough to need localization, at that point, I will figure it out.”

Well, what if I told you that using Resources.resx is extremely easy?

What if I told you that it hardly takes more time at all?

If it easy and hardly time consuming at all, you would do it, right? I would.  Hence this post.

Step by step guide for Preparing your strings for locaization

I have a project called LicenseAgreementManager.  Right now this only needs to display a license agreement in English, but maybe someday, this will need to display a license agreement in any language.

Preparation – Create a new project or use an existing project

In Visual Studio, create a new WPF Applcation project.

I named my project LicenseAgreementManager.

Right away, you already have at least one string statically entered into your XAML, the text for the window title.

Step 1 – Add all your strings to the Resources.resx file

  1. Double-click on Resources.resx in your WPF Project. This found under the ProjectName | Properties option in your Solution Explorer tree.
  2. Change the Access Modifier drop down menu from Internal to Public.
  3. Enter your strings in the Resources.resx by giving them a unique name and a value of the desired string.  A comment is also optional.

You now have a publicized Resource.resx file and a few strings inside it.

Step 2 – Add a reference to your Properties

  1. In your project, open your MainWindow.xaml file.The XAML looks as follows:
    <Window x:Class="LicenseAgreementManager.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>
    
        </Grid>
    </Window>
    
  2. Add a line to reference your Properties in the Windows element.
    <Window x:Class="LicenseAgreementManager.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:p="clr-namespace:LicenseAgreementManager.Properties"
            Title="MainWindow" Height="350" Width="525">
    

Step 3 – Replace static text with strings from the Resources.resx

  1. Change the Title attribute from static text to instead use access the string from your Resources.resx named EULA_Title.
    <Window x:Class="LicenseAgreementManager.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:p="clr-namespace:LicenseAgreementManager.Properties"
            Title="{x:Static p:Resources.EULA_Title}"
            Height="350" Width="525">
    

That was pretty easy, wasn’t it.

As you add elements that have strings, use the Resources.resx.

Step 4 – Try to use dynamic sizing

As best as possible, remove any dynamic sizing.

I have just added some items and removed the sizing as best as possible.  Here is my XAML.

<Window x:Class="LicenseAgreementManager.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:p="clr-namespace:LicenseAgreementManager.Properties"
        Title="{x:Static p:Resources.EULA_Title}"
        SizeToContent="WidthAndHeight"
        xml:lang="en-US">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <RichTextBox Name="_EulaTextBox" HorizontalAlignment="Stretch"  VerticalAlignment="Stretch"/>
        <StackPanel Grid.Row="1" Margin="0,10,0,0" Name="stackPanel2" HorizontalAlignment="Stretch"  VerticalAlignment="Stretch">
            <RadioButton Content="{x:Static p:Resources.EULA_Accept}" Margin="20,20,20,0" Name="radioButton1" />
            <RadioButton Content="{x:Static p:Resources.EULA_NotAccept}" Margin="20,20,20,0" Name="radioButton2" />
            <Button Content="{x:Static p:Resources.Next_Button}" Name="button1" Margin="20,20,35,20"  HorizontalAlignment="Right" />
        </StackPanel>
    </Grid>
</Window>

What changes did I make above that I couldn’t do through the Visual Studio GUI?

  1. I removed Height and size from almost every element.
  2. I added SizeToContent=”WidthAndHeight” to the Windows element.
  3. I added some extra size to the margins.

Conclusion

You don’t have to be localized to be prepared for easy localization.  By doing the above simple steps, when it comes time to add localization, you will be ready.

If you want to go on an finish localization.  You might want to read some of my sources.

Sources:

http://compositeextensions.codeplex.com/Thread/View.aspx?ThreadId=52910
http://msdn.microsoft.com/en-us/library/ms788718%28v=VS.90%29.aspx
http://msdn.microsoft.com/en-us/library/ms746621.aspx


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

 

Adding an alias in Windows 7 or making ls = dir in a command prompt

Hey all,

I don’t know about you but I switch between FreeBSD and Windows a lot.  So it drives me crazy when I type the command ls on windows and get the error message.

C:\Windows\system32>ls
‘ls’ is not recognized as an internal or external command,
operable program or batch file.

So I want this to go away.

I looked for the alias command in Windows and couldn’t find one.  So I made a batch file that solves this.

Windows doesn’t seem to have the equivalent of a .shrc or .cshrc or .bashrc. I couldn’t find a .profile either.  So I decided to go with the batch file route.

Creating a batch file as an alias

I created an <AliasName>.bat file that just forwards calls the original file and forwards all parameters passed when making the call.

Here is how it works.

Create a file called ls.bat. Add the following text.

ls.bat

@ECHO OFF
REM
REM Run a command with as many parameters as are passed.
REM This is used as a wrapper for any command.
REM It may also be used to alias a command.
REMREM Change this variable to equal the command you want to alias.
SET RealCMDPath=dir:getparams
SET cmdparams=%1
shift
:addparams
SET cmdparams=%cmdparams% %1
SHIFT
IF NOT %1.==. GOTO addparams

:runcmd
%RealCMDPath% %cmdparams%

Copy this batch file to your C:\Windows\System32 directory. Now you can type in ls on a windows box at the command prompt and it works.

How does this work to make your aliased command?

  1. Name the batch file the name of the alias.  I want to alias ls to dir, so my batch file is named ls.bat.
  2. In the batch file, set the RealCMDPath variable to the proper value, in my case it is dir.

So if you want to alias cp to copy, you do this:

  1. Copy the file and name it cp.bat.
  2. Edit the file and set this line:
    SET RealCMDPath=dir

Now you have an alias for both ls and cp.

Using different versions of msbuild.exe

You can also use this so you don’t have to add a path.

I need to use C:\Windows\Microsoft.NET\Framework\v3.5\msbuild.exe but sometimes I want to use C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe. Both files are named the same. So I can easily use my alias command.

  1. Create two files in C:\Windows\System32: one named msbuild35.bat and one named msbuild40.bat.
  2. Change the line in each file to have the appropriate paths for the RealCMDPath.

Anyway, this is really a useful batch file.

October 12, 2010

Running Unit Tests in Visual Studio 2010: DebugTestsInClass

Filed under: C# (C-Sharp) — J. Abram barneck @ 7:28 am

Problem

So, I am trying to run Unit tests in Visual Studio 2010.  However, it isn’t working.

I am getting this message in the status bar.

The key combination (Ctrl + R, Ctrl + C) is bound to command (DebugTestsInClass) which is currently not available.

I do have Visual Studio 2010 Ultimate so I expected everything to be available.

I did a Google and Bing and MSDN search for “DebugTestsInClass” and got a big fat nothing, which is pretty difficult to do these days. (Of course, that won’t happen for the next guy now that I have made this post!)

Anybody know what the DebugTestsInClass is and how to make it available?

Cause

Ok, so I found the issue.  My test project was created a long time ago in Visual Studio 2008 and using MBUnit.

I had changed the test to use no longer use MBUnit, but to use Microsoft.VisualStudio.QualityTools.UnitTestFramework.

I had create a new test project by click Test | New Test.

Then migrate my test classes to the new project.

I was unaware that the test project must be .NET 4, but yes it does.  Creating a new Test project allows me to use my Ctrl + R, Ctrl + C  functionality.

At first, I thought that using .NET 4 might be a problem because everything else we are doing is currently in .NET 3.5.  However, even though we are developing in .NET 3.5 currently, our test projects can be .NET 4 as they only run on dev and build machines.

Resolution

So it looks like multiple steps were required to move my test project from one testing library to another.

  1. Create a new Test project by going to Test | New Test.
  2. Move the classes to the new test project.
  3. Change the class syntax to match the syntax specified by Microsoft.VisualStudio.QualityTools.UnitTestFramework.
  4. Add any references needed.

 

September 9, 2010

How to document a function so Visual Studio’s Intellisense displays it?

Filed under: C# (C-Sharp),Visual Studio — J. Abram barneck @ 7:37 am

So, when I code, I am usually in Visual Studio and I am used to writing documentation above my functions as follows:

        /*
         * The is SomeFunction that does some action.
         */
        private void SomeFunction(int inSomeValue)
        {
                // write code here
        }

However, it annoys me that this information doesn’t show up in Visual Studio’s Intellisense. So I took time to look up the proper way to make function documentation show up in Intellisense.

It turns out that you can type /// above a function and Visual Studio will automagically populate the markup needed to have your comments show up in intellisense.

        /// <summary>
        ///  The is SomeFunction that does some action.
        /// </summary>
        /// <param name="inSomeValue">Enter an integer as some value here.</param>
        private void SomeFunction(int inSomeValue)
        {
                // write code here
        }

So it seems if you use this syntax, the function documentation will now show up in Visual Studio’s Intellisense.

How to document a function so Visual Studio's Intellisense displays it?

Filed under: C# (C-Sharp),Visual Studio — J. Abram barneck @ 7:37 am

So, when I code, I am usually in Visual Studio and I am used to writing documentation above my functions as follows:

        /*
         * The is SomeFunction that does some action.
         */
        private void SomeFunction(int inSomeValue)
        {
                // write code here
        }

However, it annoys me that this information doesn’t show up in Visual Studio’s Intellisense. So I took time to look up the proper way to make function documentation show up in Intellisense.

It turns out that you can type /// above a function and Visual Studio will automagically populate the markup needed to have your comments show up in intellisense.

        /// <summary>
        ///  The is SomeFunction that does some action.
        /// </summary>
        /// <param name="inSomeValue">Enter an integer as some value here.</param>
        private void SomeFunction(int inSomeValue)
        {
                // write code here
        }

So it seems if you use this syntax, the function documentation will now show up in Visual Studio’s Intellisense.

August 5, 2010

A DottedDecimal Object

Filed under: C# (C-Sharp),C/C++ — J. Abram barneck @ 10:32 am

Ok, so there are a lot of objects that are represented in dotted decimal notation.  The most common are versions and IP addresses.

Version 3.1.9.27

IP Address: 192.168.0.1

I have to wonder why I have never found in the Standard C++ Library, or in the C# libraries an object for these?  Are they there and I just don’t know how to find them.  It seems they are always just treated as Strings and this makes no sense to me.  Also these seem common enough that they should be standard objects in all languages.

Which IP Address is greater?

192.168.0.2
192.168.0.100

Well, since these are usually treated as strings, then .2 is greater than .100.  Unfortunately that is not correct.  We all know that .100 is greater.

So I created some objects that overload the >,>=,<=,<,==,!= functions.  Maybe these are completely finished, but hey, they are a start. I created C# and C++ versions.  The C# is first, scroll down if you are looking for C++ versions.

This is really great for versions that can be different.  However, I think that for an IP address object, that because it is limited to three characters and each section is one byte and only can be seen as 0-255, that a very efficient object could be created, but for now, a more generic DottedDecimal object is fine, though if you had a large list of IP addresses, you may want that efficiency.

Also, this is only tested with digits 0-9, not hex, so there is plenty more work to do, but usually version are just 0-9, though sometimes people throw in an “a” or “b” build such as 1.0.0.1a.  That is not handled yet.  So again, much more work to do.  But for my needs these are more than enough for now.

If there are already objects like this that are awesome, efficient, tested, and free, let me know.

C# DottedDecimal object for IP address and Versions

For C#, I implement a lot of interfaces too as you can see in the object.

DottedDecimal.cs

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

namespace DottedDecimalProject
{
    public class DottedDecimal
        : IComparable, IComparable<DottedDecimal>, IComparable<String>, ICloneable, IEquatable<string>, IEquatable<DottedDecimal>
    {
        #region Member Variables
        List<long> _DecimalValues;
        CompareDirection _CompareDirection = CompareDirection.LeftToRight;
        #endregion

        #region Constructors
        /*
         * The default constuctor.
         * The default compare direction is left to right
         * No values are added by default.
         */
        public DottedDecimal()
        {
        }

        /*
         * This constructor takes a string in this regex format
         * [0-9]+(\.[0-9])*
         */
        public DottedDecimal(String inDottedDecimalString)
        {
            _DecimalValues = null;
            _DecimalValues = StringToDottedDecimalList(inDottedDecimalString);
        }

        /*
         * This constructor takes two parameters.
         * Parameter 1 is a string in this regex format: [0-9]+(\.[0-9])*
         * Parameter 2 sets the compare direction. See this.Direction.
         */
        public DottedDecimal(String inDottedDecimalString, CompareDirection inCompareDirection)
        {
            _CompareDirection = inCompareDirection;
            _DecimalValues = null;
            _DecimalValues = StringToDottedDecimalList(inDottedDecimalString);
        }
        #endregion

        #region Properties
        /*
         * Returns the dotted decimal object in string format.
         */
        public String DottedDecimalString
        {
            get { return DottedDecimalListToString(); }
            set { _DecimalValues = StringToDottedDecimalList(value); }
        }

        /*
         * The decimal values are stored in order.  If LeftToRight, the left
         * most value is first.  If RightToLeft, the right most value is first.
         */
        public List<long> DecimalValues
        {
            get { return _DecimalValues; }
            set { _DecimalValues = value; }
        }

        /*
         * Determines whether to compare left to right or right to left.
         *
         * LeftToRight - 1.0.0.1 is greater than 1.0.0.0
         *               1.0.10 is greater than 1.0.0.27
         *
         * RightToLeft - 1.0.0.1 is less than 1.0.0.0
         *             - 1.0.10 is less than 1.0.0.27
         */
        public CompareDirection Direction
        {
            get { return _CompareDirection; }
            set
            {
                if (!(this.Direction == value))
                {
                    this._DecimalValues.Reverse();
                }
                _CompareDirection = value;
            }
        }
        #endregion

        #region Functions
        /*
         * Verifies that the CompareDirection values match between two DottedDecimal objects.
         */
        private static bool CompareDirectionsMatch(DottedDecimal left, DottedDecimal right)
        {
            if (left.Direction == right.Direction)
                return true;
            else
                return false;
        }

        /*
         * Overloads the greater than operator (>) to allow for a syntax as follows:
         *
         *      bool b = dd1 > dd2;
         */
        public static bool operator >(DottedDecimal left, DottedDecimal right)
        {
            int count = (left.DecimalValues.Count > right.DecimalValues.Count) ? right.DecimalValues.Count : left.DecimalValues.Count;

            for (int i = 0; i < count; i++)
            {
                // If left side is greater then true;
                if (left.DecimalValues[i] > right.DecimalValues[i])
                {
                    return true;
                }
                // If right side is greater then false;
                if (left.DecimalValues[i] < right.DecimalValues[i])
                {
                    return false;
                }
                // If it is equal, check the next decimal values over
                if (left.DecimalValues[i] == right.DecimalValues[i])
                {
                    continue;
                }
            }

            if (left.DecimalValues.Count > right.DecimalValues.Count)
            {
                // If the left side has the same values as the right,
                // but then has more values, true.
                return true;
            }

            if (left.DecimalValues.Count < right.DecimalValues.Count)
            {
                // If the left side has the same values as the right,
                // but then the right side has more values, false.
                return false;
            }
            // If we get here both sides are equals, so false
            return false;
        }

        /*
         * Overloads the less than operator (<) to allow for a syntax as follows:
         *
         *      bool b = dd1 < dd2;
         */
        public static bool operator <(DottedDecimal left, DottedDecimal right)
        {
            int count = (left.DecimalValues.Count > right.DecimalValues.Count) ? right.DecimalValues.Count : left.DecimalValues.Count;
            for (int i = 0; i < count; i++)
            {
                // If right side is greater then true;
                if (left.DecimalValues[i] < right.DecimalValues[i])
                {
                    return true;
                }
                // If the left is greater then false;
                if (left.DecimalValues[i] > right.DecimalValues[i])
                {
                    return false;
                }
                // If it is equal, check the next decimal values over
                if (left.DecimalValues[i] == right.DecimalValues[i])
                {
                    continue;
                }
            }

            if (left.DecimalValues.Count > right.DecimalValues.Count)
            {
                // If the left side has the same values as the right,
                // but then has more values, false.
                return false;
            }

            if (left.DecimalValues.Count < right.DecimalValues.Count)
            {
                // If the left side has the same values as the right,
                // but then the right side has more values, true.
                return true;
            }
            // If we get here both sides are equals, so false
            return false;
        }

        /*
         * Overloads the equals operator (==) to allow for a syntax as follows:
         *
         *      bool b = dd1 == dd2;
         */
        public static bool operator ==(DottedDecimal left, DottedDecimal right)
        {
            // If there are more values in either side, they aren't equal
            if (!(left.DecimalValues.Count == right.DecimalValues.Count))
            {
                return false;
            }
            for (int i = 0; i < left.DecimalValues.Count; i++)
            {
                // If any one value is not equal, then false
                if (left.DecimalValues[i] != right.DecimalValues[i])
                {
                    return false;
                }
            }
            // If you get here they are all equal so true
            return true;
        }

        /*
         * Overloads the not equals operator (!=) to allow for a syntax as follows:
         *
         *      bool b = dd1 != dd2;
         */
        public static bool operator !=(DottedDecimal left, DottedDecimal right)
        {
            // If there are more values in either side, they aren't equal
            if (!(left.DecimalValues.Count == right.DecimalValues.Count))
            {
                return true;
            }
            for (int i = 0; i < left.DecimalValues.Count; i++)
            {
                // If any one value is not equal, then true
                if (left.DecimalValues[i] != right.DecimalValues[i])
                {
                    return true;
                }
            }
            // If you get here they are all equal so false
            return false;
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

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

        public override string ToString()
        {
            return DottedDecimalString;
        }

        /*
         * Appends a new string value to the left side of a DottedDecimal object.  Adding "12" to
         * 1.0.0 makes it 1.0.0.12.  Because it is a string, you can also add multiple values at
         * a time so adding the string "12.24" makes 1.0.0.12.24.
         */
        void AddToLeftSide(String inVal)
        {
            foreach (string decimalString in inVal.Split('.'))
            {
                _DecimalValues.Insert(0, Convert.ToInt64(inVal));
            }
        }

        /*
         * Appends a new value to the left side of a DottedDecimal object.  Adding 12 to
         * 1.0.0 makes it 1.0.0.12
         */
        public void AddToLeftSide(long inVal)
        {
            _DecimalValues.Insert(0, inVal);
        }

        /*
         * Appends a new string value to the right side of a DottedDecimal object.  Adding "12" to
         * 1.0.0 makes it 12.1.0.0.  Because it is a string, you can also add multiple values at
         * a time so adding the string "12.24" makes 12.24.1.0.0.
         */
        public void AddToRightSide(String inVal)
        {
            foreach (string decimalString in inVal.Split('.'))
            {
                _DecimalValues.Add(Convert.ToInt64(decimalString));
            }
        }

        /*
         * Appends a new value to the right side of a DottedDecimal object.  Adding 12 to
         * 1.0.0 makes it 12.1.0.0
         */
        public void AddToRightSide(long inVal)
        {
            _DecimalValues.Add(inVal);
        }

        private string DottedDecimalListToString()
        {
            string retVal = "";
            if (this.Direction == CompareDirection.LeftToRight)
            {
                foreach (long l in _DecimalValues)
                {
                    if (!retVal.Equals(""))
                    {
                        retVal += ".";
                    }
                    retVal += l;
                }
            }
            else
            {
                for (int i = _DecimalValues.Count - 1; i >= 0; i--)
                {
                    if (!retVal.Equals(""))
                    {
                        retVal += ".";
                    }
                    retVal += _DecimalValues[i];
                }
            }
            return retVal;
        }

        private List<long> StringToDottedDecimalList(String inString)
        {
            List<long> retList = new List<long>();
            foreach (string decimalString in inString.Split('.'))
            {
                retList.Add(Convert.ToInt64(decimalString));
            }
            if (this.Direction == CompareDirection.RightToLeft)
            {
                retList.Reverse();
            }
            return retList;
        }

        #endregion

        #region Interface Functions

        #region IComparable Members
        public int CompareTo(object inOjbect)
        {
            DottedDecimal dd = (DottedDecimal)inOjbect;
            return CompareTo(dd);
        }
        #endregion

        #region IComparable<DottedDecimal> Members
        public int CompareTo(DottedDecimal inDottedDecimal)
        {
            if (this < inDottedDecimal)
                return -1;
            if (this == inDottedDecimal)
                return 0;
            if (this > inDottedDecimal)
                return 1;
            return -2; // Should never get here.
        }
        #endregion

        #region IComparable<string> Members
        public int CompareTo(string inString)
        {
            DottedDecimal dd = new DottedDecimal(inString);
            return CompareTo(dd);
        }
        #endregion

        #region ICloneable Members
        public object Clone()
        {
            return new DottedDecimal(this.DottedDecimalString, this.Direction);
        }

        #endregion

        #region IEquatable<string> Members
        public bool Equals(string inString)
        {
            DottedDecimal dd = new DottedDecimal(inString);
            return this == dd;
        }

        #endregion
        #region IEquatable<DottedDecimal> Members
        public bool Equals(DottedDecimal inDottedDecimal)
        {
            return this == inDottedDecimal;
        }
        #endregion

        #endregion

        #region Enums
        public enum CompareDirection
        {
            LeftToRight,
            RightToLeft
        }
        #endregion
    }
}

C++ DottedDecimal object for IP address and Versions

I tried to overload the common operators, if there is one you would like overloaded, let me know.

DottedDecimal.h

#pragma once
#include <vector>
#include <iostream>
#include "windows.h"

using namespace std;

class DottedDecimal
{
public:
	// Constructors
	DottedDecimal(); // Default constructor
	DottedDecimal(DottedDecimal & inDottedDecimal); // Copy constructor
	DottedDecimal(string inString);
	DottedDecimal(char * inString);
	DottedDecimal(LPTSTR inString);

	// Destructors
	~DottedDecimal();

	// Public functions
	string GetDottedDecimal();

	template <class T>
	void SetDottedDecimal(const T& t);

	vector<long> GetDecimals();

	// Functions Overloading Operators
	friend ostream &operator<<(ostream & dataStream, DottedDecimal & dd);

	friend bool operator==(DottedDecimal & left, DottedDecimal & right);
	friend bool operator!=(DottedDecimal & left, DottedDecimal & right);

	friend bool operator>(DottedDecimal & left, DottedDecimal & right);
	friend bool operator>=(DottedDecimal & left, DottedDecimal & right);

	friend bool operator<(DottedDecimal & left, DottedDecimal & right);
	friend bool operator<=(DottedDecimal & left, DottedDecimal & right);

private:
	// Member Variables
	vector<long> _decimals;

	// Private Functions
	void StringSplit(string inString, string inDelim, vector<string> * outResults);

	template <class T>
	string AnyTypeToString(const T& t);

	template <class T>
	void StringToAnyType(T& t, std::string inString);
};

DottedDecimal.cpp

#include "StdAfx.h"
#include "DottedDecimal.h"
#include <iostream>
#include <sstream>

using namespace std;

DottedDecimal::DottedDecimal()
{
}

DottedDecimal::DottedDecimal(DottedDecimal & inDottedDecimal)
{
	SetDottedDecimal(inDottedDecimal.GetDottedDecimal());
}

DottedDecimal::DottedDecimal(string inString)
{
	SetDottedDecimal(inString);
}

DottedDecimal::DottedDecimal(LPTSTR inString)
{
	wstring ws = wstring(inString);
	string s;
	s.assign(ws.begin(), ws.end());
	SetDottedDecimal(s);
}

DottedDecimal::DottedDecimal(char * inString)
{
	SetDottedDecimal(inString);
}

DottedDecimal::~DottedDecimal()
{
}

string DottedDecimal::GetDottedDecimal()
{
	string retVal = "";
	for (unsigned short i = 0; i < _decimals.size(); i++)
	{
		if (retVal.compare("") != 0)
		{
			retVal += ".";
		}
		retVal += AnyTypeToString(_decimals.at(i));
	}
	return retVal;
}

template <class T>
void DottedDecimal::SetDottedDecimal(const T& t)
{
	_decimals.clear();
	string valueString = AnyTypeToString(t);
	vector<string> * values = new vector<string>();
	StringSplit(valueString, ".", values);
	for (unsigned short i = 0; i < values->size(); i++)
	{
		long l;
		StringToAnyType(l, values->at(i));
		_decimals.push_back(l);
	}
	delete values;
}

vector<long> DottedDecimal::GetDecimals()
{
	return _decimals;
}

ostream &operator<<(ostream & dataStream, DottedDecimal & dd)
{
	dataStream << dd.GetDottedDecimal();
	return dataStream;
}

bool operator==(DottedDecimal & left, DottedDecimal & right)
{
	// If the value count isn't the same, then false
	if (left.GetDecimals().size() != right.GetDecimals().size())
		return false;

	for (unsigned short i = 0; i < left.GetDecimals().size(); i++)
	{
		// If at any time values don't match, return false
		if (left.GetDecimals().at(i) != right.GetDecimals().at(i))
			return false;
	}

	// If you get here they are the same.
	return true;
}

bool operator!=(DottedDecimal & left, DottedDecimal & right)
{
	// If the value count isn't the same, then true
	if (left.GetDecimals().size() != right.GetDecimals().size())
		return true;

	for (unsigned short i = 0; i < left.GetDecimals().size(); i++)
	{
		// If at any time values don't match, return true
		if (left.GetDecimals().at(i) != right.GetDecimals().at(i))
			return true;
	}

	// If you get here they are the same.
	return false;
}

bool operator>(DottedDecimal & left, DottedDecimal & right)
{
	// If one has three values and the other has four, only check three
	short count = (left.GetDecimals().size() <= right.GetDecimals().size() ? left.GetDecimals().size() : right.GetDecimals().size());
	for (unsigned short i = 0; i < count; i++)
	{
		if (left.GetDecimals().at(i) > right.GetDecimals().at(i))
			return true;
	}

	// If you get here, then the checked values were the same.
	// Return true if the left side has more values than the right side.
	if (left.GetDecimals().size() > right.GetDecimals().size() )
		return true;
	else
		return false;
}

bool operator>=(DottedDecimal & left, DottedDecimal & right)
{
	// If one has three values and the other has four, only check three
	short count = (left.GetDecimals().size() <= right.GetDecimals().size() ? left.GetDecimals().size() : right.GetDecimals().size());
	for (unsigned short i = 0; i < count; i++)
	{
		// If any compared value is greater, return true;
		if (left.GetDecimals().at(i) > right.GetDecimals().at(i))
			return true;
	}

	// If you get here, then the checked values were the same.
	// Return true if the left side has more values than or the same values as the right side.
	return left.GetDecimals().size() >= right.GetDecimals().size();
}

bool operator<(DottedDecimal & left, DottedDecimal & right)
{
// If one has three values and the other has four, only check three
	short count = (left.GetDecimals().size() <= right.GetDecimals().size() ? left.GetDecimals().size() : right.GetDecimals().size());
	for (unsigned short i = 0; i < count; i++)
	{
		// If any compared value is less, return true;
		if (left.GetDecimals().at(i) < right.GetDecimals().at(i))
			return true;
	}

	// If you get here, then the checked values were the same.
	// Return true if the left side has less values than the right side.
	return left.GetDecimals().size() < right.GetDecimals().size();
}

bool operator<=(DottedDecimal & left, DottedDecimal & right)
{
	// If one has three values and the other has four, only check three
	short count = (left.GetDecimals().size() <= right.GetDecimals().size() ? left.GetDecimals().size() : right.GetDecimals().size());
	for (unsigned short i = 0; i < count; i++)
	{
		// If any compared value is greater, return true;
		if (left.GetDecimals().at(i) > right.GetDecimals().at(i))
			return true;
	}

	// If you get here, then the checked values were the same.
	// Return true if the left side has less values than or the same values as the right side.
	return left.GetDecimals().size() <= right.GetDecimals().size();
}

// Private

template <class T>
string DottedDecimal::AnyTypeToString(const T& t)
{
	std::stringstream ss;
	ss << t;
	return ss.str();
}

template <class T>
void DottedDecimal::StringToAnyType(T& t, std::string inString)
{
	std::stringstream ss(inString);
	ss >> t;
}

void DottedDecimal::StringSplit(string inString, string inDelim, vector<string> * outResults)
{
	int cutAt;
	while( (cutAt = inString.find_first_of(inDelim)) != inString.npos )
	{
		if(cutAt > 0)
		{
			outResults->push_back(inString.substr(0,cutAt));
		}
		inString = inString.substr(cutAt+1);
	}
	if(inString.length() > 0)
	{
		outResults->push_back(inString);
	}
}

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

Next Page »

Blog at WordPress.com.