Google
WWW Yariv Hammer's Code Site

Thursday, October 27, 2005

Posts Index

About Me

Remoting and Networking
Ping in .NET 2003
Calling Remoting Objects- Basic Concepts
Creating a Simple Server/Client Application With Remoting - A Step-By-Step Tutorial
How To Get the Singleton Instance of a Remote Object in the Server and in the Client
Creating a Broadcast Events Server Using .NET Remoting
Recovering From Server/Clients Disconnections in Remoting
Maintaining a List of All Connected Clients

DataGrid and ADO.NET
Using JoinView to Show Queries From Multiple Tables
Setting the Row Height of the Grid to Fit the Contents
DataGrid With Columns of Any Control You Like
How-To Show Different Columns in the DataGrid of the same DataTable
How To Show Only a Subset of the Columns in the DataGrid
How-To Select a Row in the DataGrid When the Mouse is Over it
Calculate a Cell value in a DataGrid based on the rows above it
How to set the ForeColor of the text in a cell based on a condition
How to use DataGridColumnStyles programatically
Loading the Entire Database Into a DataSet, Including Relations (New)
Generating a DataSet From an Xml Schema in 2005 (New)

GUI Related Issues
Print Screen And Save It to File
Problems With NumericUpDown Control and Binding
Making RichTextBox Readonly (With Rtf)
How-to allow user to move a control on a form
How-To Allow the User to Resize Controls on a Form at Runtime
DegreesUpDown Control

Xml
Loading and Validating Xml Files
Xml Schema Reader Application

.NET Assemblies
Exploring .NET Assemblies
Multi-File Assemblies
Strong Named Assemblies
Placing Assemblies in the Global Assembly Cache (GAC)
Administrative Configuration of Applications
Loading a class dynamically (New)

MultiThreading
Asynchronous Programming in .NET
Synchronizing Threads in .NET
MultiThreading Without The Thread Class
Passing Parameter to Thread
Creating a general delegate using Generics (New)

.NET Related Issues
Create a Script to Build .NET Projects
Importing C++ Unmanaged class into .NET 2003
How-to create a Main method in VB.NET
How-to prevent an Application from running more than once
ASP.NET don't work even though IIS is installed

Create a Script to Build .NET Projects

