How can I tell if a form is closed from the controlbox (system menu) or from a call to Form.Close

One way to do this is to override the form’s WndProc method and check for WM_SYSCOMMAND and SC_CLOSE. Looking for WM_CLOSE in the override is not sufficient as WM_CLOSE is seen in both cases. A sample is available for download (C#, VB). public const int SC_CLOSE = 0xF060; public const int WM_SYSCOMMAND = 0x0112; //_closeClick is a bool member of the form initially set false… // It can be tested in the Closing event to see how the closing came about. protected override void WndProc(ref System.Windows.Forms.Message m) { if(m.Msg == WM_SYSCOMMAND && (int)m.WParam == SC_CLOSE) this._closeClick = true; base.WndProc(ref m); }

How can I catch keyboard messages on a application-wide basis

You can implement the IMessageFilter interface in your main form. This amounts to adding an override for PreFilterMessage, and looking for the particular message you need to catch. Here are code snippets that catch an escape key on a keydown. You can download a sample project(C#, VB). In the sample, there are two forms, with several controls. You’ll notice that no matter what form or control has input focus, the escape key is caught in the PreFilterMessage override. [C#] public class MyMainForm : System.Windows.Forms.Form, IMessageFilter { const int WM_KEYDOWN = 0x100; const int WM_KEYUP = 0x101; public bool PreFilterMessage(ref Message m) { Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode; if(m.Msg == WM_KEYDOWN && keyCode == Keys.Escape) { Console.WriteLine(”Ignoring Escape…”); return true; } return false; } …. …. …. private void MyMainForm_Load(object sender, System.EventArgs e) { Application.AddMessageFilter(this); } } [VB.NET] Public Class MyMainForm Inherits System.Windows.Forms.Form Implements IMessageFilter Private WM_KEYDOWN As Integer = &H100 Private WM_KEYUP As Integer = &H101 Public Function PreFilterMessage(ByRef m As Message) As Boolean Dim keyCode As Keys = CType(CInt(m.WParam), Keys) And Keys.KeyCode If m.Msg = WM_KEYDOWN And keyCode = Keys.Escape Then Console.WriteLine(”Ignoring Escape…”) Return True End If Return False End Function ’PreFilterMessage …. …. …. Private Sub MyMainForm_Load(sender As Object, e As System.EventArgs) Application.AddMessageFilter(Me) End Sub ’MyMainForm_Load End Class ’MyMainForm

How do I display a column of buttons such as pushbuttons or combobox buttons

This sample (download C#, download VB) derives two custom columnstyles that display buttons. One displays a pushbutton with the cell text used as the button label. The second columnstyle displays text plus a dropdown button similar to a combobox button. Both columnstyles have an event that your form can handle to respond to clicks on the buttons. The row and column of the click are passed as part of the event arguments. Both columnstyles derive from DataGridTextBoxColumn, and override Paint and Edit. The Edit override does not call the baseclass to avoid allowing the cell going into the edit mode. In the Paint override, the text is drawn, and a bitmap showing the button face is drawn. There is no mouse handling within a columnstyle. To catch the click action, the columnstyle must handle the datagrid’s MouseDown and MouseUp events. In the columnstyle handlers for these events, the handler draws the depressed button as well as firing the columnstyle’s ColumnButtonClick event. Your handler for this ColumnButtonClick event should take whatever action as a result of the buttonclick. In the sample projects, the handler just displays a messagebox.

How can I place text in the rowheader column of my datagrid

There is no text property exposed for a rowheader cell. But you can handle the Paint event and draw header text yourself. You can download sample projects (C#, VB) that illustrate one technique for doing so. The sample loads the datagrid in the form’s Load event. In addition, this event is used to set the rowheaderwidth of the datagrid, and to remember the point where cell 0,0 is located. This point will allow us to find the toprow number when we need it to start drawing the header text. A handler for the datagrid’s Paint event is used to draw the text. It finds the toprow using the point from the original cell 0,0, and using the toprow determines the correct text for each rowheader. Finally, to avoid the complication of the user changing rowheights, we derive a new grid to prevent this. private void dataGrid1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { int row = TopRow(); int yDelta = dataGrid1.GetCellBounds(row, 0).Height + 1; int y = dataGrid1.GetCellBounds(row, 0).Top + 2; CurrencyManager cm = (CurrencyManager) this.BindingContext[dataGrid1.DataSource, dataGrid1.DataMember]; while(y < dataGrid1.Height – yDelta && row < cm.Count) { //get & draw the header text… string text = string.Format(‘row{0}’, row); e.Graphics.DrawString(text, dataGrid1.Font, new SolidBrush(Color.Black), 12, y); y += yDelta; row++; } } Here is a datagrid with red row headers containing text.

How can I enable column selections in my datagrid

Here is a sample (C#, VB) that has column selections implemented. It derives a datagrid, adds a columns selection array list, and maintains this list in an override of OnMouseDown. Then to handle actually drawing the selected columns, it uses a derived column style, and sets the backBrush color and foreBrush color to the selection values in the override of the Paint method when it needs to draw a selected cell. As an alternative to drawing the selection in a derived column style, you could just draw the selection in your derived grid by overriding OnPaint, calling the base class and then looping through the columns selections, filling a rectangle over the selected columns. The problem with this technique is that you would either have to redraw text in column with the correct forecolor, or you would have to use an alphablended color to let the text show through the selection rectangle. Using an alphablended color would eliminate the need to a column style override, but would give a different appearance than the ’standard’ selections that you see in a datagrid. The sample allows the row selections to continue to work so the column style override makes sense here.