Find answers for the most frequently asked questions
Expand All Collapse All

For example, the ‘C:\WINNT\Microsoft.NET\Framework\v1.0.3705’ dir for the 1.0 framework version.

You can do so using PInvoke to call this native API method:


[C#]
[DllImport('mscoree.dll')] 
// Declaration
internal static extern void GetCORSystemDirectory([MarshalAs(UnmanagedType.LPTStr)]System.Text.StringBuilder Buffer,
	int BufferLength, ref int Length);
// Gets the path to the Framework directory.
System.Text.StringBuilder sb = new System.Text.StringBuilder(1024);
int size;
// returned value in size can be ignored
GetCORSystemDirectory(sb, sb.Capacity, ref size);

[VB.Net]
’ Declaration
Private Declare Function GetCORSystemDirectory Lib 'mscoree.dll' ( ByVal Buffer As System.Text.StringBuilder, ByVal BufferLength As Integer, ByRef Length As Integer) As Integer

’ Gets the path to the Framework directory.
Dim Path As New System.Text.StringBuilder(1024)
Dim Size As Integer
’ returned value in Size can be ignored
GetCORSystemDirectory(Path, Path.Capacity, Size)
Permalink

Compiled from the newsgroup posts by Andy Fish and Brian:

You can do this in the DragDrop event handler of your control:


[C#]
try
{
	//Use e.Data.GetData('UniformResourceLocator') to get the URL
    	System.IO.Stream ioStream=
                 	(System.IO.Stream)e.Data.GetData('FileGroupDescriptor');
    	byte[] contents = new Byte[512];
    	ioStream.Read(contents,0,512);
    	ioStream.Close();
    	StringBuilder sb = new StringBuilder();
	//The magic number 76 is the size of that part of the
	//FILEGROUPDESCRIPTOR structure before the filename starts - cribbed
	//from another usenet post.
    	for (int i=76; contents[i] != 0; i++) 
    	{
        		sb.Append((char)contents[i]);
    	}
    	if (!sb.ToString(sb.Length-4,4).Equals('.url'))
    	{
        		throw new Exception('filename does not end in ’.url’');
    	}
    	filename = sb.ToString(0,sb.Length-4);

}
catch(Exception ex)
{
    	MessageBox.Show(ex.ToString());
}

[VB.Net]
Try
	’Use e.Data.GetData('UniformResourceLocator') to get the URL
    	System.IO.Stream ioStream=
                 	CType(e.Data.GetData('FileGroupDescriptor'), System.IO.Stream)
    	Dim contents() As Byte =  New Byte(512) {} 
    	ioStream.Read(contents,0,512)
    	ioStream.Close()
    	Dim sb As StringBuilder =  New StringBuilder() 
 	
	’The magic number 76 is the size of that part of the
	’FILEGROUPDESCRIPTOR structure before the filename starts - cribbed
	’from another usenet post.
    	Dim i As Integer
    	For  i = 76 To contents(i)  0 Step  i + 1
        		sb.Append(CType(contents(i), Char))
    	Next
    	If Not sb.ToString(sb.Length-4,4).Equals('.url') Then
        		Throw New Exception('filename does not end in ’.url’')
    	End If
    	filename = sb.ToString(0,sb.Length-4)
Catch ex As Exception
    	MessageBox.Show(ex.ToString())
End Try
Permalink

This is possible in this case: Say your object graph contains an object A, which has a reference to the object B. Then while deserializing A, the reference B might not be initialized yet. This is because while deserializing, references are deserialized one at a time and when A is deserialized, B might not have been deserialized, yet. You should follow the workaround as follows:


[C#]
protected MyCustomConstrucotr(SerializationInfo info, StreamingContext context)
{
	this.cachedRefToB = (B)info.GetValue('B', typeof(B));
	// At this point cachedRefToB might not be initialized.
}
// But when this method gets called, after complete serialization, the cachedRefToB will be initialized
void IDeserializationCallback.OnDeserialization(object sender)
{
	// At this point cachedRefToB will be initialized.
}

[VB.Net]
protected MyCustomConstrucotr(ByVal info As SerializationInfo, ByVal context As StreamingContext) As Protected
	Me.cachedRefToB = CType(info.GetValue('B', Type.GetType(B)), B)
	’ At this point cachedRefToB might not be initialized.
End Function

’ But when this method gets called, after complete serialization, the cachedRefToB will be initialized
’ Your class should implement IDeserializationCallback
Sub OnDeserialization(ByVal sender As Object) as IDeserializationCallback.OnDeserialization
	’ At this point cachedRefToB will be initialized.
End Sub
Permalink

Here is how it can be done. This takes into account all docked controls (including menus) in the mdi parent form.


[C#]
		private void FillActiveChildFormToClient()
		{
			Form child = this.ActiveMdiChild;
			Rectangle mdiClientArea = Rectangle.Empty;
			foreach(Control c in this.Controls)
			{
				if(c is MdiClient)
					mdiClientArea = c.ClientRectangle;
			}
			child.Bounds = mdiClientArea;
		}

[VB.Net]
		Private  Sub FillActiveChildFormToClient()
			Dim child As Form =  Me.ActiveMdiChild 
			Dim mdiClientArea As Rectangle =  Rectangle.Empty 
			Dim c As Control
			For Each c In Me.Controls
				If TypeOf c Is MdiClient Then
					mdiClientArea = c.ClientRectangle
				End If
			Next
			child.Bounds = mdiClientArea
		End Sub
Permalink

You can do so using the native GetGuiResources api. Here is a sample:


		/// 
		/// uiFlags: 0 - Count of GDI objects
		/// uiFlags: 1 - Count of USER objects
		/// - Win32 GDI objects (pens, brushes, fonts, palettes, regions, device contexts, bitmap headers) 
		/// - Win32 USER objects:
		///	  - WIN32 resources (accelerator tables, bitmap resources, dialog box templates, font resources, menu resources, raw data resources, string table entries, message table entries, cursors/icons) 
		///   - Other USER objects (windows, menus) 
		/// 
		[DllImport('User32')]
		extern public static int GetGuiResources(IntPtr hProcess, int uiFlags);

		public static int GetGuiResourcesGDICount()
		{
			return GetGuiResources(Process.GetCurrentProcess().Handle, 0);
		}

		public static int GetGuiResourcesUserCount()
		{
			return GetGuiResources(Process.GetCurrentProcess().Handle, 1);
		}

		’ uiFlags: 0 - Count of GDI objects
		’ uiFlags: 1 - Count of USER objects
		’ - Win32 GDI objects (pens, brushes, fonts, palettes, regions, device contexts, bitmap headers) 
		’ - Win32 USER objects:
		’	  - WIN32 resources (accelerator tables, bitmap resources, dialog box templates, font resources, menu resources, raw data resources, string table entries, message table entries, cursors/icons) 
		’  - Other USER objects (windows, menus) 
		’ 
		 _ 
		extern Public static Integer GetGuiResources(IntPtr hProcess, Integer uiFlags)
 
		Public Shared Function GetGuiResourcesGDICount() As Integer
			Return GetGuiResources(Process.GetCurrentProcess().Handle,0)
		End Function
 
		Public Shared Function GetGuiResourcesUserCount() As Integer
			Return GetGuiResources(Process.GetCurrentProcess().Handle,1)
		End Function
Permalink

Microsoft has confirmed that calling EnableVisualStyles in the main method resulting in some ImageList corruption is a bug. There however seems to be a workaround posted by Martin Robins in the newsgroup which worksaround this issue:


public virtual void Main() { 
Application.EnableVisualStyles(); 
// Calling DoEvents after the above method call seems to fix this issue:
Application.DoEvents(); 
Application.Run(new Form1()); 
}
Permalink

The Environment class in the System namespace has this information.

[C#]
	string versionText = Environment.OSVersion.Version.ToString();

[VB.NET]
	Dim versionText As String = Environment.OSVersion.Version.ToString()

The Version property has member properties such as Major and Minor that give additional information.

Note that XP is windows version 5.1

Permalink

Check the the property Form.DesignMode.

But, note that when in Visual Inheritance mode (designing a derived form), your Control’s DesignMode property will be true when the base form’s constructor gets executed in the design-time.

To workaround this, you could check if the app in which your control is running is not devenv.exe, as follows:


string exePath = Application.ExecutablePath;
exePath = exePath.ToLower();
if(Application.ExecutablePath.ToLower().IndexOf('devenv.exe') > -1)
{
	// Then you are running in vs.net.
}				
Permalink

You can do so using the System.Diagnostics.Process.Start method as follows:


// Just specifying the document name will open the appropriate app based on system settings.
Process.Start('Http://msdn.microsoft.com') 
// Open a word document in Word.
Process.Start('AWordDocument.doc')
// Or open the app directly:
Process.Start() 
Permalink

The best place to ensure a particular height/width for you control is in the SetBoundsCore override of your Control, as follows:


		protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
		{
			int prefHeight = this.GetPreferredHeight();
			// Ensure that the height is atleast as big as prefHeight
			if(height < prefHeight)
				height = prefHeight;

			base.SetBoundsCore(x, y, width, height, specified);
		}

	Protected Overrides  Sub SetBoundsCore(ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer, ByVal specified As BoundsSpecified)
			Dim prefHeight As Integer =  Me.GetPreferredHeight() 
			’ Ensure that the height is atleast as big as prefHeight
			If height < prefHeight Then
				height = prefHeight
			End If
 
			MyBase.SetBoundsCore(x, y, width, height, specified)
		End Sub
Permalink

Your main form is an object of type System.Windows.Forms.Form. Use its Close method to exit the application. If you wish to Exit from a Form’s constructor, this will not work. A workaround is to set a boolean flag that you can later check in the Form’s Load method to call Close if required.

Another way is to use the Application.Exit() method.

Permalink

First keep track of which control is showing the ContextMenu by listening to the menu’s Popup event and querying for the SourceControl.

Then when you are ready to cancel the popup, do as follows:


[C#]
		[DllImport('user32.dll', CharSet=CharSet.Auto)]
		extern internal static IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

		private void Timer_Tick(object sender, EventArgs e)
		{
			if(menuSourceControl != null)
				SendMessage(menuSourceControl.Handle, 0x001F/*WM_CANCELMODE*/, IntPtr.Zero, IntPtr.Zero);

		}

[VB.Net]
		 _ 
		extern internal static IntPtr SendMessage(IntPtr hWnd, Integer msg, IntPtr wParam, IntPtr lParam)
 
		Private  Sub Timer_Tick(ByVal sender As Object, ByVal e As EventArgs)
			If Not menuSourceControl Is Nothing Then
				SendMessage(menuSourceControl.Handle, 0x001F, IntPtr.Zero, IntPtr.Zero)
			End If
 
		End Sub

Permalink

You will have to first provide some space in the NC area by setting the WS_BORDER flag in CreateParams and then draw the border yourself by listening to the WM_NCPAINT message in your Control, as follows:


		protected override CreateParams CreateParams
		{
			get 
			{
				System.Windows.Forms.CreateParams cp = base.CreateParams;
				if(this.needFlatBorder)
				{
					cparams.ExStyle &= ~512 /*WS_EX_CLIENTEDGE*/;
					cparams.Style &= ~8388608 /*WS_BORDER*/;
					cp.Style |= 0x800000; // WS_BORDER
				}
			}
		}

		protected override void WndProc(ref Message m)
		{
			if(m.Msg == 133/*WM_NCPAINT*/)
			{
				this.DrawFlatNCBorder(ref m);
			}
			base.WndProc(ref m);
		}

		private void DrawFlatNCBorder(ref Message msg)
		{
			IntPtr hRgn1 = (IntPtr) msg.WParam; 
			// The update region is clipped to the window frame. When wParam is 1, the entire window frame needs to be updated.

			IntPtr hdc = NativeMethods.GetDCEx(msg.HWnd, hRgn1, 1/*DCX_WINDOW*/|0x0020/*DCX_PARENTCLIP*/);
			if (hdc != IntPtr.Zero)
			{
				using (Graphics g = Graphics.FromHdc(hdc))
				{

					Rectangle bounds = new Rectangle(0,0,this.Width,this.Height);
			
					ControlPaint.DrawBorder(g,bounds,this.borderColor,ButtonBorderStyle.Solid);

					// create a clipping region for remaining parts to be drawn excluding
					// the border we did just drew
					bounds.Inflate(-1, -1);
					IntPtr hRgn2 = NativeMethods.CreateRectRgn(bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);

					if(hRgn2 == (IntPtr)1)
					{
						// Provide a new clipping region.
						msg.WParam = (IntPtr) hRgn2;
					}
					else
					{
						// combine with existing clipping region.
						NativeMethods.CombineRgn(hRgn1, hRgn1, hRgn2, NativeMethods.RGN_AND);
						NativeMethods.DeleteObject(hRgn2);
					}
				}

				msg.Result = (IntPtr) 1;
				NativeMethods.ReleaseDC(msg.HWnd, hdc);
		
			}			
			Invalidate();
		}
Permalink

You can do so as follows by overriding the CreateParams property in your Control. The advantage with this approach is that drawing is handled by the system as soon as you set the flag below.


		protected override CreateParams CreateParams
		{
			get
			{
				CreateParams cparams;

				cparams = base.CreateParams;

				if(this.need3DBorder)
				{
					cparams.ExStyle &= ~512;
					cparams.Style &= ~8388608 /*WS_BORDER*/;
					cparams.ExStyle = cparams.ExStyle | 512 /*WS_EX_DLGFRAME*/;
				}
				return cparams;
			}

		}

Permalink

In Usenet posts, MS has acknowledged this bug. The problem is essentially that any time the visibility changes on a CheckedListBox, it loses its previous selections. Naturally this happens all the time in tab controls when changing tabs.

This derived Control saves it’s state while getting hidden and reloads it while getting shown:


[C#]
# region Workaround for CheckedListBox bug
		//////////////////////////////////////////////////////////////////////
		// When CheckedList box becomes invisible (e.g. when the tab page
		// containing this control is overlapped with another tab page),
		// checked state of the items are getting lost. This workaround will
		// fix this problem
		//////////////////////////////////////////////////////////////////////

		private bool[] isItemChecked;
		protected override void OnDataSourceChanged(EventArgs e)
		{
			base.OnDataSourceChanged(e);

			int cnt = this.Items.Count;
			isItemChecked = new Boolean[cnt];
			for(int i = 0; i < cnt; i++)
			{
				isItemChecked[i] = GetItemChecked(i);
			}
		}

		protected override void OnItemCheck(ItemCheckEventArgs e)
		{
			base.OnItemCheck(e);
			isItemChecked[e.Index] = (e.NewValue == CheckState.Checked);
		}

		protected override void OnVisibleChanged(EventArgs e)
		{
			base.OnVisibleChanged(e);

			if (this.Visible == true)
			{
				// Reset the checked states when it becomes visible.
				for(int i =0; i < this.Items.Count; i++)
				{
					SetItemChecked(i, isItemChecked[i]);
				}
			}
		}
#endregion


[VB.Net]
Public Class MyCheckedListBox
   Inherits CheckedListBox
    ’////////////////////////////////////////////////////////////////////
    ’ When CheckedList box becomes invisible (e.g. when the tab page
    ’ containing this control is overlapped with another tab page),
    ’ checked state of the items are getting lost. This workaround will
    ’ fix this problem
    ’////////////////////////////////////////////////////////////////////
   Private isItemChecked() As Boolean
   
   Protected Overrides Sub OnDataSourceChanged(e As EventArgs)
      MyBase.OnDataSourceChanged(e)
      
      Dim cnt As Integer = Me.Items.Count
      isItemChecked = New [Boolean](cnt) {}
      Dim i As Integer
      For i = 0 To cnt - 1
         isItemChecked(i) = GetItemChecked(i)
      Next i
   End Sub ’OnDataSourceChanged
   
   
   Protected Overrides Sub OnItemCheck(e As ItemCheckEventArgs)
      MyBase.OnItemCheck(e)
      isItemChecked(e.Index) = e.NewValue = CheckState.Checked
   End Sub ’OnItemCheck
   
   
   Protected Overrides Sub OnVisibleChanged(e As EventArgs)
      MyBase.OnVisibleChanged(e)
      
      If Me.Visible = True Then
         ’ Reset the checked states when it becomes visible.
         Dim i As Integer
         For i = 0 To (Me.Items.Count) - 1
            SetItemChecked(i, isItemChecked(i))
         Next i
      End If
   End Sub ’OnVisibleChanged

End Class ’MyCheckedListBox 

(Contributed by Eric and Reddy Duggempudi in Syncfusion Windows Forms FAQ forums).

Permalink

The .Net framework libraries does not provide you an API to query for the focused Control. You have to invoke a windows API to do so:


[C#]
public class MyForm : Form
{
		[DllImport('user32.dll', CharSet=CharSet.Auto, CallingConvention=CallingConvention.Winapi)] 
		internal static extern IntPtr GetFocus();

		private Control GetFocusedControl()
		{
			Control focusedControl = null;
			// To get hold of the focused control:
			IntPtr focusedHandle = GetFocus();
			if(focusedHandle != IntPtr.Zero)
				// Note that if the focused Control is not a .Net control, then this will return null.
				focusedControl = Control.FromHandle(focusedHandle);
			return focusedControl;
		}
}

[VB.Net]
Public Class Form1

’ Declare the GetFocused method here:
     _
    Public Shared Function GetFocus() As IntPtr
    End Function


    Private Function GetFocusedControl() As Control
        Dim focusedControl As Control = Nothing
        ’ To get hold of the focused control:
        Dim focusedHandle As IntPtr = GetFocus()
        If IntPtr.Zero.Equals(focusedHandle) Then
            ’ Note that if the focused Control is not a .Net control, then this will return null.
            focusedControl = Control.FromHandle(focusedHandle)
        End If
        Return focusedControl
    End Function

End Class
Permalink

In C#, you can do as follows:


		// Use a custom Delegate to hold your subscribers
		private EventHandler myHandlers;
		// Control Click event firing, for example.
		public new event EventHandler Click
		{
			add
			{
				this.myHandlers += value;
			}
			remove
			{
				this.myHandlers -= value;
			}
		}

		protected override void OnClick(EventArgs e)
		{
			// First let my derived classes receive the Click event.
			foreach(Delegate d in this.myHandler.GetInvocationList())
			{
				if(d.Target == this)
				{
					d.DynamicInvoke(new object[]{this, e});
					break;
				}
			}
			// Then let other subscribers receive the Click event.
			foreach(Delegate d in this.myHandler.GetInvocationList())
			{
				if(d.Target != this)
					d.DynamicInvoke(new object[]{this, e});
			}

		}
Permalink

In C#, you can do as follows:


		// In a Control derived class, for example, first store the handlers in a custom list.
		private EventHandler myHandlers;
		public new event EventHandler Click
		{
			add
			{
				this.myHandlers += value;
			}
			remove
			{
				this.myHandlers -= value;
			}
		}

		// This method will specify whether a particular delegate is subscribed.
		public bool IsSubscribed(Delegate del)
		{
			System.Delegate[] delegates = this.myHandlers.GetInvocationList();
			foreach(Delegate d in delegates)
			{
				if(d == del)
					return true;
			}
			return false;
		}

		// Fire the Click event by parsing through your delegate list.
		protected override void OnClick(EventArgs e)
		{
			// First let my derived classes receive the Click event.
			foreach(Delegate d in this.myHandlers.GetInvocationList())
			{
				d.DynamicInvoke(new object[]{this, e});
			}
		}

You can then find our if a delegate is subscribed as follows:


// myControl is an instance of the above derived class.
bool subscribed = this.myControl.IsSubscribed(new EventHandler(this.myControl_Clicked));
Permalink

Here are some snippets. (Courtesy of Michael Lang)

[C#]
	DataTable list = new DataTable();
	list.Columns.Add(new DataColumn('Display', typeof(string)));
	list.Columns.Add(new DataColumn('Id', typeof(int)));
	list.Rows.Add(list.NewRow());
	list.Rows.Add(list.NewRow());
	list.Rows.Add(list.NewRow());
	list.Rows[0][0] = 'one';
	list.Rows[0][1] = 1;
	list.Rows[1][0] = 'two';
	list.Rows[1][1] = 2;
	list.Rows[2][0] = 'three';
	list.Rows[2][1] = 3;
	comboBox1.DataSource = list;
	comboBox1.DisplayMember = 'Display';
	comboBox1.ValueMember = 'Id';

[VB.NET]
	Dim list As New DataTable()
	list.Columns.Add(New DataColumn('Display', GetType(String)))
	list.Columns.Add(New DataColumn('Id', GetType(Integer)))
	list.Rows.Add(list.NewRow())
	list.Rows.Add(list.NewRow())
	list.Rows.Add(list.NewRow())
	list.Rows(0)(0) = 'one' ’
	list.Rows(0)(1) = 1 ’
	list.Rows(1)(0) = 'two' ’
	list.Rows(1)(1) = 2 ’
	list.Rows(2)(0) = 'three' ’
	list.Rows(2)(1) = 3 ’
	comboBox1.DataSource = list
	comboBox1.DisplayMember = 'Display'
	comboBox1.ValueMember = 'Id'
Permalink

You can call stored procedures in basically the same manner as executing other SQL commands.

When creating the SqlCommand, set the query string to be the name of the stored procedure, and then set the CommandType to be CommandType.StoredProcedure.


if(sqlConn.State == ConnectionState.Closed)sqlConn.Open();

SqlCommand cmd = new SqlCommand('sp_my_stored_procedure',sqlConn);
cmd.CommandTimeout = 180;
cmd.CommandType = CommandType.StoredProcedure;

After you setup the command type, you need to pass in any parameters required for the stored procedure. Here is an example of one input and one output parameter.


SqlParameter parm;

parm = cmd.Parameters.Add(new SqlParameter('@oid', SqlDbType.VarChar,50)); 
parm.Direction = ParameterDirection.Input; 
cmd.Parameters['@oid'].Value = OrderID;

parm = cmd.Parameters.Add(new SqlParameter('@custName', SqlDbType.VarChar,50)); 
parm.Direction = ParameterDirection.Output; 

If the stored procedure is returning a selection query at the end, you can fill your DataSet and retrieve any tables.


SqlDataAdapter tempDA = new SqlDataAdapter();
tempDA.TableMappings.Add('your mapping','your mapping');
tempDA.SelectCommand = cmd;
DataSet dataSet1 = new DataSet();
tempDA.Fill(dataSet1);
DataTable resultTable = dataSet1.Tables[0];

Or, if no tables are being returned, you can execute the command as a non-query


cmd.ExecuteNonQuery();
Permalink

This behavior can be seen when you embedded a control like a textbox or combobox in your derived GridColumnStyle. If you press the tabkey slowly, you may see the cell get focus on the downkey and the cell lose focus on the upkey. One way to avoid this problem is to subclass the embedded control, and override its WndProc method, ignoring the KeyUp.

[C#]
public class MyCombo : ComboBox
{
         private const int WM_KEYUP = 0x101;

         protected override void WndProc(ref System.Windows.Forms.Message m)
         {
                  if(m.Msg == WM_KEYUP)
                  {
                           return;  //ignore the keyup
                  }
                  base.WndProc(ref m);
         }
}

[VB.NET]
Public Class MyTextBox
	Inherits TextBox
	Private WM_KEYUP As Integer = &H101
 
	Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
		If m.Msg = WM_KEYUP Then
			Return ’ignore the keyup
		End If
		MyBase.WndProc(m)
	End Sub ’WndProc
End Class ’MyTextBox

Permalink

There are two ways in which this can be done. The first way is to use the provided Public assembly folder that is installed with VS.Net.

This folder is: ‘C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\PublicAssemblies’

All assemblies in this folder will be picked up by the ‘Add Reference’ dialog under the ‘.NET’ tab, and the ‘Customize Toolbox’ under the ‘.NET Framework Components’ tab.

Now, you are not limited to using this folder. You can specify your own public assembly folder by adding a key to the registry.

If you look at the following key:
‘HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.0\AssemblyFolders’, you will see a subkey named ‘PublicAssemblies’. This is where the path above is specified as a public assembly folder. To add your own folder, create a key (e.g. MyAssemblies), and set the default value to be the desired path.

Permalink

The version information needs to be set with the ‘AssemblyVersion’ attribute for each project. However, this attribute does not need to be specified in the project’s AssemblyInfo file. You can create a separate file with the ‘AssemblyVersion’ attribute that is shared across projects that you wish to keep in sync. This file can either be shared via VSS, or by including the file as a link in the projects.

Permalink

This is because of a bug in the .net framework. When tooltips are set on a control that hosts other controls within it (like the numeric updown), tooltips are not shown on those child controls.

To workaround this issue, do the following in code:


[C#]
foreach(Control c in this.numericUpDown1.Controls)
{
	this.tooltip.SetToolTip(c, 'mytooltip');
}

[VB.Net]
Dim c As Control
For Each c In Me.numericUpDown1.Controls
	Me.tooltip.SetToolTip(c, 'mytooltip')
Next
Permalink

If you have added a table style to your datagrid (so individual column styles have been generated), then you can use code such as this to set the Format property of the particular column style.

[C#]
	//add format col 3 columnstyle where column 3 holds a date...

	DataGridTextBoxColumn dgtbc;
	dgtbc = dataGrid1.TableStyles[0].GridColumnStyles[3] as DataGridTextBoxColumn;

	if(dgtbc != null)
	 	dgtbc.Format = 'g'; // or 'u' or whatever format you want to see

[VB.NET]
	’add format col 3 columnstyle where column 3 holds a date...

	Dim dgtbc as DataGridTextBoxColumn 
	dgtbc = CType(dataGrid1.TableStyles(0).GridColumnStyles(3),  DataGridTextBoxColumn)

	If Not dgtbc is Nothing Then
	 	dgtbc.Format = 'g'  ’ or 'u' or whatever format you want to see
	End If
Permalink

The framework automatically resizes the form if the current Font size during runtime is different from the font size in design-time. It however doesn’t auto size when the resolution changes. But it should be easy for you to accomplish. You could derive a custom Form, provide a ‘ScreenResolutionBase’ property that could return the current screen resolution (Screen.PrimarScreen.Bounds will give you this). This value will get serialized in code during design time. Then during runtime in the Form’s OnLoad you could check for the current screen resolution and resize the Form appropriately.

Permalink

The XmlNode.AppendChild restricts you to add XmlNodes originated in the same XmlDocument. So, to do the above, here is a sample workaround:


[C#]
		// destParent and sourceParent are from different XmlDocuments.
		// This method will append the children of sourceParent to the destParent’s children.
		public static void TransferChildren(XmlDocument destDoc, XmlNode destParent, XmlNode sourceParent)
		{
			// Create a temporary element into which we will add the children.
			XmlElement tempElem = destDoc.CreateElement('Temp');
			tempElem.InnerXml = sourceParent.InnerXml;

			foreach(XmlNode node in tempElem.ChildNodes)
				destParent.AppendChild(node);
		}

[VB.Net]
		’ destParent and sourceParent are from different XmlDocuments.
		’ This method will append the children of sourceParent to the destParent’s children.
		Public Static  Sub TransferChildren(ByVal destDoc As XmlDocument, ByVal destParent As XmlNode, ByVal sourceParent As XmlNode)
			’ Create a temporary element into which we will add the children.
			Dim tempElem As XmlElement =  destDoc.CreateElement('Temp') 
			tempElem.InnerXml = sourceParent.InnerXml
 
			Dim node As XmlNode
			For Each node In tempElem.ChildNodes
				destParent.AppendChild(node)
			Next
		End Sub
Permalink

When the Form.KeyPreview property is set to true, the Form’s KeyPress, KeyDown and KeyUp events will be fired even before the Control with the focus’ corresponding events. You may choose to forward these message to the Control after processing them in the Form’s event handlers (this happens by default) or set the e.Handled property to true (in the event argument) to prevent the message from being sent to the Control with focus.

Permalink

Here is some code that will do it.


[C#]
	internal class NativeMethods
	{
		[DllImport('user32.dll')]
		public extern static IntPtr GetDesktopWindow();

		[System.Runtime.InteropServices.DllImport('user32.dll')]
		public static extern IntPtr GetWindowDC(IntPtr hwnd);

		[System.Runtime.InteropServices.DllImport('gdi32.dll')]
		public static extern UInt64 BitBlt
			(IntPtr hDestDC,
			int x,
			int y,
			int nWidth,
			int nHeight,
			IntPtr hSrcDC,
			int xSrc,
			int ySrc,
			System.Int32 dwRop);
	}

		// Save the screen capture into a jpg
		public void SaveScreen()
		{
			Image myImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
				Screen.PrimaryScreen.Bounds.Height);
			Graphics gr1 = Graphics.FromImage(myImage);
			IntPtr dc1 = gr1.GetHdc();
			IntPtr dc2 = NativeMethods.GetWindowDC(NativeMethods.GetDesktopWindow());
			NativeMethods.BitBlt(dc1, 0, 0, Screen.PrimaryScreen.Bounds.Width,
				Screen.PrimaryScreen.Bounds.Height, dc2, 0, 0, 13369376);
			gr1.ReleaseHdc(dc1);
			myImage.Save('screenshot.jpg', ImageFormat.Jpeg);
		}

[VB.Net]
Friend Class NativeMethods
      
        _
      Public Shared Function GetDesktopWindow() As IntPtr
        End Function

         _
        Public Shared Function GetWindowDC(ByVal hwnd As IntPtr) As IntPtr
        End Function

         _
        Public Shared Function BitBlt(ByVal hDestDC As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hSrcDC As IntPtr, ByVal xSrc As Integer, ByVal ySrc As Integer, ByVal dwRop As System.Int32) As UInt64
        End Function
End Class ’NativeMethods

  ’Save the screen capture into a jpg
      Private Sub SaveScreen()
         Dim myImage = New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
         Dim gr1 As Graphics = Graphics.FromImage(myImage)
         Dim dc1 As IntPtr = gr1.GetHdc()
         Dim dc2 As IntPtr = NativeMethods.GetWindowDC(NativeMethods.GetDesktopWindow())
         NativeMethods.BitBlt(dc1, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, dc2, 0, 0, 13369376)
         gr1.ReleaseHdc(dc1)
         myImage.Save('screenshot.jpg', ImageFormat.Jpeg)
      End Sub ’SaveScreen
Permalink

Override WndProc in your Control and do the following. You should then listen to keyup and show the context menu yourself.


[C#]
protected override void WndProc(ref Message m)
{
	if(m.Msg == 0x7b /*WM_CONTEXTMENU*/ )
	{
		return;
	}
	if(m.Msg == 0x101 /*WM_KEYUP*/)
	{
		Keys keys = (Keys)m.WParam.ToInt32();
		// Prevent this key from being processed.
		if(keys == Keys.Apps)
			return;
	}
	base.WndProc(ref m);
}

[VB.Net]
Protected Overrides  Sub WndProc(ByRef m As Message)
	If m.Msg = 0x7b Then ’WM_CONTEXTMENU
		Return
	End If
	If m.Msg = 0x101 Then ’WM_KEYUP
		Dim keys As Keys = CType(m.WParam.ToInt32(), Keys)
		’ Prevent this key from being processed.
		If keys = Keys.Apps Then
			Return
		End If
	End If
	MyBase.WndProc( m)
End Sub
Permalink

You need to use a second instance of VS.NET to debug the one that’s running the code.

Put your control on a from in VS.NET Start a 2nd Vs.Net Choose the Debug menu >> Processes … Double click ‘devenv.exe’ and choose ‘Common Language Runtime’ as the types of debugging Open your code file, set your breakpoint, and you’re debugging.

Posted by Shawn Burke of MSFT in microsoft.public.dotnet.framework.windowsforms.

Permalink

The method DataGrid.IsSelected can tell you if a particular row is selected.
So, you could use IsSelected in a loop through all your rows to finds if
multiple rows have been selected. Depending upon the size of your datagrid,
this may be a viable solution. If not, you could track the selections
yourself by monitoring the key actions and the mouse actions. This would be
more work. Thanks to John Hughes to the suggestion to use the dataview.

[C#]
public ArrayList GetSelectedRows(DataGrid dg)
{
	ArrayList al = new ArrayList();
	CurrencyManager cm = (CurrencyManager)this.BindingContext[dg.DataSource, dg.DataMember];    
    	DataView dv = (DataView)cm.List;
    
	for(int i = 0; i < dv.Count; ++i)
	{
		if(dg.IsSelected(i))
			al.Add(i);
	}
	return al;
}

private void button1_Click(object sender, System.EventArgs e)
{
	string s = 'Selected rows:';
	foreach(object o in GetSelectedRows(dataGrid1))
	{
		s+=''+o.ToString();
	}
	MessageBox.Show(s);
}

[VB.NET]
	Public Function GetSelectedRows(ByVal dg As DataGrid) As System.Collections.ArrayList
		Dim al As New ArrayList()

		Dim cm As CurrencyManager = Me.BindingContext(dg.DataSource, dg.DataMember)
		Dim dv As DataView = CType(cm.List, DataView)
   
		Dim i As Integer
		For i = 0 to dv.Count - 1
			If dg.IsSelected(i) Then
				al.Add(i)
			End If
		End Next
		Return al
	End Function ’GetSelectedRows
	
	 Private Sub button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
		 Dim s As String = 'Selected rows:'
		Dim o As Object
		For Each o In GetSelectedRows(dataGrid1)
			s += ' ' + o.ToString()
		Next o
		MessageBox.Show(s)
	 End Sub ’button1_Click
Permalink

As the message suggests, the code is calling Control.DataBindings.Add twice with what amounts to the same parameters.

One way this might happen is if you call the same code more than once in your program to reload your datasource for some reason, and in this code, you have lines such as:

Me.TextBox1.DataBindings.Add('Text', myDataTable, 'Col1Name')
Me.TextBox2.DataBindings.Add('Text', myDataTable, 'Col2Name')
Me.TextBox3.DataBindings.Add('Text', myDataTable, 'Col3Name')

On the second call, this would attempt to add a duplicate binding to the DataBindings collection. One solution is to Clear the DataBindings collection before you add your new binding.

Me.TextBox1.DataBindings.Clear();
Me.TextBox1.DataBindings.Add('Text', myDataTable, 'Col1Name')
Me.TextBox2.DataBindings.Clear();
Me.TextBox2.DataBindings.Add('Text', myDataTable, 'Col2Name')
Me.TextBox3.DataBindings.Clear();
Me.TextBox3.DataBindings.Add('Text', myDataTable, 'Col3Name')
Permalink

Sometimes the framework will throw an exception if you try to set the bg color to be transparent. This is because the Control doesn’t support transparent colors. To work around this you should call this method from within the Control:


[C#]
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);


[VB.Net]
Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)

Depending on the Control, you might also have to perform some custom drawing, then.

Permalink

Here is a routine that will let you do this. The code below uses the routine from our previous faq how to translate a HSB color to RGB color.


[C#]
		/// <summary>
		/// Adjusts the specified Fore Color’s brightness based on the specified back color and preferred contrast.
		/// </summary>
		/// <param name="foreColor">The fore Color to adjust.
		/// <param name="backColor">The back Color for reference.
		/// <param name="prefContrastLevel">Preferred contrast level.
		/// <remarks>
		/// This method checks if the current contrast in brightness between the 2 colors is 
		/// less than the specified contrast level. If so, it brigtens or darkens the fore color appropriately.
		/// </remarks>
		public static void AdjustForeColorBrightnessForBackColor(ref Color foreColor, Color backColor, float prefContrastLevel)
		{
			float fBrightness = foreColor.GetBrightness();
			float bBrightness = backColor.GetBrightness();

			float curContrast = fBrightness - bBrightness;
			float delta = prefContrastLevel - (float)Math.Abs(curContrast);

			if((float)Math.Abs(curContrast) < prefContrastLevel)
			{
				if(bBrightness < 0.5f)
				{
					fBrightness = bBrightness + prefContrastLevel;
					if(fBrightness > 1.0f)
						fBrightness = 1.0f;
				}
				else
				{
					fBrightness = bBrightness - prefContrastLevel;
					if(fBrightness < 0.0f)
						fBrightness = 0.0f;
				}

				float newr, newg, newb;
				ConvertHSBToRGB(foreColor.GetHue(), foreColor.GetSaturation(), fBrightness, out newr, out newg, out newb);

				foreColor = Color.FromArgb(foreColor.A, (int)Math.Floor(newr * 255f),
					(int)Math.Floor(newg * 255f),
					(int)Math.Floor(newb * 255f));
			}
		}
[VB.Net]
   ’/ <summary>
   ’/ Adjusts the specified Fore Color’s brightness based on the specified back color and preferred contrast.
   ’/ </summary>
   ’/ <param name="foreColor">The fore Color to adjust.
   ’/ <param name="backColor">The back Color for reference.
   ’/ <param name="prefContrastLevel">Preferred contrast level.
   ’/ <remarks>
   ’/ This method checks if the current contrast in brightness between the 2 colors is 
   ’/ less than the specified contrast level. If so, it brigtens or darkens the fore color appropriately.
   ’/ </remarks>
   Public Shared Sub AdjustForeColorBrightnessForBackColor(ByRef foreColor As Color, backColor As Color, prefContrastLevel As Single)
      Dim fBrightness As Single = foreColor.GetBrightness()
      Dim bBrightness As Single = backColor.GetBrightness()
      
      Dim curContrast As Single = fBrightness - bBrightness
      Dim delta As Single = prefContrastLevel - System.Convert.ToSingle(Math.Abs(curContrast))
      
      If System.Convert.ToSingle(Math.Abs(curContrast)) < prefContrastLevel Then
         If bBrightness < 0.5F Then
            fBrightness = bBrightness + prefContrastLevel
            If fBrightness > 1F Then
               fBrightness = 1F
            End If
         Else
            fBrightness = bBrightness - prefContrastLevel
            If fBrightness < 0F Then
               fBrightness = 0F
            End If
         End If 
         Dim newr, newg, newb As Single
         ConvertHSBToRGB(foreColor.GetHue(), foreColor.GetSaturation(), fBrightness, newr, newg, newb)
         
         foreColor = Color.FromArgb(foreColor.A, Fix(Math.Floor((newr * 255F))), Fix(Math.Floor((newg * 255F))), Fix(Math.Floor((newb * 255F))))
      End If
   End Sub ’AdjustForeColorBrightnessForBackColor
Permalink

Here is a routine that does this. Note that the conversion is not precise but very close. (Please do post any better algorithm in our forums).


[C#]
		// This does not seem to yield accurate results, but very close.
		public static void ConvertHSBToRGB(float h, float s, float v, out float r, out float g, out float b)
		{
			if (s == 0f)
			{
				// if s = 0 then h is undefined
				r = v;
				g = v;
				b = v;
			}
			else
			{
				float hue = (float)h;
				if (h == 360.0f)
				{
					hue = 0.0f;
				}
				hue /= 60.0f;
				int i = (int)Math.Floor((double)hue);
				float f = hue - i;
				float p = v * (1.0f - s);
				float q = v * (1.0f - (s * f));
				float t = v * (1.0f - (s * (1 - f)));

				switch(i)
				{
					case 0: r = v; g = t; b = p; break;
					case 1: r = q; g = v; b = p; break;
					case 2: r = p; g = v; b = t; break;
					case 3: r = p; g = q; b = v; break;
					case 4: r = t; g = p; b = v; break;
					case 5: r = v; g = p; b = q; break;

					default: r = 0.0f; g = 0.0f; b = 0.0f; break; /*Trace.Assert(false);*/ // hue out of range
				}
			}
		}
[VB.Net]
Public Shared Sub ConvertHSBToRGB(h As Single, s As Single, v As Single, ByRef r As Single, ByRef g As Single, ByRef b As Single)
      If s = 0F Then
         ’ if s = 0 then h is undefined
         r = v
         g = v
         b = v
      Else
         Dim hue As Single = System.Convert.ToSingle(h)
         If h = 360F Then
            hue = 0F
         End If
         hue /= 60F
         Dim i As Integer = Fix(Math.Floor(System.Convert.ToDouble(hue)))
         Dim f As Single = hue - i
         Dim p As Single = v *(1F - s)
         Dim q As Single = v *(1F - s * f)
         Dim t As Single = v *(1F - s *(1 - f))
         
         Select Case i
            Case 0
               r = v
               g = t
               b = p
            Case 1
               r = q
               g = v
               b = p
            Case 2
               r = p
               g = v
               b = t
            Case 3
               r = p
               g = q
               b = v
            Case 4
               r = t
               g = p
               b = v
            Case 5
               r = v
               g = p
               b = q
            
            Case Else
               r = 0F
               g = 0F
               b = 0F ’Trace.Assert(false);
         ’ hue out of range
         End Select
      End If
   End Sub ’ConvertHSBToRGB
Permalink

Yes, there are framework classes that will give you the Call Stack information at a particular point.


[C#]
		public static void TraceExceptionCatched(Exception e)
		{
			StackTrace st = new StackTrace(1, true);
			StackFrame sf = st.GetFrame(StackTrace.METHODS_TO_SKIP);
			if (sf != null)
			{
				MethodBase mb = sf.GetMethod();
				Trace.WriteLine(e.ToString());
				StringBuilder sb = new StringBuilder();
				sb.Append('catched in File ');
				sb.Append(sf.GetFileName());
				sb.Append(', line ');
				sb.Append(sf.GetFileLineNumber());
				Trace.WriteLine(sb.ToString());
				sb = new StringBuilder();
				sb.Append('in method ');
				sb.Append(mb.ReflectedType.Name);
				sb.Append('.');
				sb.Append(mb.Name);
				sb.Append('(');
				bool first = true;
				foreach (ParameterInfo pi in mb.GetParameters())
				{
					if (!first)
						sb.Append(', ');
					first = false;
					sb.Append(pi.ParameterType.Name);
					sb.Append(' ');
					sb.Append(pi.Name);
				}   
				sb.Append(');');
				Trace.WriteLine(sb.ToString());
			}
		}

You could then call this method from the Catch portion of a try/catch block.

Permalink

Yes, there are classes in the framework that will provide you call stack information that you can trace to the output:


[C#]
		public static void TraceCallStack()
		{
			StackTrace st = new StackTrace(1, true);
			StackFrame sf = st.GetFrame(StackTrace.METHODS_TO_SKIP);
			if (sf != null)
			{
				MethodBase mb = sf.GetMethod();
				StringBuilder sb = new StringBuilder();
				sb.Append(mb.ReflectedType.Name);
				sb.Append('.');
				sb.Append(mb.Name);
				sb.Append('(');
				bool first = true;
				foreach (ParameterInfo pi in mb.GetParameters())
				{
					if (!first)
						sb.Append(', ');
					first = false;
					sb.Append(pi.ParameterType.Name);
					sb.Append(' ');
					sb.Append(pi.Name);
				}   
				sb.Append(');');

				int n = StackTrace.METHODS_TO_SKIP+1;
				sf = st.GetFrame(n);
				if (sf != null)
				{
					sb.Append(' called from ');

					do 
					{
						mb = sf.GetMethod();
						sb.Append(mb.ReflectedType.Name);
						sb.Append('.');
						sb.Append(mb.Name);
						sb.Append(':');
						sf = st.GetFrame(++n);
					}
					while (sf != null);
                        
				}

				Trace.WriteLine(sb.ToString());
			}
		}
Permalink

The focused control’s ProcessCmdKey will be called first.

1) The Control class implementation of this method will check if there is a ContextMenu associated with the Control and if so let the context menu handle the shortcut.

2) If not handled, the ProcessCmdKey of the parent will be called recursively until the Form is reached.

3) When the Form is reached it’s MainMenu will be requested to handle the key.

You can override ProcessCmdKey of any Control and interrupt the normal processing. Note that you can also override the ProcessCmdKey method is the MainMenu and ContextMenu classes (this is not documented) to override default processing.

Permalink

You can listen to the Popup event, determine where the mouse was clicked and selectively make the menu items visible in the menu as follows:


		// In C#
		private void contextMenu1_Popup(object sender, System.EventArgs e)
		{
			// Get current mouse click position in the control (assuming pictureBox1 is the control):
			Point ptClick = this.pictureBox1.PointToClient(Control.MousePosition);
			// Get the rectangle where you want to show the context menu.
			Rectangle preferredClickRect = new Rectangle(0, 0, 50, 50);
			if(preferredClickRect.Contains(ptClick))
			{
				// Show all the menu items so that the menu will appear
				foreach(MenuItem item in this.contextMenu1.MenuItems)
					item.Visible = true;
			}
			else
			{
				// Hide all the menu items so that the menu will not appear
				foreach(MenuItem item in this.contextMenu1.MenuItems)
					item.Visible = false;
			}
		}

		’ In VB.Net
		Private  Sub contextMenu1_Popup(ByVal sender As Object, ByVal e As System.EventArgs)
			’ Get current mouse click position in the control (assuming pictureBox1 is the control):
			Dim ptClick As Point =  Me.pictureBox1.PointToClient(Control.MousePosition) 
			’ Get the rectangle where you want to show the context menu.
			Dim preferredClickRect As Rectangle =  New Rectangle(0,0,50,50) 
			If preferredClickRect.Contains(ptClick) Then
				’ Show all the menu items so that the menu will appear
				Dim item As MenuItem
				For Each item In Me.contextMenu1.MenuItems
					item.Visible = True
				Next
			Else 
				’ Hide all the menu items so that the menu will not appear
				Dim item As MenuItem
				For Each item In Me.contextMenu1.MenuItems
					item.Visible = False
				Next
			End If
		End Sub
Permalink

The issues listed here are pertaining to code running in IE in the default Internet Zone.

1) You cannot view Controls inside IE using the 1.0 framework (when running with the permissions in the default Internet Zone). This is however possible with the 1.1 (Everett) framework.

2) Use only one . in the assembly file name and ‘Assembly Name'(in Project Properties Dialog). For example, ‘Syncfusion.Shared.dll’ is an invalid dll name, but ‘Shared.dll’ is valid.

3) Signed assemblies couldn’t be loaded.

Permalink

While the STAThread is required (as the documentation states) and pertinent only to applications that use COM interop, 1.0 version of the .Net framework has some bugs that makes it necessary for you to specify the STAThread attribute:

1) Ole Drag Drop will not work without STA. You can check this by turning on drag and drop in a form and try to run it.

2) Invoking a method in a type using Reflection will not work either.

These bugs have however been resolved in the 1.1 version of the framework (Everett). Which means you then do not have to specify this attribute for your main method.

Permalink

If you have two controls bound to the same datasource, and you do not want them to share the same position, then you must make sure that the BindingContext member of one control differs from the BindingContext member of the other control. If they have the same BindingContext, they will share the same position in the datasource.

If you add a ComboBox and a DataGrid to a form, the default behavior is for the BindingContext member of each of the two controls to be set to the Form’s BindingContext. Thus, the default behavior is for the DataGrid and ComboBox to share the same BindingContext, and hence the selection in the ComboBox is synchronized with the current row of the DataGrid. If you do not want this behavior, you should create a new BindingContext member for at least one of the controls.

[C#]
private void Form1_Load(object sender, System.EventArgs e)
{
	this.myDataTable = GetATable(); //get a datatable somehow...

	this.dataGrid1.DataSource = myDataTable;

	//set a new binding context for the combobox
	this.comboBox1.BindingContext = new BindingContext();
	this.comboBox1.DataSource = myDataTable;
	this.comboBox1.DisplayMember = 'Col1';
	this.comboBox1.ValueMember = 'Col1';
}

[VB.NET]
Private Sub Form1_Load(ByVal sender as Object, ByVal e as  System.EventArgs)
 
	Me.myDataTable = GetATable() ’get a datatable somehow...

	Me.dataGrid1.DataSource = myDataTable

	’set a new binding context for the combobox
	Me.comboBox1.BindingContext = New BindingContext()
	Me.comboBox1.DataSource = myDataTable
	Me.comboBox1.DisplayMember = 'Col1'
	Me.comboBox1.ValueMember = 'Col1'
End Sub
Permalink

You can avoid the combobox dropping by overriding its WndProc method and ignoring the WM_LBUTTONDOWN and WM_LBUTTONDBLCLK.

[C#]
 public class MyComboBox : ComboBox
 {
	protected override void WndProc(ref System.Windows.Forms.Message m)
	{
		 if(m.Msg == 0x201  //WM_LBUTTONDOWN
		    || m.Msg == 0x203)  //WM_LBUTTONDBLCLK
  			 return;
		base.WndProc(ref m);
	}
 }

[VB.NET]
Public Class MyComboBox
	Inherits ComboBox
   
	Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
		If m.Msg = &H201 OrElse m.Msg = &H203 Then ’WM_LBUTTONDOWN  or WM_LBUTTONDBLCLK
			Return
		End If

		MyBase.WndProc(m)
	End Sub ’WndProc
End Class ’MyComboBox
Permalink

First set the ContextMenu property of the TextBox to a dummy, empty ContextMenu instance. This will prevent the default context menu from showing. Then, override the ProcessCmdKey method as follows in a TextBox derived class:


		// In C#
		protected override bool ProcessCmdKey(ref Message msg,	Keys keyData)
		{
			if(keyData == (Keys.Control | Keys.V))
				return true;
			else
				return base.ProcessCmdKey(ref msg, keyData);
		}

		’ In VB.Net
		Protected Overrides Function ProcessCmdKey(ByRef msg As Message, ByVal keyData As Keys) As Boolean
			If keyData =(Keys.Control | Keys.V) Then
				Return True
			Else 
				Return MyBase.ProcessCmdKey( msg, keyData)
			End If
		End Function
Permalink

You can use the TabPage’s Validating event to prevent a new tab page selection. Here are the steps:

1) Every time the user selects a new tab, make sure that the corresponding tab page gets the focus. You can do so as follows:


// In C#
private void tabControl1_SelectedIndexChanged(object sender, 
System.EventArgs e)
{
	tabControl1.TabPages[tabControl1.SelectedIndex].Focus();
	tabControl1.TabPages[tabControl1.SelectedIndex].CausesValidation = true;
}

’VB.Net
Private  Property sender,() As tabControl1_SelectedIndexChanged(object
End Property
Private Function e)() As System.EventArgs
	tabControl1.TabPages(tabControl1.SelectedIndex).Focus()
	tabControl1.TabPages(tabControl1.SelectedIndex).CausesValidation = True
End Function

Note that CausesValidation should be set to True since you will be listening to the Validating event in the next step.
You will also have to add some code like above when the TabControl is shown the very first time (like in the Form_Load event handler).

2) Listen to the TabPage’s Validating event (which will be called when the user clicks on a different tab page) and determine whether the user should be allowed to change the selected tab page.


// In C#
private void tabPage1_Validating(object sender, 
System.ComponentModel.CancelEventArgs e)
{
	if(!checkValidated.Checked)
		e.Cancel = true;
}

’ In VB.Net
Private  Sub tabPage1_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs)
	If Not checkValidated.Checked Then
		e.Cancel = True
	End If
End Sub
Permalink

You cannot move it via drag-and-drop. But you change it’s position or dock order by selecting the ‘Bring To Front’ or ‘Send To Back’ verbs in it’s context menu. ‘Bring To Front’ will move it to the top of the children list and ‘Send To Back’ will move it to the last of the children list. This is possible because the docking logic will be applied on the children in the order in which they appear in the child controls list.

Permalink

Make sure to preface the method/property name with the fully qualified interface name that it belongs to, like this:


	// In C#
	// Where someType implements ISomeInterface’s SomeMethod as a private implementation.
	Type someType = someInstance.GetType();
	MethodInfo mi = someType.GetMethod('System.Windows.Forms.ISomeInterface.SomeMethod', 
			BindingFlags.NonPublic | BindingFlags.Instance);
	if(mi != null)
	{
		mi.Invoke(someInsance, new object[]{});
	}

	’ In VB.Net
	’ Where someType implements ISomeInterface’s SomeMethod as a private implementation.
	Dim someType As Type =  someInstance.GetType() 
	MethodInfo mi = someType.GetMethod('System.Windows.Forms.ISomeInterface.SomeMethod', 
			BindingFlags.NonPublic | BindingFlags.Instance)
	If Not mi Is Nothing Then
		’ Assuming no arguments for SomeMethod.
		mi.Invoke(someInsance, Nothing)
	End If

Permalink

Below is a technique that uses FolderNameEditor and FolderBrowser classes to implement a solution. You can also use iterop to get a solution.

Both the FolderNameEditor and FolderBrowser classes used in this solution are described in the Docs as ‘This type supports the .NET Framework infrastructure and is not intended to be used directly from your code.’

	// add a reference to System.Design.DLL

	using System.Windows.Forms.Design;
	.............

	public class DirBrowser : FolderNameEditor
	{
		FolderBrowser fb = new FolderBrowser();

		public string Description
		{
			set { _description = value; }
			get { return _description; }
		}

		public string ReturnPath
		{
			get { return _returnPath; }
		}

		public DirBrowser() { }

		public DialogResult ShowDialog()
		{
			fb.Description = _description;
			fb.StartLocation = FolderBrowserFolder.MyComputer;

			DialogResult r = fb.ShowDialog();
			if (r == DialogResult.OK)
				_returnPath = fb.DirectoryPath;
			else
				_returnPath = String.Empty;

			return r;
		}

		private string _description = 'Choose Directory';
		private string _returnPath = String.Empty;
	}

(Posted by Ryan Farley on the microsoft.public.dotnet.language.csharp newsgroup)

Permalink

You can do this by deriving the TextBox, overriding the WndProc method and ignoring these mousedowns.

[C#]
public class MyTextBox : TextBox
{
	protected override void WndProc(ref System.Windows.Forms.Message m)
	{	// WM_NCLBUTTONDOWN  WM_LBUTTONDOWN 
		if(this.ReadOnly && (m.Msg ==  0xa1 || m.Msg == 0x201))
		{
			return; //ignore it
		}
		base.WndProc(ref m);
	}
}
[VB.NET]
Public Class MyTextBox
	Inherits TextBox
    
	Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
		’ WM_NCLBUTTONDOWN  WM_LBUTTONDOWN 
		If Me.ReadOnly AndAlso(m.Msg = &HA1 OrElse m.Msg = &H201) Then 
			Return ’ignore it
		End If
		MyBase.WndProc(m)
	End Sub ’WndProc
End Class ’MyTextBox
Permalink

It appears that this behavior is a bug that will be corrected in a future .NET release.

You can control the size of your child form by adding a Layout event handler for it. Here is a code snippet that imposes the minimum size that you set in its properties. You can also handle it by overriding the form’s WndProc method as explained in this Microsoft KB article.

[C#]
	private void Document_Layout(object sender, System.Windows.Forms.LayoutEventArgs e)
	{
		if(this.Bounds.Width < this.MinimumSize.Width)
			this.Size = new Size(this.MinimumSize.Width, this.Size.Height);

		if(this.Bounds.Height < this.MinimumSize.Height)
			this.Size = new Size(this.Size.Width, this.MinimumSize.Height);
	}

[VB.NET]
	Private Sub Document_Layout(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LayoutEventArgs) Handles MyBase.Layout

		If (Me.Bounds.Width < Me.MinimumSize.Width) Then
			Me.Size = New Size(Me.MinimumSize.Width, Me.Size.Height)
		End If

		If (Me.Bounds.Height < Me.MinimumSize.Height) Then
			Me.Size = New Size(Me.Size.Width, Me.MinimumSize.Height)
		End If
	End Sub
Permalink

If you make sure your DataGrid is using a DataGridTableStyle, then you can access the TextBox through the GridColumnStyles collection and hook the event there. Here is some code….

[C#]
	//in formload
	this.dataGrid2.DataSource = this.dataSet11.Customers; // set the data source

            	//make sure grid has a tablestyle
	DataGridTableStyle ts = new DataGridTableStyle();
	ts.MappingName = this.dataSet11.Customers.TableName;
	this.dataGrid2.TableStyles.Add(ts);

	//now we can wire up wire up events for columns 1 and 4 ....
	DataGridTextBoxColumn tbc = (DataGridTextBoxColumn)ts.GridColumnStyles[0];
	tbc.TextBox.KeyPress += new KeyPressEventHandler(CellKeyPress);

	tbc = (DataGridTextBoxColumn)ts.GridColumnStyles[3];
	tbc.TextBox.KeyPress += new KeyPressEventHandler(CellKeyPress);.....

	//the handler
	private void CellKeyPress(object sender, KeyPressEventArgs e)
	{
		//don’t allow 1’s
		if(e.KeyChar == ’1’)
		e.Handled = true;
	}

[VB.NET]
	 ’in formload
	Me.dataGrid2.DataSource = Me.dataSet11.Customers ’ set the data source
	
	’make sure grid has a tablestyle
	Dim ts As New DataGridTableStyle()
	ts.MappingName = Me.dataSet11.Customers.TableName
	Me.dataGrid2.TableStyles.Add(ts)

	’now we can wire up wire up events for columns 1 and 4 ....
	Dim tbc as DataGridTextBoxColumn = CType(ts.GridColumnStyles(0), DataGridTextBoxColumn)
	AddHandler tbc.TextBox.KeyPress, AddressOf CellKeyPress

	tbc = CType(ts.GridColumnStyles(3), DataGridTextBoxColumn)
	AddHandler tbc.TextBox.KeyPress, AddressOf CellKeyPress
	.....

	’the handler
	Private Sub CellKeyPress(sender As Object, e As KeyPressEventArgs) 
   		’don’t allow 1’s
		If e.KeyChar = '1'c Then
			e.Handled = True
		End If
	End Sub ’CellKeyPress
Permalink

You can do this using the bitwise operators &, | and ^ ( And, Or and Xor (or &, Or, ^) in VB.Net). Here is code that will toggle label1 being anchored on the left.

[C#]
	private void button1_Click(object sender, System.EventArgs e)
	{
		if ((label1.Anchor & AnchorStyles.Left) == 0)
		{	//add it
			label1.Anchor = label1.Anchor | AnchorStyles.Left;
		}
		else if ((label1.Anchor & AnchorStyles.Left) != 0)
		{	//remove
        			label1.Anchor = label1.Anchor ^ AnchorStyles.Left;
		}
	}

[VB.NET]


	Private Sub button1_Click(sender As Object, e As System.EventArgs)
		If(label1.Anchor And AnchorStyles.Left) = 0 Then
			’add it
			label1.Anchor = label1.Anchor Or AnchorStyles.Left
		ElseIf(label1.Anchor And AnchorStyles.Left) <> 0 Then
			’remove
			label1.Anchor = label1.Anchor Xor AnchorStyles.Left
		End If
	End Sub ’button1_Click
Permalink

When you first click into a checkbox column, the checked state of the cell does not change. One way you can make the checked state change on the first click is to handle the grid’s MouseUp event, and change the check value there.

[VB.Net}
	Private myCheckBoxCol As Integer = 9  ’my checkbox column
	Private Sub DataGrid2_MouseUp(ByVal sender As Object,  ByVal e As MouseEventArgs) Handles DataGrid2.MouseUp
		Dim hti As DataGrid.HitTestInfo = Me.dataGrid2.HitTest(e.X, e.Y)
		Try
			If hti.Type = DataGrid.HitTestType.Cell AndAlso hti.Column = myCheckBoxCol Then
				Me.dataGrid2(hti.Row, hti.Column) = Not CBool(Me.dataGrid2(hti.Row, hti.Column))
			End If
		Catch ex As Exception
			MessageBox.Show(ex.ToString())
		End Try
	End Sub ’dataGrid2_MouseUp

[C#]
	private int myCheckBoxCol = 9; //my checkbox column

	private void dataGrid2_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
	{
		DataGrid.HitTestInfo hti   = this.dataGrid2.HitTest(e.X, e.Y);
		try
		{
			if( hti.Type == DataGrid.HitTestType.Cell && 
				hti.Column == myCheckBoxCol)
			{
				this.dataGrid2[hti.Row, hti.Column] = ! (bool) this.dataGrid2[hti.Row, hti.Column];
			}
		}																				catch(Exception ex)
		{
			MessageBox.Show(ex.ToString());
		}
	}
Permalink

You can set the control’s Enabled property to false. This will prevent clicking but also gives the disabled look.

There is a ControlStyles.Selectable flag that determines whether the control can get focus or not. But it does not appear to affect some controls such as TextBox. But you can prevent the TextBox from getting focus by overriding its WndProc method and ignoring the mouse down.

public class MyTextBox : TextBox
{
	const int WM_LBUTTONDOWN = 0x0201;
  
	protected override void WndProc(ref System.Windows.Forms.Message m)
	{
		if(m.Msg == WM_LBUTTONDOWN)
			return;
		base.WndProc(ref m);
	}
}
Permalink

MDIContainer forms have an MDIClient child window and it is to this MDIClient window that MDI child forms are parented. The MDIClient’s ControlAdded/ControlRemoved events will be fired whenever a child form is added or removed. You can subscribe to these events and add the required processing code from within the handlers.


// From within the MDIContainer form, subscribe to the MDIClient’s ControlAdded/ControlRemoved events 
foreach(Control ctrl in this.Controls) 
{ 
	if(ctrl.GetType() == typeof(MdiClient)) 
	{ 
		ctrl.ControlAdded += new ControlEventHandler(this.MDIClient_ControlAdded); 
		ctrl.ControlRemoved += new ControlEventHandler(this.MDIClient_ControlRemoved); 
		break;
	} 
} 

protected void MDIClient_ControlAdded(object sender, ControlEventArgs e) 
{ 
	Form childform = e.Control as Form;
	Trace.WriteLine(String.Concat(childform.Text, ' - MDI child form was added.'));
} 

protected void MDIClient_ControlRemoved(object sender, ControlEventArgs e) 
{ 
	Trace.WriteLine(String.Concat(e.Control.Text, ' - MDI child form was removed.'));
} 
Permalink

Here is a solution suggested by Elan Zhou (MS) on the microsoft.public.dotnet.languages.vb newsgroup.

You can also use the following code:
1. Put a DataGrid on the form.
2. Try the following sample code: (Suppose the csv is c:\test.csv.)


Imports System.Data
Imports System.Data.OleDb


Public Class Form1
	Inherits System.Windows.Forms.Form
	Dim objDataset1 As DataSet()

	Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        
		Dim sConnectionString As String = 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\;Extended Properties=Text;'
		Dim objConn As New OleDbConnection(sConnectionString)
		objConn.Open()

		Dim objCmdSelect As New OleDbCommand('SELECT * FROM test.csv', objConn)
		Dim objAdapter1 As New OleDbDataAdapter()
		objAdapter1.SelectCommand = objCmdSelect

		Dim objDataset1 As New DataSet()
		objAdapter1.Fill(objDataset1, 'Test')
		DataGrid1.DataSource = objDataset1.Tables(0).DefaultView
		objConn.Close()
	End Sub
End Class
Permalink

GDI+ Programming: Creating Custom Controls using C#
by Eric White, Chris Garrett.
Wrox Press Inc; ISBN: 1861006314

The title of the this book is kind of misleading. It is an excellent introduction to GDI+. In addition to GDI+ there is also some information on control designers that will be useful to control authors.

Permalink

C# Design patterns by James W. Cooper. ISBN: 0201844532

This is a good book to learn about patterns through a C#/Windows Forms lens. Several of the samples are UI related and use Windows Forms.

Permalink

Derive a DataGrid. In your derived grid, add a handler for the VertScrollBar.VisibleChanged event. In your handler, if the scrollbar is not visible, size it and position it, and then show it. The code below assumes no horizontal scrollbar is necessary. If it is present, you would have to adjust the sizing code.

C#
public class MyDataGrid : DataGrid
{

	public MyDataGrid()
	{
		//make scrollbar visible & hook up handler
		this.VertScrollBar.Visible = true;
		this.VertScrollBar.VisibleChanged += new EventHandler(ShowScrollBars);
	}

	private int CAPTIONHEIGHT = 21;
	private int BORDERWIDTH = 2;
	
	private void ShowScrollBars(object sender, EventArgs e)
	{
		if(!this.VertScrollBar.Visible)
		{
			int width = this.VertScrollBar.Width;
			this.VertScrollBar.Location = new Point(this.ClientRectangle.Width - width  - BORDERWIDTH, CAPTIONHEIGHT);
			this.VertScrollBar.Size = new Size(width, this.ClientRectangle.Height - CAPTIONHEIGHT - BORDERWIDTH);
			this.VertScrollBar.Show();				
		}
	}
}

VB.NET
Public Class MyDataGrid
	Inherits DataGrid
   
	Public Sub New()
		’make scrollbar visible & hook up handler
		Me.VertScrollBar.Visible = True
		AddHandler Me.VertScrollBar.VisibleChanged, AddressOf ShowScrollBars
	End Sub ’New
   
	Private CAPTIONHEIGHT As Integer = 21
	Private BORDERWIDTH As Integer = 2
   
	Private Sub ShowScrollBars(sender As Object, e As EventArgs)
		If Not Me.VertScrollBar.Visible Then
			Dim width As Integer = Me.VertScrollBar.Width
			Me.VertScrollBar.Location = New Point(Me.ClientRectangle.Width - width - BORDERWIDTH, CAPTIONHEIGHT)
			Me.VertScrollBar.Size = New Size(width, Me.ClientRectangle.Height - CAPTIONHEIGHT - BORDERWIDTH)
			Me.VertScrollBar.Show()
		End If
	End Sub ’ShowScrollBars
End Class ’MyDataGrid
Permalink

The DataGrid class does not have a property that controls whether a new row can be added. But the DataView class does have such a property (along with some others such as AllowEdit and AllowDelete). Here is code that will turn off the append row by getting at the dataview associated with the datagrid.

	string connString = @'Provider=Microsoft.JET.OLEDB.4.0;data source=C:\northwind.mdb';
	string sqlString = 'SELECT * FROM customers';

	// Connection object
	OleDbConnection connection = new OleDbConnection(connString);

	// Create data adapter object
	OleDbDataAdapter dataAdapter = new OleDbDataAdapter(sqlString, connection);

	// Create a dataset object and fill with data using data adapter’s Fill method
	DataSet dataSet = new DataSet();
	dataAdapter.Fill(dataSet, 'customers');
			
	// Attach dataset’s DefaultView to the datagrid control
	dataGrid1.DataSource = dataSet.Tables['customers'];

	//no adding of new rows thru dataview...
	CurrencyManager cm = (CurrencyManager)this.BindingContext[dataGrid1.DataSource, dataGrid1.DataMember];	
	((DataView)cm.List).AllowNew = false;

If your datagrid contains links, then Matthew Miller suggest adding Navigate handler such as the one below to disallow the AddNew.

private void DataGrid1_Navigate(object sender, System.Windows.Forms.NavigateEventArgs ne)
{
	if(ne.Forward)
	{
		CurrencyManager cm  = (CurrencyManager)BindingContext[DataGrid1.DataSource,DataGrid1.DataMember];
		DataView dv  = (DataView) cm.List;
		dv.AllowNew = false;
	}
}
Permalink

Please check out this article from the October 2000 issue of MSDN Magazine.

Allen Weng gives the following explanation in a post on the microsoft.public.dotnet.framework.windowsforms newgroup.

If what you are looking for is just to intercept and handle generic Windows messages such as WM_NCPAINT or alike, you can override WndProc (). You don’t need to use the hook procedure. Here is some code that does this:

public enum WinMsg 
{
	WM_KEYDOWN = 256,
	WM_KEYUP = 257,
	WM_PAINT = 15,
	WM_CREATE = 1
	.......
	.......
};

protected override void WndProc(ref System.Windows.Forms.Message m)
{
	.............. 
	if (m.Msg == (int) WinMsg.WM_PAINT)
	{
		m.Result = new IntPtr(0); // no further processing is needed.
		.......
		.......
	}
	..............
	base.WndProc(ref m);
}

But if you need to use a hook procedure, be cautious since they might interfere with normal execution of other applications. In some extreme cases, they might bring the whole system down if not processed correctly. Here is the code snippet that shows you how to do implement and use the hook procedure in .NET:

public class Win32Hook
{
	[DllImport('kernel32')]
	public static extern int GetCurrentThreadId();

	[DllImport( 'user32', CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
	public static extern int  SetWindowsHookEx( HookType idHook,
				HOOKPROC lpfn,
				int hmod,
				int dwThreadId
				);

	public enum HookType
	{
		WH_KEYBOARD = 2
	}
	public delegate int HOOKPROC(int nCode, int wParam, int lParam);

	private HOOKPROC hookProc; //private field with class scope

	public void SetHook()
	{
		 // set the keyboard hook
		hookProc = new HOOKPROC(this.MyKeyboardProc);

            		SetWindowsHookEx(HookType.WH_KEYBOARD, hookProc, 0,
GetCurrentThreadId());

	}

	public int MyKeyboardProc(int nCode, int wParam, int lParam)
	{
		return 0;
	}
}

To install the hook procedure

            Win32Hook hook = new Win32Hook();
            hook.SetHook();
Permalink

You can use the IsNull operator.

[C#]
	//the outer quotes are double quotes and the inner quotes are 2 single quotes
	//Fax is the column mapping name
	this.dataView1.RowFilter = 'IsNull(Fax, ’’) = ’’';

	// for a numeric null in custNo  (suggested by Bob Gibson)
	this.dataView1.RowFilter = 'IsNull(custNo, 0) = 0';

[VB.NET]
	’the outer quotes are double quotes and the inner quotes are 2 single quotes
	’Fax is the column mapping name
	Me.dataView1.RowFilter = 'IsNull(Fax, ’’) = ’’'

	’ for a numeric null in custNo  (suggested by Bob Gibson)
	Me.DataView1.RowFilter = 'IsNull(custNo, 0) = 0'
Permalink

Share with

Couldn't find the FAQs you're looking for?

Please submit your question and answer.