Introduction
Sometimes we need to use command line in order to compile our C# or VB.NET projects. This is very useful when we have a big project with a lot of solutions. Compiling each manually can be vary tedious.
I want a solution that will not require me to use csc (C# compiler) because I don't know all the flags that the VS IDE uses when it builds my project.

Using The IDE From Command Line
I found out that I can tell VS.NET to build my project/solution in command line using the following statement:
devenv mySolution.sln /rebuild debug
or
devenv mySolution.sln /build release

It will build my solution as if I click the Build button in the menu inside the IDE. This is exactly what I need - I will set the project properties in the comfortable project properties window, and then run a script that will build everything for me, and get an extra bonus: It can copy stuff around, run executables, check things in between the builds.

Creating the Script
The script is actually a bat file. Here is a template you can use for your project:
-----------------------------------------------

@echo off
set visualStudioDir=C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDEset solutionDir="."
set buildType=Debug
set returnErrorCode=true
set pause=true

if "%1"=="/?" goto HELP
if not "%1"=="" set solutionDir=%1
if "%1"=="" set solutionDir="C:\"
if not Exist "%visualStudioDir%..\Tools\vsvars32.bat" goto HELPVS

set savedPrompt=%prompt%
set prompt=*$g
@call "%visualStudioDir%..\Tools\vsvars32.bat"

GenerateSolution:
set solutionName= MySolutionName
set solutionPath= RelativePathToSolution

pushd %solutionDir%\%RelativePathToSolution%\
if not Exist %solutionDir%\%solutionPath%\%solutionName%.sln goto ErrorCouldNotFindSolution
devenv %solutionName%.sln /build %buildType%
@if errorlevel 1 goto :error
popd
@goto :exit

:error
if %returnErrorCode%==false goto exit
@ECHO An error occured in BuildLibrary.bat - %errorLevel%
if %pause%==true PAUSE
@exit errorLevel

:ErrorCouldNotFindSolution
echo Could not find %solutionDir%\%solutionPath%\%solutionName%.sln
@goto :exit

:HELPVS
echo Error: Unable to locate Visual Studio.NET
echo.
echo This batch assumes Visual Studio.NET 2003 has been installed in its default location
echo ("%visualStudioDir%".)
echo.
echo If you have installed Visual Studio.NET 2003 to a different location, you will need echo to update this batch file to reflect that location.
echo.
goto exit

:HELP
echo Usage: BatchBuild [path]
echo.
echo BatchBuild will build the solution that is located in path.
echo.

goto exit
:exit
if %pause%==true PAUSE
set pause=
set solutionDir=
set buildType=
set returnErrorCode=
set prompt=%savedPrompt%
set savedPrompt=
set solutionName=
set solutionPath=
echo on

---------------------------------------
The emphasized part is the one that builds your solution. Change only what in the red section: Customize it by changing the tag (GeneratedSolution:), the solutionName and solutionPath. You can duplicate it if you need to build several solutions.
Usage:
Script.bat /? - Shows help
Script.bat C:\ - Will start all compilations from this directory (useful when you have few versions of same project).

Wednesday, October 26, 2005

How To Get the Singleton Instance of a Remote Object in the Server and in the Client

Introduction
If we are using Singleton classes in the Remoting session, that means that all the clients will access the same copy of the object that lives in the Server process.
I will show a good way of getting the instance of the singleton object, and a way of getting this instance in the server.

Using Singleton Objects
Generally speaking, the Singleton design pattern is not supported for classes. You wll need to implement it yourself (private constructor, static Instance property, you know the deal). But for Remoting objects (MarshalByRefObjects) there is no need for such explicit implementation. When you register the object for remoting in the server:
--------------------------------

RemotingConfiguration. RegisterWellKnownServiceType( typeof(RemoteObject), "MyServer", WellKnownObjectMode.Singleton );

--------------------------------
And the object will be a Singleton without it showing in the code.

Getting the Remote Singleton In the Client
The following class should be in the Client application (or referenced by it). It is a generic factory to get remote objects (not necessarily Singletons):
------------------------------------

public class RemotingHelper
{
   internal static bool _isInit = false;
   private static IDictionary _wellKnownTypes;
   public static object GetObject(Type type)
   {
      if (!_isInit)
         InitTypeCache();
      WellKnownClientTypeEntry entr = (WellKnownClientTypeEntry) _wellKnownTypes[type];
      if (entr==null)
         throw new RemotingException("Type not found");
      return Activator.GetObject(entr.ObjectType,entr.ObjectUrl);
   }

   private static void InitTypeCache()
   {
      _wellKnownTypes = new Hashtable();
      foreach(WellKnownClientTypeEntry entr in RemotingConfiguration. GetRegisteredWellKnownClientTypes())
         _wellKnownTypes.Add(entr.ObjectType,entr);
      _isInit = true;
   }
}

-----------------------------------
use RemotingConfiguration.GetObject(typeof(whatever)) to get the remote object.
This class is very efficient because it uses Hashtable to store the objects. It will throw an exception when the type is not registered for remoting in the client or server. It is generic!!! You can use it in every client you write with no regards to the object types.

Getting the Remote Singleton In the Server
If you do this in the server:
RemoteObject obj = new RemoteObject();
You will get a new instance of the RemoteObject. You will not get the actual copy that the clients are using. This is important to know!!!

So I put a class in the Server application (or referenced by it) which has a Hashtable similar to the one I showed before:
-------------------------------------------------

public class RemoteSingletonObjectsList
{
   private static RemoteSingletonObjectsList _instance = new RemoteSingletonObjectsList();
   public static RemoteSingletonObjectsList Instance
   {
      get { return _instance; }
   }
   private RemoteSingletonObjectsList() { }
   private Hashtable _objects = new Hashtable();
   public void RegisterRemoteSingletonObject(object obj)
   {
      _objects[obj.GetType()] = obj;
   }
   public object GetRemoteSingletonObject(Type type)
   {
      return _objects[type];
   }
}

------------------------------------------------
The following method should be called from the Main of the server before running the Form:
------------------------------------------------

private static void InitRemoting()
{
   foreach (WellKnownServiceTypeEntry entry in RemotingConfiguration. GetRegisteredWellKnownServiceTypes())
   {
      MarshalByRefObject pxy = (MarshalByRefObject) Activator.GetObject(entry.ObjectType, "tcp://localhost:port/MyServer/" + entry.ObjectUri);
      pxy.CreateObjRef(entry.ObjectType);
      RemoteSingletonObjectsList.Instance. RegisterRemoteSingletonObject(pxy);
   }
}

------------------------------------------------
The Activator.GetObject and MarshalByRefObject.CreateObjRef methods do the work of getting the Remote objects.

When you need the object in the server you call RemoteSingletonObjectsList.GetRemoteSingletonObject(typeof(whatever)).

How-To Show Different Columns in the DataGrid of the same DataTable

Introduction
In my previous post I showed how to select which rows to show in the DataGrid. Now I will take this one step further, and show how to add buttons in the form which when clicked change which columns are shown in the DataGrid.
This can be very useful on large tables with many columns. We want to have different "views" of the same DataTable, instead of showing all the data at once.

Example
In this example I have a form with a DataGrid and two Buttons. On Form_Load I create a DataTable with 100 columns (which might simulate your problem). I create a DataGridColumnStyle for each column, and store them in a Hashtable, mapping each column index with the appropriate ColumnStyle:
------------------------------------------------

   Private ts As New DataGridTableStyle
   Private hash As New Hashtable
   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      'Create the table
      Dim dt As DataTable = New DataTable("table")
      For i As Integer = 1 To 100
         dt.Columns.Add(New DataColumn("col" & i))
      Next

      Create a TableStyle
      ts.MappingName = "table"
      'Create the ColumnStyles and map them to the columns
      For i As Integer = 1 To 100
         Dim cs As New DataGridTextBoxColumn
         cs.MappingName = "col" & i
         cs.HeaderText = "col" & i
         hash(i) = cs
         'Only the first 10 columns is shown!!!!!
         If (i <= 10) Then _
            ts.GridColumnStyles.Add(cs)
      Next
      DataGrid1.TableStyles.Add(ts)
      DataGrid1.DataSource = dt
   End Sub

-------------------------------------------------
As you can see, all the ColumnStyles which are added to the TableStyle is shown to the user in the order of insertion. So in our case, we will see only the first 10. But I created 100 ColumnStyles.
On the first button click I will show the first 10 columns. On the second button click I will show the next 10 (11-21).
-------------------------------------------------

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
   ts.GridColumnStyles.Clear()
   For i As Integer = 1 To 10
      ts.GridColumnStyles.Add(hash(i))
   Next
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
   ts.GridColumnStyles.Clear()
   For i As Integer = 11 To 20
      ts.GridColumnStyles.Add(hash(i))
   Next
End Sub


-------------------------------------------------
You can, for example, create 10 radio buttons (shaped as buttons), each of them creates a different view, by selecting other columns to map.

How To Show Only a Subset of the Columns in the DataGrid

Introduction
This is a common problem: You have a table with a lot of columns and you only want to show some columns to the user in a DataGrid. Or, you have an ID column that you don't want to show the user.
Unfortunately when you set the DataSource of the Datarid to be a DataTable or a DataView, the user can see all the columns, and there is no easy way to filter what columns you actually need.

Using DataGridColumnStyles Will Solve The Problem.
You can learn about DataGridColumnStyles in this post. When you setup ColumnStyles to your DataGrid the user can see only those which where added explicitly to the TableStyle.
For example: If you have 3 columns in your DataTable: ID, Name and Value and you only want to show Name and Value. The code to use is this:
---------------------------------------

//Initialize objects
DataGridTableStyle myTable = new DataGridTableStyle();
DataGridTextBoxColumn nameColumn = new DataGridTextBoxColumn();
DataGridTextBoxColumn valueColumn = new DataGridTextBoxColumn();

//Setting a DataTable as the DataSource - dt is DataTable object
dataGrid1.BeginInit();
dataGrid1.DataSource = dt;


// myTable
dataGrid1.TableStyles.AddRange(new DataGridTableStyle[] {myTable});
myTable.DataGrid = dataGrid1;
myTable.GridColumnStyles.AddRange(new DataGridColumnStyle[] {nameColumn,valueColumn});
myTable.MappingName = "TableName"; // This is the name of the table.

// nameColumn
nameColumn.MappingName = "Name"; // This is the name of the column.

// valueColumn
valueColumn.MappingName = "Value"; // This is the name of the column.
dataGrid1.EndInit();

---------------------------------------
We did not create a ColumnStyle for the Id column, so the user will not see it in the grid. Of course when creating a new row in the grid we will need a mechanism to set the Id instead of the user (for example: AutoNumber).

In the next post I will take this one step further and show how to set different views of columns.

Monday, October 24, 2005

Problems With NumericUpDown Control and Binding

Introduction
The NumericUpDown control has some problems in .NET 2003, which I will show how to solve:
  • When the user edit the NumericUpDown and deletes the content of the TextBox, leaving it empty, an unhandled exception will be shown when the control looses focus.
  • When the control is bound to a DataTable, and the user edits the text (not pressing on the up and down buttons), the changed value is not updated to the table when the control looses focus as expected.

I will also show how to show a MessageBox notifying the user that the value he inserted is not valid, and the valid range. After the message is gone the user will not be able to exit the control.

The Code

We will need to inherit from NumericUpDown, and add the following code to the new control (The code is in VB.NET):

-----------------------------------------------------



Public Class MyNumericUpDown
   Inherits System.Windows.Forms.NumericUpDown
   (...) ' Windows designer stuff

   Private bHaveChanges As Boolean = False

   Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
      bHaveChanges = True
   End Sub

   Private Sub RefreshValue()
      Dim oldMax As Decimal = Me.Maximum
      Me.Maximum += Me.Increment*2
      Me.UpButton()
      Me.DownButton()
      Me.Maximum = oldMax
   End Sub

   Private _lock As Boolean = False
   Private Sub IosNumericUpDown_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.LostFocus
      If _lock Then Exit Sub
      If (Me.Text = "") Then
         _lock = True
         Me.Text = "0"
         _lock = False
      End If
      Try
         If CDec(Me.Text) <> Me.Maximum Then
            _lock = True
            MsgBox("Value should be between " & Me.Minimum &amp; " and " & Me.Maximum & "!", _
               MsgBoxStyle.OKOnly + MsgBoxStyle.Critical, "Validation")
            Me.Focus()
            Me.Select(0, Me.Text.Length)
            _lock = False
            Return
         End If
      Catch ' CDbl failed
         _lock = False
         Me.Text = "0"
      End Try
      If bHaveChanges Then
         RefreshValue()
         bHaveChanges = False
      End If
   End Sub

   Private Sub IosNumericUpDown_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Leave
      If Value = _beforeValue Then Exit Sub
         _lockEnterLeave = True
         RefreshValue()
         _lockEnterLeave = False
   End Sub

   Private _lockEnterLeave As Boolean = False
   Private _beforeValue As Decimal
   Private Sub IosNumericUpDown_Enter(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Enter
      If _lockEnterLeave Then
         Exit Sub
      End If
      _beforeValue = Value
   End Sub
End Class

-----------------------------------------

Making RichTextBox Readonly (With Rtf)

Introduction
I recently needed to place an RTF file with pictures in side a RichTextBox. This is a very easy procedure: Simply call the LoadFile method of RichTextBox. The advantages of using RTF is the ability to create a very complex document using Microsoft word, and displaying it on my form. The user can edit the contents of the control and save it in a rich text format. In my case I used it because I needed to show the user lots of pictures in one control, and he could scroll up and down to see all of them.

The Problem
I needed to prevent the user from editing the contents of the RichTextBox.
I tried the Enabled property. Setting it to false disabled the Scroll Bar of the RichTextBox. Without it the user can't see all the pictures, so this is out of the question.
I tried the ReadOnly property. It does nothing when loading RTF files.
I needed to find some other way to prevent the user from editing. I had a really serious problem, because when the RTF contains pictures, those can be selected by the user and deleted by pressing on the delete key.

The Solution
The best solution I could come up with is disabling the click event, the MouseDown KeyDown and Enter event. Some of them require another control to receive focus:
-----------------------------------------------

private void richTextBox1_MouseDown(object sender, MouseEventArgs e)
{
   textBox1.Focus(); //To remove the focus to another control.
}
private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
   e.Handled = true;
}
private void richTextBox1_Enter(object sender, EventArgs e)
{
   textBox1.Focus(); //To remove the focus to another control.
}

------------------------------------------------

How-To Select a Row in the DataGrid When the Mouse is Over it

Introduction
If you want to select a row in the DataGrid when the user point the mouse on it (without clicking!!!), Then you will need to do some coding.
The DataGrid has a HitTest method to help us get the cell that the mouse is pointing at. We can use the Select and Unselect methods.

Code
----------------------------------------------
Create a MouseMove event handler to the DataGrid and place this code:

private int _prevRow = -1;
private void dataGrid1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
   DataGrid.HitTestInfo info = dataGrid1.HitTest(e.X, e.Y);
   if (info.Type == DataGrid.HitTestType.Cell)
   {
      if (_prevRow != info.Row)
      {
         this.BindingContext[dataGrid1].EndCurrentEdit();
         if (_prevRow != -1)
         dataGrid1.UnSelect(_prevRow);          dataGrid1.Select(info.Row);
         _prevRow = info.Row;
      }
   }
   else
   {
      if (_prevRow != -1)
      {
         dataGrid1.UnSelect(_prevRow);
         _prevRow = -1;
      }
   }
}

