Drag and Drop support for column reordering in DataGrid control
2004-11-04 20:24
801 查看
Link From :http://www.codeproject.com/cs/miscctrl/ElvinDataGridEx.asp
![](http://www.codeproject.com/cs/miscctrl/ElvinDataGridEx/DataGridEx.jpg)
Thanks to the extensible architecture of
public static extern bool BitBlt
(
IntPtr hdcDest, // handle to destination DC (device context)
int nXDest, // x-coord of destination upper-left corner
int nYDest, // y-coord of destination upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
IntPtr hdcSrc, // handle to source DC
int nXSrc, // x-coordinate of source upper-left corner
int nYSrc, // y-coordinate of source upper-left corner
System.Int32 dwRop // raster operation code
);
For more information on this API, please consult the Win32 documentation.
{
try
{
DataGrid.HitTestInfo hti = HitTest(e.X, e.Y);
/*
* The following conditions must be met in order to
* start of the drag operation
* 1) Column Header is clicked with left mouse button.
* 2) AllowUserToOrderColumns property has been set to true
*
* */
if (
(hti.Type == DataGrid.HitTestType.ColumnHeader)
&& ((e.Button & MouseButtons.Left) == MouseButtons.Left)
&& (allowColumnsReorder))
{
// Notify application that the drag operation is about to start
ColumnStartDragEventArgs csde = new ColumnStartDragEventArgs(
hti.Column, GetColumnName(hti.Column), false);
OnColumnStartDrag(csde);
if (!csde.Cancel) // This column is drag-able
{
// Remember the column header clicked
dragColumnIndex = hti.Column;
isColumnDragging = true;
/*
* Currently, there is no way to determine the drag column's top
* left position.
* Workaround : Assumes the mouse clicked in the middle of the
* drag column.
*
* */
mouseDelta = new Point
(
e.X - (e.X - (GetColumnWidth(hti.Column) / 2)),
(CaptionVisible == true ? GetCaptionHeight() : 0)
);
Point dragColumn = PointToScreen(new Point(e.X, mouseDelta.Y));
Point screenPoint = PointToScreen(new Point(e.X, e.Y));
screenPoint.X -= mouseDelta.X;
screenPoint.Y = dragColumn.Y;
// Retrieve the DataGridColumnStyle for the drag column
dragColumnStyle = GetColumnStyle(hti.Column);
// Create the screen graphic device
CreateDisplayDC();
// Determine the actual size of the dragged image
dragImageSize = new Size(dragColumnStyle.Width,
ColumnHeaderHeight - 2);
// Determine and create the image buffer.
buffer = new Bitmap(Math.Max(dragColumnStyle.Width,
NODROPIMAGE_WIDTH + 2), ColumnHeaderHeight);
bufferGraphics = Graphics.FromImage(buffer);
pBufferDC = bufferGraphics.GetHdc();
// Copy the rectangluar image from the screen into buffer.
WinGDI.BitBlt(pBufferDC, 0, 0, buffer.Width, buffer.Height,
pDisplayDC, screenPoint.X, screenPoint.Y, WinGDI.SRCCOPY);
// Store the image buffer position for tracking
bufferPos = new Point(screenPoint.X, screenPoint.Y);
}
}
}
catch(Exception) { /* Ignore */ }
finally
{
base.OnMouseDown(e);
}
}
}
{
try
{
DataGrid.HitTestInfo hti = HitTest(e.X, e.Y);
/*
* The following conditions must be met before
* performing the drawing of drag operation
* 1) AllowUserToOrderColumns property has been set to true
* 2) Column is being dragged with left mouse button
*
* */
if (
(allowColumnsReorder)
&& (isColumnDragging)
&& ((e.Button & MouseButtons.Left) == MouseButtons.Left))
{
if (hti.Column >= 0)
{
// Re-calculate the mouse location in the screen
Point screenPoint = PointToScreen(new Point(e.X, e.Y));
screenPoint.X -= mouseDelta.X;
screenPoint.Y = bufferPos.Y;
// Performs the image swapping
WinGDI.BitBlt(pDisplayDC, bufferPos.X, bufferPos.Y,
buffer.Width, buffer.Height, pBufferDC, 0,
0, WinGDI.SRCCOPY);
WinGDI.BitBlt(pBufferDC, 0, 0, buffer.Width, buffer.Height,
pDisplayDC, screenPoint.X, screenPoint.Y,
WinGDI.SRCCOPY);
bufferPos = new Point(screenPoint.X, screenPoint.Y);
/*
* Notify application that the dragged column is dragging over
* to another column and determines whether the dragged column
* can be dropped onto it.
*
* */
ColumnSequenceChangingEventArgs csce =
new ColumnSequenceChangingEventArgs(dragColumnIndex,
GetColumnName(dragColumnIndex), hti.Column,
GetColumnName(hti.Column), false);
OnColumnSequenceChanging(csce);
if (csce.Cancel) // Drop on this column is not allow
DrawDragImage(displayGraphics, screenPoint.X, screenPoint.Y, false);
else
DrawDragImage(displayGraphics, screenPoint.X, screenPoint.Y, true);
}
}
}
catch(Exception) { /* Ignore */ }
finally
{
base.OnMouseMove(e);
}
}
}
When the mouse button releases,
{
try
{
DataGrid.HitTestInfo hti = HitTest(e.X, e.Y);
if(
(allowColumnsReorder)
&& (isColumnDragging)
&& ((e.Button & MouseButtons.Left) == MouseButtons.Left))
{
// Clean up the drawn image from the screen
WinGDI.BitBlt(pDisplayDC, bufferPos.X, bufferPos.Y, buffer.Width,
buffer.Height, pBufferDC, 0, 0, WinGDI.SRCCOPY);
/*
* The following conditions must be met before moving the drag column
* 1) Drop column is within bound
* 2) Source Column <> Destination Column
* */
if (hti.Column >= 0 && dragColumnIndex != hti.Column)
{
/*
* Notify application that the dragged column is about to drop onto
* another column.
* */
ColumnSequenceChangingEventArgs columnChanging =
new ColumnSequenceChangingEventArgs(dragColumnIndex,
GetColumnName(dragColumnIndex), hti.Column,
GetColumnName(hti.Column), false);
OnColumnSequenceChanging(columnChanging);
if (!columnChanging.Cancel) // Drop on this column is allowed
{
// Move the column
MoveColumn(dragColumnIndex, hti.Column);
// Notify application that the dragged column
// is reordered to new location
ColumnSequenceChangedEventArgs columnChanged =
new ColumnSequenceChangedEventArgs(columnChanging.SourceColumnIndex,
columnChanging.SourceColumnName, columnChanging.DestinationColumnIndex,
columnChanging.DestinationColumnName);
OnColumnSequenceChanged(columnChanged);
}
}
// House Keeping
isColumnDragging = false;
dragColumnIndex = -1;
dragColumnStyle = null;
DisposeDisplayDC();
DisposeBufferDC();
}
}
catch(Exception) { /* Ignore */ }
finally
{
base.OnMouseUp(e);
}
}
The cornerstone of drawing the dragged column is encapsulated in the function
{
try
{
g.SmoothingMode = SmoothingMode.AntiAlias;
// Anti-aliased rendering
Rectangle rect = new Rectangle(x, y, dragImageSize.Width,
dragImageSize.Height);
using(Pen p = new Pen(Color.Black))
{
// Semi-Transparent
using(Brush backBrush = new SolidBrush(Color.FromArgb(127,
Color.LightSteelBlue)))
{
using(Brush foreBrush = new SolidBrush(Color.Black))
{
g.FillRectangle(backBrush, rect.Left + 1, rect.Top + 1,
rect.Width - 2, rect.Height - 2);
g.DrawRectangle(p, rect.Left, rect.Top, rect.Width - 1,
rect.Height - 1);
using(StringFormat sf = new StringFormat(StringFormatFlags.NoWrap))
{
sf.LineAlignment = StringAlignment.Center;
if (dragColumnStyle.Alignment == HorizontalAlignment.Center)
sf.Alignment = StringAlignment.Center;
else if (dragColumnStyle.Alignment == HorizontalAlignment.Left)
sf.Alignment = StringAlignment.Near;
else if (dragColumnStyle.Alignment == HorizontalAlignment.Right)
sf.Alignment = StringAlignment.Far;
g.DrawString(dragColumnStyle.HeaderText, HeaderFont,
foreBrush, rect, sf);
}
// Draw an X icon in the semi-transparent drag column
if (!bEnabled)
{
using(Pen redPen = new Pen(new SolidBrush(Color.Red), 3))
{
// Note: Those offset applied here is meant to
// avoid drawing the X icon outside
// of the bound rectangle.
Point p1; Point p2; // X
Point p3; Point p4; // Y
if (dragImageSize.Width > NODROPIMAGE_WIDTH)
{
int left = rect.Left + ((dragImageSize.Width
- NODROPIMAGE_WIDTH) / 2);
p1 = new Point(left, rect.Top + 1);
p2 = new Point(left + NODROPIMAGE_WIDTH, rect.Top
+ buffer.Height - 2);
p3 = new Point(left + NODROPIMAGE_WIDTH, rect.Top + 1);
p4 = new Point(left, rect.Top + buffer.Height - 2);
}
else
{
p1 = new Point(rect.Left + 1, rect.Top + 1);
p2 = new Point(rect.Left + NODROPIMAGE_WIDTH - 1,
rect.Top + buffer.Height - 2);
p3 = new Point(rect.Left + NODROPIMAGE_WIDTH - 1,
rect.Top + 1);
p4 = new Point(rect.Left + 1, rect.Top + buffer.Height - 2);
}
redPen.StartCap = LineCap.Round;
redPen.EndCap = LineCap.Round;
g.DrawLine(redPen, p1, p2);
g.DrawLine(redPen, p3, p4);
}
}
}
}
}
}
catch(Exception) { /* Ignore */ }
}
{
if(fromColumn == toColumn) return;
DataGridTableStyle oldTS = TableStyles[0];
DataGridTableStyle newTS = new DataGridTableStyle();
newTS.MappingName = oldTS.MappingName; // Table Name
CopyTableStyle(oldTS, newTS);
// Copy the old TableStyle to new TableStyle
for(int i = 0; i < oldTS.GridColumnStyles.Count; i++)
{
if(i != fromColumn && fromColumn < toColumn)
newTS.GridColumnStyles.Add(oldTS.GridColumnStyles[i]);
if(i == toColumn)
newTS.GridColumnStyles.Add(oldTS.GridColumnStyles[fromColumn]);
if(i != fromColumn && fromColumn > toColumn)
newTS.GridColumnStyles.Add(oldTS.GridColumnStyles[i]);
}
TableStyles.Remove(oldTS);
TableStyles.Add(newTS);
}
![](http://www.codeproject.com/cs/miscctrl/ElvinDataGridEx/DataGridEx.jpg)
Introduction
DataGridis one of the most powerful Windows?Forms control. By using default
DataGridproperty settings you can easily bind a
DataSetto it to create an impressive Windows Forms user interface ?one that display large amounts of data efficiently and intuitively without bewildering the user.
Thanks to the extensible architecture of
DataGridcontrol, it gives developers the flexibility in hand to extend its functionalities, where native support is not sufficed. In this article, I am going to show you how to enhance the
DataGridcontrol with the drag and drop support for column reordering. This is particular useful in situation when you need to compare columns side-by-side that may not reside together by default.
Background
In this implementation, I've made use of some unmanaged Win32 APIs to perform the graphics drawing process ?one that draw the semi-transparent dragged column during the drag and drop operation. All these Win32 APIs are encapsulated in the WinGDI.cs file for the separation of managed and unmanaged code. Underpinnings the drawing of drag and drop support for column reordering is the functionBitBlt.
BitBlt?Bit Block Transfer, one of the powerful drawing functions which transfer a block of bits (a bitmap) from one device context to another. . One point worth mentioning in this API is that currently there are 17 constants defined for the
dwRop(Raster Operation Code) variable and you can easily create different kind of effects on image by changing the raster operation code.
SRCCOPY (0xcc0020)is the easiest to use and performs a simple copy action. [DllImport("gdi32.dll")]
public static extern bool BitBlt
(
IntPtr hdcDest, // handle to destination DC (device context)
int nXDest, // x-coord of destination upper-left corner
int nYDest, // y-coord of destination upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
IntPtr hdcSrc, // handle to source DC
int nXSrc, // x-coordinate of source upper-left corner
int nYSrc, // y-coordinate of source upper-left corner
System.Int32 dwRop // raster operation code
);
For more information on this API, please consult the Win32 documentation.
Using the code
To preserve the existing functionalities provided byDataGridcontrol, I抳e created a new control named
DataGridEx, which inherits from the existing
DataGridcontrol. A property
AllowUserToOrderColumnsis added, which enables or disables the control抯 ability to reorder the columns. In order to provide drag and drop for column reordering, the methods
OnMouseDown,
OnMouseMoveand
OnMouseUpof the base control must be overridden.
OnMouseDownis the method that will be called when column header is clicked. To initiate the drag operation, it entails the
AllowUserToOrderColumnsproperty has been set to true and the mouse button that initiates the click event must be left mouse button. Just before starting the drag operation,
ColumnStartDragevent will be fired to determine whether this column is drag-able. Developers at the application level can react to this event by setting the
Cancelvariable in the event arguments to true to stop the drag operation. It everything goes fine, the process of drag operation starts.protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
{
try
{
DataGrid.HitTestInfo hti = HitTest(e.X, e.Y);
/*
* The following conditions must be met in order to
* start of the drag operation
* 1) Column Header is clicked with left mouse button.
* 2) AllowUserToOrderColumns property has been set to true
*
* */
if (
(hti.Type == DataGrid.HitTestType.ColumnHeader)
&& ((e.Button & MouseButtons.Left) == MouseButtons.Left)
&& (allowColumnsReorder))
{
// Notify application that the drag operation is about to start
ColumnStartDragEventArgs csde = new ColumnStartDragEventArgs(
hti.Column, GetColumnName(hti.Column), false);
OnColumnStartDrag(csde);
if (!csde.Cancel) // This column is drag-able
{
// Remember the column header clicked
dragColumnIndex = hti.Column;
isColumnDragging = true;
/*
* Currently, there is no way to determine the drag column's top
* left position.
* Workaround : Assumes the mouse clicked in the middle of the
* drag column.
*
* */
mouseDelta = new Point
(
e.X - (e.X - (GetColumnWidth(hti.Column) / 2)),
(CaptionVisible == true ? GetCaptionHeight() : 0)
);
Point dragColumn = PointToScreen(new Point(e.X, mouseDelta.Y));
Point screenPoint = PointToScreen(new Point(e.X, e.Y));
screenPoint.X -= mouseDelta.X;
screenPoint.Y = dragColumn.Y;
// Retrieve the DataGridColumnStyle for the drag column
dragColumnStyle = GetColumnStyle(hti.Column);
// Create the screen graphic device
CreateDisplayDC();
// Determine the actual size of the dragged image
dragImageSize = new Size(dragColumnStyle.Width,
ColumnHeaderHeight - 2);
// Determine and create the image buffer.
buffer = new Bitmap(Math.Max(dragColumnStyle.Width,
NODROPIMAGE_WIDTH + 2), ColumnHeaderHeight);
bufferGraphics = Graphics.FromImage(buffer);
pBufferDC = bufferGraphics.GetHdc();
// Copy the rectangluar image from the screen into buffer.
WinGDI.BitBlt(pBufferDC, 0, 0, buffer.Width, buffer.Height,
pDisplayDC, screenPoint.X, screenPoint.Y, WinGDI.SRCCOPY);
// Store the image buffer position for tracking
bufferPos = new Point(screenPoint.X, screenPoint.Y);
}
}
}
catch(Exception) { /* Ignore */ }
finally
{
base.OnMouseDown(e);
}
}
}
OnMouseMovemethod will be called to draw the semi-transparent dragged column as the mouse moving around in the
DataGrid. If the dragged column is drag over to another column,
ColumnSequenceChangingevent will be fired to determine whether the dragged column can be dropped onto it. Developers at the application level can use this event to determine the droppable columns based on their condition. An X icon will be drawn on the dragged column to inform users that the particular column is not droppable. protected override void OnMouseMove(MouseEventArgs e)
{
try
{
DataGrid.HitTestInfo hti = HitTest(e.X, e.Y);
/*
* The following conditions must be met before
* performing the drawing of drag operation
* 1) AllowUserToOrderColumns property has been set to true
* 2) Column is being dragged with left mouse button
*
* */
if (
(allowColumnsReorder)
&& (isColumnDragging)
&& ((e.Button & MouseButtons.Left) == MouseButtons.Left))
{
if (hti.Column >= 0)
{
// Re-calculate the mouse location in the screen
Point screenPoint = PointToScreen(new Point(e.X, e.Y));
screenPoint.X -= mouseDelta.X;
screenPoint.Y = bufferPos.Y;
// Performs the image swapping
WinGDI.BitBlt(pDisplayDC, bufferPos.X, bufferPos.Y,
buffer.Width, buffer.Height, pBufferDC, 0,
0, WinGDI.SRCCOPY);
WinGDI.BitBlt(pBufferDC, 0, 0, buffer.Width, buffer.Height,
pDisplayDC, screenPoint.X, screenPoint.Y,
WinGDI.SRCCOPY);
bufferPos = new Point(screenPoint.X, screenPoint.Y);
/*
* Notify application that the dragged column is dragging over
* to another column and determines whether the dragged column
* can be dropped onto it.
*
* */
ColumnSequenceChangingEventArgs csce =
new ColumnSequenceChangingEventArgs(dragColumnIndex,
GetColumnName(dragColumnIndex), hti.Column,
GetColumnName(hti.Column), false);
OnColumnSequenceChanging(csce);
if (csce.Cancel) // Drop on this column is not allow
DrawDragImage(displayGraphics, screenPoint.X, screenPoint.Y, false);
else
DrawDragImage(displayGraphics, screenPoint.X, screenPoint.Y, true);
}
}
}
catch(Exception) { /* Ignore */ }
finally
{
base.OnMouseMove(e);
}
}
}
When the mouse button releases,
OnMouseUpmethod will be called to invoke the
MoveColumnfunction to reorder the columns if the dragged and dropped column is not the same.
ColumnSequenceChangedevent will be fired once the column reordering is done. This marks the end of the drag operation and performs the necessary house keeping. protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
{
try
{
DataGrid.HitTestInfo hti = HitTest(e.X, e.Y);
if(
(allowColumnsReorder)
&& (isColumnDragging)
&& ((e.Button & MouseButtons.Left) == MouseButtons.Left))
{
// Clean up the drawn image from the screen
WinGDI.BitBlt(pDisplayDC, bufferPos.X, bufferPos.Y, buffer.Width,
buffer.Height, pBufferDC, 0, 0, WinGDI.SRCCOPY);
/*
* The following conditions must be met before moving the drag column
* 1) Drop column is within bound
* 2) Source Column <> Destination Column
* */
if (hti.Column >= 0 && dragColumnIndex != hti.Column)
{
/*
* Notify application that the dragged column is about to drop onto
* another column.
* */
ColumnSequenceChangingEventArgs columnChanging =
new ColumnSequenceChangingEventArgs(dragColumnIndex,
GetColumnName(dragColumnIndex), hti.Column,
GetColumnName(hti.Column), false);
OnColumnSequenceChanging(columnChanging);
if (!columnChanging.Cancel) // Drop on this column is allowed
{
// Move the column
MoveColumn(dragColumnIndex, hti.Column);
// Notify application that the dragged column
// is reordered to new location
ColumnSequenceChangedEventArgs columnChanged =
new ColumnSequenceChangedEventArgs(columnChanging.SourceColumnIndex,
columnChanging.SourceColumnName, columnChanging.DestinationColumnIndex,
columnChanging.DestinationColumnName);
OnColumnSequenceChanged(columnChanged);
}
}
// House Keeping
isColumnDragging = false;
dragColumnIndex = -1;
dragColumnStyle = null;
DisposeDisplayDC();
DisposeBufferDC();
}
}
catch(Exception) { /* Ignore */ }
finally
{
base.OnMouseUp(e);
}
}
The cornerstone of drawing the dragged column is encapsulated in the function
DrawDragImage. A normal semi-transparent dragged column will be drawn when it drags over to those droppable columns. Otherwise, a semi-transparent dragged column with an X icon will be drawn. private void DrawDragImage(Graphics g, int x, int y, bool bEnabled)
{
try
{
g.SmoothingMode = SmoothingMode.AntiAlias;
// Anti-aliased rendering
Rectangle rect = new Rectangle(x, y, dragImageSize.Width,
dragImageSize.Height);
using(Pen p = new Pen(Color.Black))
{
// Semi-Transparent
using(Brush backBrush = new SolidBrush(Color.FromArgb(127,
Color.LightSteelBlue)))
{
using(Brush foreBrush = new SolidBrush(Color.Black))
{
g.FillRectangle(backBrush, rect.Left + 1, rect.Top + 1,
rect.Width - 2, rect.Height - 2);
g.DrawRectangle(p, rect.Left, rect.Top, rect.Width - 1,
rect.Height - 1);
using(StringFormat sf = new StringFormat(StringFormatFlags.NoWrap))
{
sf.LineAlignment = StringAlignment.Center;
if (dragColumnStyle.Alignment == HorizontalAlignment.Center)
sf.Alignment = StringAlignment.Center;
else if (dragColumnStyle.Alignment == HorizontalAlignment.Left)
sf.Alignment = StringAlignment.Near;
else if (dragColumnStyle.Alignment == HorizontalAlignment.Right)
sf.Alignment = StringAlignment.Far;
g.DrawString(dragColumnStyle.HeaderText, HeaderFont,
foreBrush, rect, sf);
}
// Draw an X icon in the semi-transparent drag column
if (!bEnabled)
{
using(Pen redPen = new Pen(new SolidBrush(Color.Red), 3))
{
// Note: Those offset applied here is meant to
// avoid drawing the X icon outside
// of the bound rectangle.
Point p1; Point p2; // X
Point p3; Point p4; // Y
if (dragImageSize.Width > NODROPIMAGE_WIDTH)
{
int left = rect.Left + ((dragImageSize.Width
- NODROPIMAGE_WIDTH) / 2);
p1 = new Point(left, rect.Top + 1);
p2 = new Point(left + NODROPIMAGE_WIDTH, rect.Top
+ buffer.Height - 2);
p3 = new Point(left + NODROPIMAGE_WIDTH, rect.Top + 1);
p4 = new Point(left, rect.Top + buffer.Height - 2);
}
else
{
p1 = new Point(rect.Left + 1, rect.Top + 1);
p2 = new Point(rect.Left + NODROPIMAGE_WIDTH - 1,
rect.Top + buffer.Height - 2);
p3 = new Point(rect.Left + NODROPIMAGE_WIDTH - 1,
rect.Top + 1);
p4 = new Point(rect.Left + 1, rect.Top + buffer.Height - 2);
}
redPen.StartCap = LineCap.Round;
redPen.EndCap = LineCap.Round;
g.DrawLine(redPen, p1, p2);
g.DrawLine(redPen, p3, p4);
}
}
}
}
}
}
catch(Exception) { /* Ignore */ }
}
MoveColumnperforms the intelligent column reordering where dragged column will be positioned before the dropped column if the dragged column was previously positioned after the dropped column and vice versa. public void MoveColumn(int fromColumn, int toColumn)
{
if(fromColumn == toColumn) return;
DataGridTableStyle oldTS = TableStyles[0];
DataGridTableStyle newTS = new DataGridTableStyle();
newTS.MappingName = oldTS.MappingName; // Table Name
CopyTableStyle(oldTS, newTS);
// Copy the old TableStyle to new TableStyle
for(int i = 0; i < oldTS.GridColumnStyles.Count; i++)
{
if(i != fromColumn && fromColumn < toColumn)
newTS.GridColumnStyles.Add(oldTS.GridColumnStyles[i]);
if(i == toColumn)
newTS.GridColumnStyles.Add(oldTS.GridColumnStyles[fromColumn]);
if(i != fromColumn && fromColumn > toColumn)
newTS.GridColumnStyles.Add(oldTS.GridColumnStyles[i]);
}
TableStyles.Remove(oldTS);
TableStyles.Add(newTS);
}
Points of Interest
For those developers who are interested to convert the drawing functions from unmanaged code to managed code, feel free to try theDrawImagemanaged API. However, the performance of
DrawImagefunction is slower than the Win32 counterpart, as it creates and destroys new device context for each call.
Conclusion
Column Reordering is just one enhancement to theDataGridcontrol. If the native functionalities provided in the Windows Forms controls aren't exactly what you need for all your scenarios, you can take advantage of the extensibility features of Windows Forms architecture to override and extend these controls to make them fit your particular needs.
相关文章推荐
- XHtmlTree - Tree control with support for HTML, XML, Smart Checkboxes, and Drag & Drop
- Drag and Drop Items in a WPF ListView
- Adding support for MrSid and other raster data formats in GeoServer
- Drag and Drop in WPF
- Support for EAP-SIM and EAP-AKA in Android.
- Drag and Drop: New Data Transfer Capabilities in the JavaTM 2 Platform, Standard Edition (J2SETM), version 1.4
- Atlas Control Toolkit and Source Code for the Build-in Asp.Net 2.0 Providers
- Simple Drag and Drop in ExtJS
- springMVC项目异步错误处理请求Async support must be enabled on a servlet and for all filters involved in async
- An explicit value for the identity column in table can only be specified when a column list is used and IDENTITY_INSERT is ON
- Drag-and-Drop(Chapter 23 of Cocoa Programming for Mac OS X)
- How to Drag and Drop in JavaScript
- Method and system for implementing mandatory file access control in native discretionary access control environments
- Drag And Drop In Javascript
- Grid Drag and Drop reorder rows
- Unicode database support in Tiburon for Delphi and C++
- Support for ViewState in Custom Control Properties
- Javascript Drag and drop for touch devices
- Drag and Drop control
- Basic drag and drop in WinForms