xenadmin/XenAdmin/Controls/CustomGridView/GridView.cs
Konstantina Chremmou d7b519a53c Updated copyright notice on files.
Signed-off-by: Konstantina Chremmou <Konstantina.Chremmou@cloud.com>
2023-01-30 16:24:16 +00:00

932 lines
33 KiB
C#

/* Copyright (c) Cloud Software Group, Inc.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace XenAdmin.Controls.CustomGridView
{
public enum MouseButtonAction
{
SingleClick, DoubleClick, MouseDown, StartDrag, SingleRightClick
}
public partial class GridView : Panel
{
public List<GridRow> Rows = new List<GridRow>();
// If currently painting the refresh call will set the PaintingRequired flag which will cause the panel to repaint after
public bool Painting = false;
public bool PaintingRequired = false;
// This draws to the control
private Graphics Graphics;
// This draws to the BackBuffer
private Graphics BufferGraphics;
// Stores the image while being drawn
private Bitmap BackBuffer;
/// <summary>
/// The width of the column containing the expander triangle, if required.
/// </summary>
private bool hasLeftExpanders = true;
public bool HasLeftExpanders
{
get { return hasLeftExpanders; }
set { hasLeftExpanders = value; }
}
private const int LEFT_OFFSET = 20;
public int LeftOffset
{
get
{
return HasLeftExpanders ? LEFT_OFFSET : 0;
}
}
// Row selection
protected string lastClickedRowPath = null;
public GridRow LastClickedRow
{
set
{
lastClickedRowPath = (value == null ? null : value.Path);
}
}
Point lastClickedPoint = new Point(0, 0);
// Iterate over all rows including child rows, in display order
public IEnumerable<GridRow> RowsAndChildren
{
get
{
foreach (GridRow row in Rows)
{
yield return row;
foreach (GridRow child in row.RowsAndChildren)
yield return child;
}
}
}
public GridView()
{
InitBuffer();
InitializeComponent();
}
// The top row in the list, NEVER set this! <- no need to dispose explicitly as will be disposed when the contents of Rows is disposed
public GridHeaderRow HeaderRow;
private bool hold_cursor_change = false;
private Cursor new_cursor = null;
public override Cursor Cursor
{
set
{
if (hold_cursor_change)
new_cursor = value;
else
base.Cursor = value;
}
}
/// <summary>
/// Set the size of the back buffer to the size of the control
/// </summary>
private void InitBuffer()
{
Graphics = this.CreateGraphics();
Rectangle disp = RealRectangle;
BackBuffer = new Bitmap(disp.Width > 0 ? disp.Width : 1, disp.Height > 0 ? disp.Height : 1);
BufferGraphics = Graphics.FromImage(BackBuffer);
BufferGraphics.TextRenderingHint = Graphics.TextRenderingHint;
}
/// <summary>
/// Update all values in the grid
/// </summary>
public override void Refresh()
{
//if (Painting)
//{
// we are currently painting, set a flag and return
// the painting will occur when the current paint has finished
// the idea is that if we get loads of calls to this then we only repaint at most once after each paint
// this is why i dont think we should have a lock as they would wait then paint all afterwards
// PaintingRequired = true;
//}
//else
//{
// we are painting
//Painting = true;
Draw(RealRectangle);
Painting = false; // slight chance of a race occuring but if we end up painting 3 times instead of just 2 it wont be the world
// if (PaintingRequired)
// {
// // we need to paint again
// PaintingRequired = false;
// Refresh();
// }
//}
}
protected override void OnInvalidated(InvalidateEventArgs e)
{
//OnPaint(null);
}
/// <summary>
/// Gets the currently displayed rectangle of the control (ie includes how far we have scrolled)
/// </summary>
protected Rectangle RealRectangle
{
get
{
Rectangle r = ClientRectangle;
r.Offset(-AutoScrollPosition.X, -AutoScrollPosition.Y);
return r;
}
}
// refresh on scroll
protected override void OnScroll(ScrollEventArgs se)
{
Refresh();
}
protected override void OnResize(EventArgs eventargs)
{
// ignore this size changed
}
protected override void OnClientSizeChanged(EventArgs e)
{
// ignore this size changed
}
protected override void OnSizeChanged(EventArgs e)
{
// use this one instead
base.OnResize(e); // do size change <= calling on resize here may seem barking but it appears to be the only combination that works...
DisposeBuffer(); // reinitalise buffer
InitBuffer();
Refresh(); //refresh
}
// dispose
private void DisposeBuffer()
{
BackBuffer.Dispose();
BufferGraphics.Dispose();
Graphics.Dispose();
}
/// <summary>
/// Render the contents of the rectangle to the buffer
/// </summary>
/// <param name="rectangle"></param>
protected void Draw(Rectangle rectangle)
{
RenderToBuffer(new PaintEventArgs(BufferGraphics, rectangle));
OnPaint(null);
}
private void RenderToBuffer(PaintEventArgs paintEventArgs)
{
if (Disposing || IsDisposed || Program.Exiting)
return;
// make rectangle a little bigger just in case
Rectangle invalid = paintEventArgs.ClipRectangle;
invalid.Offset(AutoScrollPosition);
// paint background
base.OnPaintBackground(new PaintEventArgs(paintEventArgs.Graphics, invalid));
// paint rows
int height = Padding.Top + AutoScrollPosition.Y;
int width = TotalWidth();
int left = Padding.Left + AutoScrollPosition.X;
// draw header
if (HeaderRow != null)
{
int headerrowheight = HeaderRow.RowAndChildrenHeight;
if (height >= invalid.Top - headerrowheight && height <= invalid.Bottom + headerrowheight)
HeaderRow.OnPaint(new RowPaintArgs(paintEventArgs.Graphics, invalid, new Rectangle(left, height, width, headerrowheight)));
height += headerrowheight + HeaderRow.SpaceAfter;
}
int numRows = Rows.Count;
for (int i = 0; i < numRows; ++i)
{
GridRow row = Rows[i];
int rowheight = row.RowAndChildrenHeight;
if (height >= invalid.Top - rowheight && height <= invalid.Bottom + rowheight)
row.OnPaint(new RowPaintArgs(paintEventArgs.Graphics, invalid, new Rectangle(left, height, width, rowheight)));
height += rowheight;
if (i < numRows - 1)
height += row.SpaceAfter;
}
height += Padding.Bottom;
// set the clientrecangle to update the autoscrollbar
AutoScrollMinSize = new Size(GetMinColumn(), height - AutoScrollPosition.Y);
//base.OnPaint(paintEventArgs);
}
private int TotalWidth()
{
int allowedwidth = ClientSize.Width - Padding.Horizontal;
if (HeaderRow == null)
return allowedwidth;
int actualwidth = GetMinColumn() - Padding.Horizontal;
return actualwidth > allowedwidth ? actualwidth : allowedwidth;
}
private int GetMinColumn()
{
if (HeaderRow == null)
return 0;
int total = Padding.Horizontal + LeftOffset;
foreach (string col in HeaderRow.Columns)
{
total += HeaderRow.GetColumnWidth(col);
}
return total;
}
protected override void OnPaint(PaintEventArgs e)
{
if (Disposing || IsDisposed || Program.Exiting)
return;
if (!DraggingColumns)
{
// we dont need to render again apparently :)
Core.Drawing.QuickDraw(Graphics, BackBuffer);
}
else
{
//paint control
IntPtr pTarget = DragColumnsGraphics.GetHdc();
IntPtr pSource = Core.Drawing.CreateCompatibleDC(pTarget);
IntPtr pOrig = Core.Drawing.SelectObject(pSource, BackBuffer.GetHbitmap());
Core.Drawing.BitBlt(pTarget, 0, 0, BackBuffer.Width, BackBuffer.Height, pSource, 0, 0, Core.Drawing.TernaryRasterOperations.SRCCOPY);
IntPtr pNew = Core.Drawing.SelectObject(pSource, pOrig);
Core.Drawing.DeleteObject(pNew);
Core.Drawing.DeleteDC(pSource);
//DragGraphics.ReleaseHdc(pTarget);
// paint dragged stuff
//IntPtr pTarget2 = DragGraphics.GetHdc();
IntPtr pSource2 = Core.Drawing.CreateCompatibleDC(pTarget);
IntPtr pOrig2 = Core.Drawing.SelectObject(pSource2, DragColumnsData.GetHbitmap());
Core.Drawing.BitBlt(pTarget, DragColumnsWindowPosition.X, DragColumnsWindowPosition.Y, DragColumnsData.Width, DragColumnsData.Height, pSource2, 0, 0, Core.Drawing.TernaryRasterOperations.SRCAND);
IntPtr pNew2 = Core.Drawing.SelectObject(pSource2, pOrig2);
Core.Drawing.DeleteObject(pNew2);
Core.Drawing.DeleteDC(pSource2);
DragColumnsGraphics.ReleaseHdc(pTarget);
// paint everything to screen
IntPtr pTarget3 = Graphics.GetHdc();
IntPtr pSource3 = Core.Drawing.CreateCompatibleDC(pTarget3);
IntPtr pOrig3 = Core.Drawing.SelectObject(pSource3, DragColumnsBuffer.GetHbitmap());
Core.Drawing.BitBlt(pTarget3, 0, 0, DragColumnsBuffer.Width, DragColumnsBuffer.Height, pSource3, 0, 0, Core.Drawing.TernaryRasterOperations.SRCCOPY);
IntPtr pNew3 = Core.Drawing.SelectObject(pSource3, pOrig3);
Core.Drawing.DeleteObject(pNew3);
Core.Drawing.DeleteDC(pSource3);
Graphics.ReleaseHdc(pTarget3);
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//base.OnPaintBackground(e);
}
private bool DraggingItems;
private bool DraggingColumns = false;
private Bitmap DragColumnsData;
private Point DragColumnsWindowPosition;
private Point DragColumnsMouseLocation;
private string ActiveColumn = "";
private Bitmap DragColumnsBuffer;
Graphics DragColumnsGraphics;
string DragColumnsLastEntered = "";
GridRow LastRow;
bool ResizingColumns = false;
Point ResizeColumnsInitialMouseLocation;
protected override void OnMouseUp(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && DraggingColumns)
{
string swapwith = "";
int left = Padding.Left;
foreach (string index in HeaderRow.Columns)
{
int width = GetColumnWidth(index, 1);
if (e.X - AutoScrollPosition.X < left + (width / 2) && !((GridHeaderItem)HeaderRow.Items[index]).Immovable)
{
swapwith = index;
break;
}
left += width;
}
if (string.IsNullOrEmpty(swapwith))
swapwith = "end";
DraggingColumns = false;
if (!HeaderRow.Items.ContainsKey(ActiveColumn))
return;
((GridHeaderItem)HeaderRow.Items[ActiveColumn]).GreyOut = false;
if (DragColumnsData != null)
{
DragColumnsData.Dispose();
DragColumnsData = null;
}
if (DragColumnsBuffer != null)
{
DragColumnsBuffer.Dispose();
DragColumnsBuffer = null;
}
if (DragColumnsGraphics != null)
{
DragColumnsGraphics.Dispose();
DragColumnsGraphics = null;
}
if (swapwith == "end")
{
HeaderRow.Columns.Remove(ActiveColumn);
HeaderRow.Columns.Add(ActiveColumn);
}
else
{
int movedn = HeaderRow.Columns.IndexOf(ActiveColumn);
int replacedn = HeaderRow.Columns.IndexOf(swapwith);
if (movedn > replacedn)
{
HeaderRow.Columns.Remove(ActiveColumn);
HeaderRow.Columns.Insert(replacedn, ActiveColumn);
}
else if (movedn < replacedn)
{
HeaderRow.Columns.Insert(replacedn, ActiveColumn);
HeaderRow.Columns.Remove(ActiveColumn);
}
}
DragColumnsLastEntered = "";
Refresh();
}
else if (e.Button == MouseButtons.Left && ResizingColumns)
{
ResizingColumns = false;
}
ActiveColumn = "";
}
public void AddRow(GridRow row)
{
Rows.Add(row);
row.GridView = this;
}
public void SetHeaderRow(GridHeaderRow hr)
{
hr.GridView = this;
}
/// <summary>
/// Returns the width of the specified columns (ie index to index + span)
/// </summary>
internal int GetColumnWidth(string col, int span)
{
if (HeaderRow == null) return 0;
int total = 0;
int index = HeaderRow.Columns.IndexOf(col);
for (int i = index; i < index + span; i++)
{
if (HeaderRow.Columns.Count <= i)
break;
total += HeaderRow.GetColumnWidth(HeaderRow.Columns[i]);
}
return total;
}
/// <summary>
/// Scroll up or down the list only if it has been focused
/// </summary>
protected override void OnMouseWheel(MouseEventArgs e)
{
AutoScrollPosition = new Point(-AutoScrollPosition.X, -AutoScrollPosition.Y - e.Delta);
OnScroll(new ScrollEventArgs(ScrollEventType.EndScroll, 0));
}
protected virtual void OnMouseButtonAction(MouseEventArgs e, MouseButtonAction type)
{
if (HeaderRow == null)
return;
if (!DraggingColumns && !ResizingColumns)
{
this.Focus();
Point p;
GridRow row = FindRowFromPoint(e.Location, out p);
if (row == null)
return;
if (e.Button == MouseButtons.Right && row is GridHeaderRow)
{
OpenChooseColumnsMenu(e.Location);
}
else if (e.Button == MouseButtons.Left)
{
if (Cursor == Cursors.SizeWE)
{
if (type == MouseButtonAction.DoubleClick)
FitColumnWidthToHeaderAndContents(row, p);
}
else
{
row.OnMouseButtonAction(p, type);
}
}
else if (type == MouseButtonAction.SingleRightClick)
{
row.OnMouseButtonAction(p, type);
}
}
}
private void FitColumnWidthToHeaderAndContents(GridRow currentRow, Point p)
{
GridHeaderItem headerItem = (GridHeaderItem)currentRow.FindItemFromPoint(new Point(p.X - GridHeaderItem.ResizeGutter, p.Y), out ResizeColumnsInitialMouseLocation);
ResizeColumnsInitialMouseLocation.X += GridHeaderItem.ResizeGutter;
ActiveColumn = headerItem.ColumnName;
if (HeaderRow.Items.ContainsKey(ActiveColumn))
{
int maxWidth = headerItem.MinimumWidth;
foreach (GridRow row in RowsAndChildren)
{
GridItemBase _item = row.GetItem(ActiveColumn);
int itemWidth = _item.GetGridItemWidth(ActiveColumn);
if (itemWidth > maxWidth)
maxWidth = itemWidth;
}
headerItem.Width = maxWidth;
Refresh();
}
}
protected override void OnMouseClick(MouseEventArgs e)
{
OnMouseButtonAction(e, e.Button == MouseButtons.Left ? MouseButtonAction.SingleClick : MouseButtonAction.SingleRightClick);
}
protected override void OnMouseDoubleClick(MouseEventArgs e)
{
OnMouseButtonAction(e, MouseButtonAction.DoubleClick);
}
protected override void OnMouseDown(MouseEventArgs e)
{
lastClickedPoint = e.Location;
OnMouseButtonAction(e, MouseButtonAction.MouseDown);
}
public virtual void OpenChooseColumnsMenu(Point p)
{
}
protected override void OnMouseMove(MouseEventArgs e)
{
HoldCursorChange(delegate() { OnMouseMove_(e); });
}
private void HoldCursorChange(MethodInvoker handler)
{
hold_cursor_change = true;
try
{
handler();
}
finally
{
hold_cursor_change = false;
if (new_cursor != null)
{
Cursor = new_cursor;
new_cursor = null;
}
}
}
private void OnMouseMove_(MouseEventArgs e)
{
if (Disposing || IsDisposed || Program.Exiting)
return;
if (HeaderRow == null)
return;
if (DraggingItems)
return;
if (DraggingColumns)
{
int x = e.Location.X - DragColumnsMouseLocation.X;
int xmax = TotalWidth() - DragColumnsData.Width;
DragColumnsWindowPosition = new Point(x <= 0 ? 0 : x < xmax ? x : xmax, 0);
string swapwith = "";
int left = Padding.Left;
foreach (string index in HeaderRow.Columns)
{
int width = GetColumnWidth(index, 1);
if (((GridHeaderItem)HeaderRow.Items[index]).Immovable)
{
left += width;
continue;
}
if (e.X - AutoScrollPosition.X < left + (width / 2))
{
swapwith = index;
break;
}
left += width;
}
if (string.IsNullOrEmpty(swapwith))
swapwith = "end";
if (swapwith != DragColumnsLastEntered)
{
if (swapwith == "end")
{
HeaderRow.Columns.Remove(ActiveColumn);
HeaderRow.Columns.Add(ActiveColumn);
}
else
{
int movedn = HeaderRow.Columns.IndexOf(ActiveColumn);
int replacedn = HeaderRow.Columns.IndexOf(swapwith);
if (movedn > replacedn)
{
HeaderRow.Columns.Remove(ActiveColumn);
HeaderRow.Columns.Insert(replacedn, ActiveColumn);
}
else if (movedn < replacedn)
{
HeaderRow.Columns.Insert(replacedn, ActiveColumn);
HeaderRow.Columns.Remove(ActiveColumn);
}
}
DragColumnsLastEntered = swapwith;
Refresh();
}
else
{
OnPaint(null);
}
}
else if (ResizingColumns)
{
if (HeaderRow.Items.ContainsKey(ActiveColumn))
{
GridHeaderItem item = (HeaderRow.Items[ActiveColumn] as GridHeaderItem);
int newWidth = item.Width + (e.Location.X - ResizeColumnsInitialMouseLocation.X);
if (newWidth > item.MinimumWidth)
{
item.Width = newWidth;
ResizeColumnsInitialMouseLocation = e.Location;
}
else
{
item.Width = item.MinimumWidth;
}
Refresh();
}
}
else if (e.Button == MouseButtons.Left && string.IsNullOrEmpty(ActiveColumn) &&
DragDistance(lastClickedPoint, e.Location) >= 2) // don't start dragging unles we've moved a little distance
// TODO: consider replacing the above with SystemParameters.MinimumHorizontalDragDistance etc. when we move to .NET 3.0
{
Point p;
GridRow row = FindRowFromPoint(lastClickedPoint, out p); // the drag is then based on the mouse-down location
if (row is GridHeaderRow)
{
GridHeaderItem item = (GridHeaderItem)row.FindItemFromPoint(new Point(p.X - GridHeaderItem.ResizeGutter, p.Y), out DragColumnsMouseLocation);
DragColumnsMouseLocation.X += GridHeaderItem.ResizeGutter;
if (item == null)
return;
ActiveColumn = item.ColumnName;
int colwidth = GetColumnWidth(ActiveColumn, 1);
if (!item.UnSizable && DragColumnsMouseLocation.X >= colwidth - GridHeaderItem.ResizeGutter)
{
ResizingColumns = true;
ResizeColumnsInitialMouseLocation = lastClickedPoint;
}
else if (!item.Immovable)
{
DraggingColumns = true;
item.GreyOut = true;
DragColumnsData = new Bitmap(GetColumnWidth(ActiveColumn, 1), ClientSize.Height);
Graphics ddGraphics = Graphics.FromImage(DragColumnsData);
ddGraphics.Clear(BackColor);
XenAdmin.Core.Drawing.QuickDraw(ddGraphics, BackBuffer, new Point((lastClickedPoint.X - DragColumnsMouseLocation.X), 0), new Rectangle(0, 0, DragColumnsData.Width, DragColumnsData.Height));
ddGraphics.Dispose();
DragColumnsBuffer = new Bitmap(ClientSize.Width, ClientSize.Height);
DragColumnsGraphics = Graphics.FromImage(DragColumnsBuffer);
}
}
else if (row != null)
row.OnMouseButtonAction(p, MouseButtonAction.StartDrag);
}
else
{
Point p;
GridRow row = FindRowFromPoint(e.Location, out p);
if (LastRow == null && row == null)
return;
if (LastRow == row)
{
LastRow.OnMouseMove(p);
}
else
{
if (LastRow != null)
LastRow.OnLeave();
LastRow = row;
if (LastRow != null)
LastRow.OnEnter(p);
}
}
}
// The L_1 distance between two points
private int DragDistance(Point p1, Point p2)
{
int xDisp = p1.X - p2.X;
int yDisp = p1.Y - p2.Y;
int totDisp = (xDisp >= 0 ? xDisp : -xDisp) + (yDisp >= 0 ? yDisp : -yDisp);
return totDisp;
}
protected override void OnMouseLeave(EventArgs e)
{
HoldCursorChange(delegate()
{
if (LastRow != null)
LastRow.OnLeave();
});
}
/// <summary>
/// Takes the point in question (eg location of the mouseclick) and returns the row
/// that was clicked and the point on that row (ie adjusted so that 0,0 is top left of that row)
/// </summary>
private GridRow FindRowFromPoint(Point point, out Point p)
{
int height = Padding.Top + AutoScrollPosition.Y;
p = Point.Empty;
if (HeaderRow != null)
{
if (RowContainsPoint(HeaderRow, point, ref height, ref p))
return HeaderRow;
}
foreach (GridRow row in Rows)
{
if (RowContainsPoint(row, point, ref height, ref p))
return row;
}
return null;
}
private bool RowContainsPoint(GridRow row, Point point, ref int height, ref Point p)
{
int rowheight = row.RowAndChildrenHeight;
if (point.Y >= height && point.Y < height + rowheight)
{
p = new Point(point.X - Padding.Left - AutoScrollPosition.X, point.Y - height);
return true;
}
else
{
height += rowheight + row.SpaceAfter;
return false;
}
}
private Dictionary<string, RowState> saveState;
protected void SaveRowStates()
{
saveState = new Dictionary<string, RowState>();
foreach (GridRow row in RowsAndChildren)
saveState[row.Path] = row.State;
}
protected void RestoreRowStates()
{
RowState state;
foreach (GridRow row in RowsAndChildren)
{
if (saveState.TryGetValue(row.Path, out state))
row.State = state;
}
}
internal void UnselectAllRowsExcept(GridRow notThisOne)
{
foreach (GridRow row in RowsAndChildren)
{
if (row != notThisOne)
row.Selected = false;
}
Refresh();
}
internal void UnselectAllRows()
{
UnselectAllRowsExcept(null);
}
internal void SelectRowRange(GridRow newRow)
{
UnselectAllRows();
// Once through to check we haven't lost either of the endpoints
// for some reason
bool foundLast = false;
bool foundNew = false;
if (lastClickedRowPath != null)
{
foreach (GridRow row in RowsAndChildren)
{
if (row.Path == lastClickedRowPath)
foundLast = true;
if (row == newRow)
foundNew = true;
if (foundLast && foundNew)
break;
}
}
// If endpoint is missing, turn it into a normal select
if (!foundLast || !foundNew)
{
newRow.Selected = true;
LastClickedRow = newRow;
}
// Otherwise do the proper range select.
// Make sure to include both endpoints.
foundLast = foundNew = false;
foreach (GridRow row in RowsAndChildren)
{
if (row.Path == lastClickedRowPath)
foundLast = true;
if (row == newRow)
foundNew = true;
if (foundLast || foundNew)
row.Selected = true;
if (foundLast && foundNew)
break;
}
}
public void StartDragDrop()
{
GridRowCollection rows = new GridRowCollection();
foreach (GridRow row in RowsAndChildren)
{
if (row.Selected && IsDraggableRow(row))
rows.Add(row);
}
if (rows.Count > 0)
DoDragDrop(rows, DragDropEffects.Move);
}
protected virtual bool IsDraggableRow(GridRow row)
{
return true;
}
/// <summary>
/// Equivalent to Clear(false).
/// </summary>
internal void Clear()
{
Clear(false);
}
/// <summary>
/// Removes all rows from the GridView.
/// </summary>
/// <param name="removeHeaders">If true, removes GridHeaderRows too.</param>
internal void Clear(bool removeHeaders)
{
Rows.RemoveAll(new Predicate<GridRow>(delegate(GridRow row)
{
return removeHeaders || !(row is GridHeaderRow);
}));
}
internal virtual void Sort()
{
Rows.Sort();
foreach (GridRow row in Rows)
{
row.Sort();
}
LastClickedRow = null;
}
public List<KeyValuePair<String, int>> ColumnsAndWidths
{
get
{
List<KeyValuePair<String, int>> columns = new List<KeyValuePair<String, int>>();
if (HeaderRow == null)
return columns;
foreach (String columnName in HeaderRow.Columns)
{
if (!HeaderRow.Items.ContainsKey(columnName))
continue;
GridHeaderItem item = HeaderRow.Items[columnName] as GridHeaderItem;
if (item == null)
continue;
columns.Add(new KeyValuePair<String, int>(columnName, item.Width));
}
return columns;
}
}
protected override void OnDragEnter(DragEventArgs e)
{
DraggingItems = true;
e.Effect = DragDropEffects.None;
base.OnDragEnter(e);
}
protected override void OnDragLeave(EventArgs e)
{
DraggingItems = false;
base.OnDragLeave(e);
}
}
}