-------------------------------------------------

Ping in .NET 2003

Introduction
Ping is very useful when there is a need to know if a certain computer is connected to the local computer via network. The quickest way to programmatically know if another computer is currently active and connected is by using ping.
However, there is no built-in support for Ping in .NET 2003 (Microsoft added a Ping class to Framework 2.0).

Solution
This code can be used in order to check if a remote computer is alive using ping:
---------------------------------------------------

public class Ping
{
   private const string REQUEST_TIMED_OUT = "Request timed out.";
   public static bool IsConnected(string ipAddress)
   {
      Process p = new Process();
      p.StartInfo.UseShellExecute = false;
      p.StartInfo.RedirectStandardOutput = true;
      p.StartInfo.Arguments = ipAddress;
      p.StartInfo.FileName=@"ping";
      p.StartInfo.CreateNoWindow=true;
      p.Start();
      string output = p.StandardOutput.ReadToEnd();
      p.WaitForExit();
      return AnalysePingOutput(output);
   }
   private static bool AnalysePingOutput(string output)
   {
      return !(output.IndexOf(REQUEST_TIMED_OUT)>0);
   }
}

---------------------------------------------------

Sunday, October 23, 2005

Importing C++ Unmanaged class into .NET 2003

Introduction
There are several ways of using unmanaged code in C# and VB.NET. The most common approach is the use of dllimport, and is frequently used when using WinAPI32 - You declare the function you want to use by declaring the managed signature, which is equivalent with the unmanaged signature, and use the method as you would any other managed function.
The problem with this approach is the lack of OO. We are importing functions, not classes, and this is really an old fashioned approach. What if we have an MFC class we want to use? Or a complex class we have implemented.

A Solution
I will present one way of importing unmanaged classes. You will need the header files of the unmanaged code as well as the compiled unmanaged product.

Two steps must be followed:
1. Create a wrapper in C++ Unmanaged code from inside VS .NET environment.
2. Create a wrapper in C++ managed code for the wrapper from the first step.
When I say "wrapper" I mean a class that has the same interface of the original class, and implements all functions simply by calling the corresponding functions from the original class.
It is obvious that you can change the interface if you really want to, but for the beginner of us we will keep the same interface.

Lets say the original class looks like this:
-------------------------------------------

class __declspec(dllexport) MyUnmanagedVC6Class
{
public:
   MyUnmanagedVC6Class(int);
   void DoSomething(int,double);
}

-------------------------------------------

and it is located in MyUnmanagedVC6Header.h file, which we have.
Step 1

Now we open a blank solution, and add a new C++ MFC Class Library Project. Lets call it MyUnmanagedDotNetVCWrapper. We will implemenet a wrapper for MyUnmanagedVC6Class:
-------------------------------------------

#include "MyUnmanagedVC6Header.h"
class __declspec(dllexport) MyUnmanagedDotNetClass
{
private:
   MyUnmanagedVC6Class* _class;
public:
   MyUnmanagedDotNetClass(int x)
   {
      _class = new MyUnmanagedVC6Class(x);
   }
   void DoSomething(int x,double d)
   {
      _class->DoSomething(x,d);
   }
}

---------------------------------------------
This should be located in MyUnmanagedDotNetHeader.h.
Notice: If you have all the sources for the original dll you can open it in VisualStudio .NET, and it will convert it for you into a dll you can use for the next step. This can save you the time for the first wrapper.

Step 2
we add to the solution (it has to be the same solution) a new project: MFC C++ project, again unmanaged. Lets call it MyManagedDotNetVCWrapper. Now we right click on the name of the new project, and we change the property "Use Manage Extensions" to "Yes". This causes it to be like a managed environment (not exactly the same, but for our purposes this is what we need).
Now we add a reference to the dll we created in step 1: RightClick on References, and then choose "Add References". On the Projects Tab, choose the MyUnmanagedDotNetVCWrapper.dll .Now we add a new header to the project, called MyManagedDotNetHeader.h, with a class:
-------------------------------------------------------

#include "MyUnmanagedDotNetHeader.h"
namespace MyWrapperNamespace
{
   public __gc class MyManagedDotNetClass
   {
   private:
      MyUnmanagedDotNetClass __nogc * _class;
   public:
      MyManagedDotNetClass(int x)
      {
         _class = new MyUnmanagedDotNetClass(x);
      }
      void DoSomething(int x, double d)
      {
         _class->DoSomething(x,d);
      }
   };
}

-------------------------------------------
Notice the __gc (Garbage Collection) flag on the managed class, and the __nogc flag on the unmanaged pointer. Also notice the use of the namespace.
After you build this, you can now use the MyManagedDotNetVCWrapper.dll in all your managed projects, like C# and VB.NET, by adding a reference to it.

How-To Allow the User to Resize Controls on a Form at Runtime

Introduction
In my previous postI showed how to let the user move a TextBox on the form at run-time using the mouse.
I am going to take this one step further and show how to let the user resize the TextBox when clicking and draging on the borders of the TextBox.

The Example
I only implemented resizing the width (left/right) of the control (This is a regular TextBox - no meaning to resizing vertically). You can apply the same algorithm to program vertical resizing yourself. The code is in VB.NET.
-----------------------------------------------

Private _mouseDown As Boolean = False
Private _initialMouseX As Integer
Private _initialMouseY As Integer
Private _initialWidth As Integer

Private Enum Borders
   Left
   Right
   None
End Enum
Private _resizeType As Borders = Borders.None

Private Sub textBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles textBox1.MouseDown
   _mouseDown = true
   _resizeType = GetBorder(e.X, e.Y)
   _initialMouseX = e.X
   _initialMouseY = e.Y
   _initialWidth = textBox1.Width
End Sub

Private Function GetBorder(int x, int y) As Borders
   If (x<5 And x>-5) Then _
      Return Borders.Left
   If (x>textBox1.Width-10 And x<textBox1.Width+10) Then _
      Return Borders.Right
   Return Borders.None
End Function

Private Sub textBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles textBox1.MouseUp
   _mouseDown = false
   Me.Cursor = Cursors.Arrow
   _resizeType = Borders.None
End Sub

Private Sub textBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles textBox1.MouseMove
   If (Not _mouseDown) Then
      If (GetBorder(e.X, e.Y) <> Borders.None) Then
         Me.Cursor = Cursors.SizeWE
      Else
         Me.Cursor = Cursors.Arrow
      End If
      Return
   End If
   If (_resizeType = Borders.None) Then
      Dim deltaX As Integer = e.X - _initialMouseX
      Dim deltaY As Integer = e.Y - _initialMouseY
      textBox1.Left += deltaX
      textBox1.Top += deltaY
   Else
      Dim deltaX As Integer = e.X - _initialMouseX
      Select Case _resizeType
         Case Borders.Left:
            If (textBox1.Width - deltaX>0) Then
               textBox1.Left += deltaX
               textBox1.Width -= deltaX
            End If
      Case Borders.Right:
            If (_initialWidth + deltaX>0) Then _
               textBox1.Width = _initialWidth + deltaX
      End Select
   End If
End Sub

Private Sub textBox1_MouseLeave(sender As Object, e As EventArgs) Handles textBox1.MouseLeave
   Me.Cursor = Cursors.Arrow;
End Sub

--------------------------------------------
When the user click on the control we check if the mouse is on the border (GetBorder method) and sample the initial width of the control . The actual resize is done in the MouseMove event handler. It is done by changing the Width property of the control (calculated comparing the initial width).

Friday, October 21, 2005

How-to allow user to move a control on a form.

Introduction
Sometimes you may want the user to move controls on the form at run-time, same way you do it in the form's designer as a developer.
I will show a way to achieve this effect using mouse events. For the purpose of the demonstration I am using a TextBox, but you can apply this to any control with MouseDown, MouseUp and MouseMove event.
I am using VB.NET here.

The code
Drag a textBox to the form (textBox1) And add the code to the form:
----------------------------------------

Private _mouseDown As Boolean = False
Private _initialMouseX As Integer
Private _initialMouseY As Integer

Private Sub textBox1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles textBox1.MouseDown
   _mouseDown = True
   _initialMouseX = e.X
   _initialMouseY = e.Y
End Sub

Private Sub textBox1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles textBox1.MouseUp
   _mouseDown = False
End Sub

Private Sub textBox1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles textBox1.MouseMove
   If ( Not _mouseDown) Then Return
   Dim deltaX As Integer = e.X - _initialMouseX
   Dim deltaY As Integer = e.Y - _initialMouseY
   textBox1.Left += deltaX
   textBox1.Top += deltaY
End Sub

--------------------------------------
I am using the MouseDown event to store the initial position of the mouse, and to set a flag that when the mouse will move we want the control to move with it.
I am using the MouseUp event to release the flag (When moving the mouse the control will not move).
The MouseMove event is used to actually move the control. The current coordinates of the mouse is compared to the initial position and moving the control by setting the Left and Top properties. All this only if the mouse is down of course.

In the next postI will show how to let the user resize the control using the mouse.

Creating a Simple Server/Client Application With Remoting - A Step-By-Step Tutorial

In my previous post I explained some basic concepts regarding Remoting.NET. In this post I will set up a small example.
The demonstartion works for VS.NET 2003 using C#. I designed the sample to be very abstract in order for anyone to apply it to their best interest.

Step 1 - Creating the solution.
Create a blank solution, and add three projects to it: Server, Client (both Windows Applications), and Common (a class library - our shared assembly). Add a reference to Common from Server and from Client.

Step2 - Creating the interfaces.
Add to Common a file, and call it interfaces.cs .
The code is here:
------------------------------------

namespace Common
{
   public interface IObjectFactory
   {
      IShareableObject GetObject();
   }

   public interface IShareableObject
   {
      long X { get; }
      string Message {get;}
   }
}

----------------------------------------------
IObjectFactory is the interface for our Remote object. The client will know this interface and not the implementation of the object - It will be marshaled by reference
IShareableObject is the interface for the object we want to pass around the processes (In our case the client will get it from the server) - It will be marshaled by value.

Step 3 - Create the Serializable object.
Add to Common project a class called ShareableObject which implements IShareableObject. This is just an example of course.
---------------------------------------

using System;
namespace Common
{
   [Serializable()]
   public class ShareableObject:IShareableObject
   {
      private long _x;
      private string _msg;

      public ShareableObject(long x, string msg)
      {
         _x = x;
         _msg = msg;
      }
      public long X
      {
         get { return _x; }
      }
      public string Message
      {
         get { return _msg; }
      }
   }
}

--------------------------------------
Notice two things: The class is in the Common assembly meaning that the implementation will be familiar to both the client and the server; The class is tagged with the Serializable attribute, meaning it will be passed around processes.

Step 4: Create the Server
Add an object to the server called ObjectFactory which implements IObjectFactory. It should inherit from MarshalByRefObject:
--------------------------------------

using System;
using Common;
namespace Server
{
   public class ObjectFactory: MarshalByRefObject,IObjectFactory
   {
      public IShareableObject GetObject()
      {
         return new ShareableObject(10,"123");
      }
   }
}

--------------------------------------
Notice how we instanciate an object of type ShareableObject (From Step 3). It will be passed by value to the client. When the client will access ObjectFactory it will call the instance in the server through a proxy. When calling GetObject it will get the object and will be able to call its method and properties from the client's process.
Also notice how the method GetObject returns an interface, but creates some concrete class.

Add a new item to the Server project which is Aplication Configurion file and make it look like this:
--------------------------------------

<?xml version="1.0" encoding="utf-8">
   <configuration>
      <system.runtime.remoting>
         <application name="MyServer">
            <service>
               <wellknown mode="Singleton" type="Server.ObjectFactory, Server" objectUri="ObjectFactory.soap"/>
            </service>
            <channels>
               <channel ref="tcp" port="16784">
                  <serverProviders>
                     <formatter ref="binary" typeFilterLevel="Full"/>
                  </serverProviders>
                  <clientProviders>
                     <formatter ref="binary"/>
                  </clientProviders>
               </channel>
         </channels>
      </application>
   </system.runtime.remoting>
</configuration>

-----------------------------------------------
This Xml defines the Remoting configuration. We will read the file soon, but let me focus on some issues:
- The ApplicationName will be seen again in the client.
- We registered the ObjectFactory as a singleton. Without it the client will nbot be able to access the object.
- The port is configurable. Remember it for the client.
- We use here a tcp channel with a binary formatter.

Last, we need to change the Main method in the server to read the remoting configuration from the Xml file:
-----------------------------------------------

[STAThread]
static void Main()
{
   string fileName = "server.exe.config";
   RemotingConfiguration.Configure(fileName);
   Application.Run(new Form1());
}

----------------------------------------------
Look how easy it is to configure remoting this way (However, using configuration files has its disadvantages).

Step 5 - Create the Client.
Add an application configuration file to the client (same as server).
It should look like this:
----------------------------------------

<?xmlversion="1.0"encoding="utf-8"?>
<configuration>
   <system.runtime.remoting>
      <application name="MyClient.exe">
         <client>
            <wellknowntype="Common.IObjectFactory,
Common" url="tcp://localhost:16784/MyServer/
ObjectFactory.soap
"/>
         </client>
         <channels>
            <channel ref="tcp"port="0">
               <serverProviders>
                  <formatter ref="binary" typeFilterLevel="Full"/>
               </serverProviders>
               <clientProviders>
                  <formatter ref="binary"/>
               </clientProviders>
            </channel>
         </channels>
      </application>
   </system.runtime.remoting>
</configuration>

----------------------------------------
This is the client side configuration file. Pay attantion to the use of interface (IObjectFactory) instead of concrete class (the client does not have a reference to the concrete class), and the use of the server URI for the object.

Next we change the Main method in the client to look like this:
----------------------------------------

[STAThread]
static void Main()
{
   string fileName = "client.exe.config";
   RemotingConfiguration.Configure(fileName);
   Application.Run(new Form1());
}

----------------------------------------

Step 6 - Add a RemotingHelper class to Common project.
This will generically create the global instances in the server and will serve as a Factory for server classes. (This is taken from Ingo Rammar's excellent book "Advanced .NET Remoting")
----------------------------------------

using System;
using System.Collections;
using System.Runtime.Remoting;
namespace Common
{
   public class RemotingHelper
   {
      internal static bool _isInit = false;
      private static IDictionary _wellKnownTypes;

      public static object GetObject(Type type)
      {
         if (!_isInit)
            InitTypeCache();
         WellKnownClientTypeEntry entr = (WellKnownClientTypeEntry) _wellKnownTypes[type];
         if (entr==null)
            throw new RemotingException("Type not found");
         return Activator.GetObject(entr.ObjectType,entr.ObjectUrl);
      }
      private static void InitTypeCache()
      {
         _wellKnownTypes = new Hashtable();
         foreach(WellKnownClientTypeEntry entr in RemotingConfiguration.
GetRegisteredWellKnownClientTypes())
            _wellKnownTypes.Add(entr.ObjectType,entr);
         _isInit = true;
      }
   }
}

------------------------------------------------
This class is used by the client to retrieve classes that are marshaled by referenced (live n the server process). We use the GetObject method whenever we need such object. It is a very generic and powerful class.

That is it. We have all that we need.

Example of usage

Open Client Form1 (designer) and drag a button and two TextBoxes.
Double-click on the button, and add this code to it:
------------------------------------------------

private void button1_Click(object sender, EventArgs e)
{
   IObjectFactory fact = (IObjectFactory) RemotingHelper.GetObject(typeof(IObjectFactory));
   IShareableObject share = fact.GetObject();
   textBox1.Text = share.X.ToString();
   textBox2.Text = share.Message;
}

-------------------------------------------------
We get a proxy to the ObjectFactory object in the server using the RemotingHelper class. Then we retrieve a copy of the ShareableObject object by calling fact.GetObject method. Then we put the values of X and Message in the GUI. You will see 10 and 123 (look at Step 4 - ObjectFactory class).
If you put a breakpoint on the beginning of the event handler, you will see that fact is a Transparent Proxy (This is created automatically for us instead of creating a regular object). This is an indication that we are indeed using a remote object. The share object however is of type ShareableObject (You can see it as a regular class - it lives in the client process).

Calling Remoting Objects- Basic Concepts

MarshalByRef and Serializable
If you want to access an object in the server - that is to activate its methods and properties, you must inherit the class from MarshalByRefObject. This is because in the client you only have a reference to that object and a proxy is created for you.
However, sometimes you just want to pass information between the server and the client in the form of objects. This objects will be serialized, sent to the other process (maybe other computer) and de-serialized in the remote process. All the internal information in these kinds of objects is passed, and each method and property you call in the remote process is done in that process. For this kind of behavior you must either set the Serializable attribute, or implement the ISerializable interface.
So how can you pass an object by value between the server and the client? You need one object in the server to inherit from MarshalByRefObject with a method that returns the Serializable object, or that get a Serializable object as parameter, That way objects are passed by value between the client and the server.

Singlecall and Singleton
Now that the issue of MarshalByRef and Marshal by value is settled, lets investigate how we can tell the server not to keep state of marshaled by reference objects, or in other words Stateless objects. There are two types of ways the client can use Remote objects (marshaled by reference): Singleton or SingleCall. The first will create one instance that all the clients call. This object will be with state that will be kept between calls. The second will act as a service - It does not remember state between call, each time a client tries to call a method or property it calls a new instance in the server.

Shared Assemblies
Ok, now I will explain what shared assemblies are all about. In order for an object to be called remotely, and it does not matter whether it is marshaled by reference or serializable, both client and server must know of this object. Why? simply because the client (for example) can't access class X's method without it having a definition for the class and its method. So what we need is to have a dll (class library) with all the common objects to both server and clients - all the MarshalByReference and Serializable objects should be in that assembly. Both Server and Client executables should have a reference to that dll.

Using Interfaces For MarshalByRef Objects
But this is quite bad. We don't want the client to have the implementation of the server's objects and the other way around. That's when interfaces come to the rescue. In the shared assembly we will put only interfaces and classes that it is ok to share. The client and server will only know of this interfaces. The actual classes which implement the interfaces will be in the client/server assemblies, but the other will not know of them. So we don't need to deploy server classes in the client - just a dll with interface which is also deployed with the server. This discussion is not relevant to objects which are passed between processes by value (Only MarshalByRefObjects).

In the next post I will show a simple example of how to set up a server and client, with a shared assembly and configuration file, using interfaces and both MarshalByRefObjects and Serializable objects.

Thursday, October 20, 2005

Calculate a Cell value in a DataGrid based on the rows above it

Introduction
In the previous post I showed how to use DataGridColumnStyle in order to paint a cells color based on a condition.
Now I will show how to calculate a cell value based on the rows above it. In the previous example I used a Transaction table with two columns: Amount and Balance. The Amount column is the amount of money deposited to the account in the transaction. Balance should be a calculated column, based on the row above it. Each time the balance is equal to the previous balance plus the amount in the current transacion. What happens when the user changes a deposit in the grid? All the balance column values should be recalculated. What happens if the grid is sorted? If a row is deleted? Each time the balance should be recalculated.
But how do we know when is data being editted? The DataGrid itself won't help us. While it has a CurrentCellChanged event, it does not contain any event to notify us when the data is actually changed.
We will need to catch events in the DataSource itself. In our case the DataSource is a DataView. Even if we bind the DataGrid to a DataTable, it is actually bound to the DefaultView property of the DataTable. What events do we have? We have the DataTable.RowChanged and DataTable.RowDeleted events (The first one handles addition and changing of a row). Those are fired when a DataRow is changed in the underlying table. But what do we do when the DataGrid is sorted, or the DataView is filtered? We have the DataView.ListChanged event to handle those cases.

Code
Ok, so after we set the column styles, and set the DataSource we want to sign up for events:
------------------------------------

private void Form1_Load(object sender, System.EventArgs e)
{
   DataTable dt = new DataTable("Transactions");
   dt.Columns.Add(new DataColumn("Amount",typeof(Int32)));
   dt.Columns.Add(new DataColumn("Balance",typeof(Int32)));

   DataView dv = new DataView(dt);
   dataGrid1.DataSource = dv;

(...) // See first article

   //Setup events
   dv.ListChanged += new ListChangedEventHandler(dv_ListChanged);
   dt.RowChanged += new DataRowChangeEventHandler(dt_RowChanged);
   dt.RowDeleted += new DataRowChangeEventHandler(dt_RowChanged);
}

----------------------------------------------------
For simplicity, I declared an empty table and the columns. In real scenarios you will need to use an actual table from the database.

Now you see at the end of the event handler that I listen to three events:

  • dv.ListChanged will be raised whenever someone will add or remove rows from the GUI - or whenever someone will change the RowFilter or Sort property of the DataView (including sorting from inside the grid).
  • dt.RowChanged will be raised whenever someone changes a value in the row, or add a row to the table by code.
  • dt.RowDeleted - Whenever someone deletes the row from the table by code.

Here is the event handlers code:
--------------------------------------

private bool _lock = false;
private void dv_ListChanged(object sender, ListChangedEventArgs e)
{
   if (_lock)
      return;
   _lock = true;
   int balance = 0;
   foreach (DataRowView drv in (DataView)sender)
   {
      if (drv.Row["Amount"] == DBNull.Value)
         drv.Row["Amount"] = 0;
      balance+=(int)drv.Row["Amount"];
      drv.Row["Balance"] = balance;
   }
   _lock = false;
}

private void dt_RowChanged(object sender, DataRowChangeEventArgs e)
{
   if (_lock)
      return;
   _lock = true;
   int balance = 0;
   foreach (DataRow dr in ((DataTable)sender).Rows)
   {
      if (dr["Amount"] == DBNull.Value)
         dr["Amount"] = 0;
      balance+=(int)dr["Amount"];
      dr["Balance"] = balance;
   }
   _lock = false;
}

-----------------------------------------------
In both handlers we iterate on the sender (DataView or DataTable) and recalculate the Balance.
Notice the _lock member. I use this technic to prevent races between events. It happens a lot that by doing something inside the event handler other events are fired (For example, changes to the DataView will change the DataTable as well and vice versa). So by using the lock I prevent that from happening.
Also notice the use of one event handler for both RowChanged and RowDeleted.

How to set the ForeColor of the text in a cell based on a condition.

Introduction
In my previous post I showed how to use DataGridColumnStyles to customize the look of the DataGrid. I will show how to further customize the DataGrid.
Sometimes you need your DataGrid to behave in a very special way. For example: To put an image instead of text, or set some cells as Readonly. In order to acheive these kinds of behavior you will need to inherit from DataGridColumnStyle or one of its derived classes.
I will not show in this article every aspect of this method, but a small example.

Example
In the previous post I showed a Transaction table, with a Balance column. Lets say we want this column to show negative values in red, and positive numbers in black.

Code
We will derive from DataGridTextBoxColumn as follows:
------------------------------------

public class PaintedColumnStyle:DataGridTextBoxColumn
{
   protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle bounds, CurrencyManager source, int rowNum, System.Drawing.Brush backBrush, System.Drawing.Brush foreBrush, bool alignToRight)
   {
      foreBrush = new SolidBrush(GetColor(GetColumnValueAtRow(source,rowNum)));
      base.Paint (g, bounds, source, rowNum, backBrush, foreBrush, alignToRight);
   }

   private Color GetColor(object text)
   {
      if (text == DBNull.Value)
         return Color.Black;
      int num;
      try
      {
         if (text.GetType() == typeof(int) )
            num = (int) text;
         else
            num = int.Parse((string)text);
      }
      catch
      {
         return Color.Black;
      }
      if (num<0)
         return Color.Red;
      return Color.Black;
   }
}

------------------------------------
I override the Paint method and change the ForeBrush as needed. I guess you would have imagined a use of ForeColor property of some sort. Well, no such property and we need the help of the System.Drawing namespace (Brush class).

The method GetColumnValueAtRow is used to get the value in a specified row in the DataSource in the current column. It is implemented for us in the base class.
I coded GetColor in order to find out whether to draw the text in red or black.

Now, instead of using DataGridTextBoxColumn as in the previous example, we use the PaintedColumnStyle we have just created:
------------------------------------

(...) //see previous post
PaintedColumnStyle balanceColumn = new PaintedColumnStyle();
(...)
// balanceColumn - no change here
balanceColumn.HeaderText = "Balance";
balanceColumn.MappingName = "Balance";
balanceColumn.ReadOnly = true;
balanceColumn.Width = 75;

-------------------------------------

In the next article I will show how to calculate the Balance column based on the rows above it in the DataGrid.

How to use DataGridColumnStyles programatically

Introduction
Sometimes we need to do things in a DataGrid which is not supported automatically. For example: set a column in the DataGrid as Read-only. Or choose what columns in the DataTable to see.
In those cases we need to use DataGridTableStyle and DataGridColumnStyle.
As an introduction I will give a short example of how to use those in code.

Example
We have a DataTable called Transactions which describes transactions in a bank account. This table has three columns: ID, Amount, Balance. The Amount column represents the amount of money in the transaction. The Balance column represents the total money left in the account, it is calculated and should be read-only. The ID column is the primary key in the table and should not be shown to the user.

Code
Here is how I code this using DataGridTableStyle and DataGridColumnStyle:
----------------------------------------

private void Form1_Load(object sender, System.EventArgs e)
{
   //Create table
   DataTable dt = new DataTable("Transactions");
   dt.Columns.Add(new DataColumn("ID",typeof(Int32)));
   dt.Columns.Add(new DataColumn("Amount",typeof(Int32)));
   dt.Columns.Add(new DataColumn("Balance",typeof(Int32)));

   //Initialize objects
   DataGridTableStyle transactionTable = new DataGridTableStyle();
   DataGridTextBoxColumn amountColumn = new DataGridTextBoxColumn();
   DataGridTextBoxColumn balanceColumn = new DataGridTextBoxColumn();

   //Setting a DataView as the DataSource
   dataGrid1.BeginInit();
   DataView dv = new DataView(dt);
   dataGrid1.DataSource = dv;

   // transactionTable
   dataGrid1.TableStyles.AddRange(new DataGridTableStyle[] {transactionTable});
   transactionTable.DataGrid = dataGrid1;
   transactionTable.GridColumnStyles.AddRange(new DataGridColumnStyle[] {amountColumn,balanceColumn});
   transactionTable.MappingName = "Transactions"; // This is the name of the table you are binding to.

   // amountColumn
   amountColumn.HeaderText = "Amount"; // This is the text that is written in the Column Header. Leave empty to show the name of the column.
   amountColumn.MappingName = "Amount"; // This is the name of the    column.amountColumn.ReadOnly = false;
   amountColumn.Width = 75;

   // balanceColumn
   balanceColumn.HeaderText = "Balance";
   balanceColumn.MappingName = "Balance"; // This is the name of the column.
   balanceColumn.ReadOnly = true;
   balanceColumn.Width = 75;

   dataGrid1.EndInit();
}

------------------------------------
Few things are interesting:
  • MappingName - The name of the table/column as it appears in the data source.
  • HeaderText - You can format the header text of the column!!! You cannot do this without DataGridColumnStyle.
  • ReadOnly - You can set an entire column as read-only. The user will not be able to edit the column.
  • Width - You can set the default width of the column.
  • Very important what is NOT in the code: No ColumnStyle for the ID column. So this column will not be shown to the user (although it exists in the DataSource).
In the next article I will show how to paint a cell in the column based on a condition.

Passing Parameter to Thread

Problem
Threads in .NET must start a functions which is void() (return no values and gets no parameters). But what if we want to pass parameters to the thread?

Solution
The parameter will be stored as a private member of the class:
-------------------------------

public class MyClass{
   public void DoSomething()
   {
      Thread t = new Thread(new ThreadStart(DoSomethingInThread));
      _parameterForThread = 5;
      t.Start();
   }
   private int _parameterForThread = -1;
   private void DoSomethingInThread()
   {
      _parameterForThread ++;
   }
}

------------------------------------------

Alternative Solution

This is not so elegant, because we need to store local data in a member (which does not necessary represent the class's state).
So to take the concept one step further, we can put all the relevant code in another class:
------------------------------------------

public class MyThread
{
   public MyThread(int parameterForThread )
   {
      _parameterForThread = parameterForThread ;
   }

   private int _parameterForThread = -1;
   public void DoSomethingInThread()
   {
      _parameterForThread ++;
   }
}

public class MyClass
{
   public void DoSomething()
   {
      MyThread mt = new MyThread(5);
      Thread t = new Thread(new ThreadStart(mt.DoSomethingInThread));
      t.Start();
   }
}

------------------------------------------

Wednesday, October 19, 2005

How-to create a Main method in VB.NET

How-to create a Main method in VB.NET
In C# the designer automatically creates a Main method inside the first form. It looks like this:
--------------------------

[STAThread]
static void Main()
{
   Application.Run(new Form1());
}

--------------------------

In VB.NET however this is not the default behavior. If you need a Main method follow this steps:
1. In Solution Explorer right-click on the project name and select Properties.
2. In the General Tab (the one that is opened) you have Startup Object
3. Select either a form, or Sub Main option (in our case).
4. Add the following code somewhere in your code:
--------------------------------

<STAThread>_
Public Shared Sub Main()
{
   Application.Run(New Form1())
}

-------------------------------

How-to prevent an Application from running more than once.

How-to prevent an Application from running more than once.

In VS.NET 2003 I often need an application to run as Singleton, meaning - run only once. This is a typical behavior of servers. Unfortunately, there is no support for this in Framework 1.1 .

So here is an elegant solution. The code is in C#, but may be applied to VB.NET as well.

The Code - Option 1
This will prevent an application from running more than once:
--------------------------------------------

using System.Threading;
using System.Runtime.InteropServices;
public class Form1 : Form
{
(...)
   [STAThread]
   static void Main()
   {
      bool createdNew;
      Mutex m = new Mutex(true, "YourAppName", out createdNew);
      if (! createdNew)
      {
         // app is already running...
         MessageBox.Show("Only one instance of this application is allowed at a time.");
         return;
      }
      Application.Run(new Form1());
      // keep the mutex reference alive until the normal termination of the program
      GC.KeepAlive(m);
   }
}

------------------------------------------
This code is added to the Main method (In VB.NET you will need to create one, click here to see how).
Notice: Make sure that you set a unique name for the application instead of YourAppName in the mutex decleration in my code (or you will prevent other applications from running).

The Code - Option 2
The next section will close the PREVIOUS instance of the application:-------------------------------------------------

using System;
using System.ComponentModel;
using System.Diagnostics;

(...)
static void Main()
{
   // get the name of the current process
   Process currentProcess = Process.GetCurrentProcess();
   string currProcessName = currentProcess.ProcessName;
   // get all instances of the this application
   Process[] prevAppInstance = Process.GetProcessesByName(currProcessName);
   // kill all other instances of this application
   for(int i = 0 ; i {
      if(prevAppInstance[i].Id != currentProcess.Id)
      {
         prevAppInstance[i].Kill();
      }
   }
   // run the aplication
   Application.Run(new Form1());
}

-------------------------
In this case you will close the instance that is running and keep the new one running (sometimes this bevior is more appropriate).

For more discussion, click here

ASP.NET don't work even though IIS is installed.

ASP.NET don't work even though IIS is installed.
Today I needed to create a Web Application, but couldn't. I got a message that the IIS is not familiar with ASP.NET ver 1.1 .

This can be solved by:
1. Running Start->Run->cmd
2. cd C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322 (or your windows directory)
3. Running: aspnet_regiis.exe -i

Welcome

Hello All

I'm a 28 years old software and computers engineer. I have over 12 years of experience in programming. I live in Haifa, Israel, and currently I work at a large high-tech company as a software engineer.

In high school I learned to program in Basic. After a while I switched to Pascal and C. During my diploma studies I learnt Object Oriented programming and C++ (I even touched a bit of Java). In the last 3 years I am working intensively in the .NET environment (C# and VB.NET).

Today I experience the Visual Studio 2005 and Team System environment.

I know there is plenty of material about programming over the net. I hope to contribute my small portion.

Thanks, hope you find everything here useful.

Feel free to use everything here. Add links to my site if you wish.

Do not copy anything to other sites without adding link to here.

All the contents of the site belong to Yariv Hammer.