//#########################################################################################
//★★★★★★★ http://www.cnpopsoft.com [华普软件] ★★★★★★★
//★★★★★★★ 华普软件 - VB & C#.NET 专业论文与源码荟萃! ★★★★★★★
//#########################################################################################
/*
* Copyright ?2005, Mathew Hall
* All rights reserved.
*
* 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 OWNER 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;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;
using XPTable.Events;
using XPTable.Models.Design;
namespace XPTable.Models
{
///
/// Represents a collection of Rows and Cells displayed in a Table.
///
[DesignTimeVisible(true),
ToolboxItem(true),
ToolboxBitmap(typeof(TableModel))]
public class TableModel : Component
{
#region Event Handlers
///
/// Occurs when a Row is added to the TableModel
///
public event TableModelEventHandler RowAdded;
///
/// Occurs when a Row is removed from the TableModel
///
public event TableModelEventHandler RowRemoved;
///
/// Occurs when the value of the TableModel Selection property changes
///
public event SelectionEventHandler SelectionChanged;
///
/// Occurs when the value of the RowHeight property changes
///
public event EventHandler RowHeightChanged;
#endregion
#region Class Data
///
/// The default height of a Row
///
public static readonly int DefaultRowHeight = 15;
///
/// The minimum height of a Row
///
public static readonly int MinimumRowHeight = 14;
///
/// The maximum height of a Row
///
public static readonly int MaximumRowHeight = 1024;
///
/// The collection of Rows's contained in the TableModel
///
private RowCollection rows;
///
/// The Table that the TableModel belongs to
///
private Table table;
///
/// The currently selected Rows and Cells
///
private Selection selection;
///
/// The height of each Row in the TableModel
///
private int rowHeight;
#endregion
#region Constructor
///
/// Initializes a new instance of the TableModel class with default settings
///
public TableModel()
{
this.Init();
}
///
/// Initializes a new instance of the TableModel class with an array of Row objects
///
/// An array of Row objects that represent the Rows
/// of the TableModel
public TableModel(Row[] rows)
{
if (rows == null)
{
throw new ArgumentNullException("rows", "Row[] cannot be null");
}
this.Init();
if (rows.Length > 0)
{
this.Rows.AddRange(rows);
}
}
///
/// Initialise default settings
///
private void Init()
{
this.rows = null;
this.selection = new Selection(this);
this.table = null;
this.rowHeight = TableModel.DefaultRowHeight;
}
#endregion
#region Methods
///
/// Releases the unmanaged resources used by the TableModel and optionally
/// releases the managed resources
///
protected override void Dispose(bool disposing)
{
if (disposing)
{
}
base.Dispose(disposing);
}
///
/// Returns the index of the Row that lies on the specified position
///
/// The y-coordinate to check
/// The index of the Row at the specified position or -1 if
/// no Row is found
public int RowIndexAt(int yPosition)
{
int row = yPosition / this.RowHeight;
if (row < 0 || row > this.Rows.Count - 1)
{
return -1;
}
return row;
}
#endregion
#region Properties
///
/// Gets the Cell located at the specified row index and column index
///
/// The row index of the Cell
/// The column index of the Cell
[Browsable(false)]
public Cell this[int row, int column]
{
get
{
if (row < 0 || row >= this.Rows.Count)
{
return null;
}
if (column < 0 || column >= this.Rows[row].Cells.Count)
{
return null;
}
return this.Rows[row].Cells[column];
}
}
///
/// Gets the Cell located at the specified cell position
///
/// The position of the Cell
[Browsable(false)]
public Cell this[CellPos cellPos]
{
get
{
return this[cellPos.Row, cellPos.Column];
}
}
///
/// A TableModel.RowCollection representing the collection of
/// Rows contained within the TableModel
///
[Category("Behavior"),
Description("Row Collection"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Editor(typeof(RowCollectionEditor), typeof(UITypeEditor))]
public RowCollection Rows
{
get
{
if (this.rows == null)
{
this.rows = new RowCollection(this);
}
return this.rows;
}
}
///
/// A TableModel.Selection representing the collection of selected
/// Rows and Cells contained within the TableModel
///
[Browsable(false)]
public Selection Selections
{
get
{
if (this.selection == null)
{
this.selection = new Selection(this);
}
return this.selection;
}
}
///
/// Gets or sets the height of each Row in the TableModel
///
[Category("Appearance"),
Description("The height of each row")]
public int RowHeight
{
get
{
return this.rowHeight;
}
set
{
if (value < TableModel.MinimumRowHeight)
{
value = TableModel.MinimumRowHeight;
}
else if (value > TableModel.MaximumRowHeight)
{
value = TableModel.MaximumRowHeight;
}
if (this.rowHeight != value)
{
this.rowHeight = value;
this.OnRowHeightChanged(EventArgs.Empty);
}
}
}
///
/// Specifies whether the RowHeight property should be serialized at
/// design time
///
/// true if the RowHeight property should be serialized,
/// false otherwise
private bool ShouldSerializeRowHeight()
{
return this.rowHeight != TableModel.DefaultRowHeight;
}
///
/// Gets the total height of all the Rows in the TableModel
///
[Browsable(false)]
public int TotalRowHeight
{
get
{
return this.Rows.Count * this.RowHeight;
}
}
///
/// Gets the Table the TableModel belongs to
///
[Browsable(false)]
public Table Table
{
get
{
return this.table;
}
}
///
/// Gets or sets the Table the TableModel belongs to
///
internal Table InternalTable
{
get
{
return this.table;
}
set
{
this.table = value;
}
}
///
/// Gets whether the TableModel is able to raise events
///
protected internal bool CanRaiseEvents
{
get
{
// check if the Table that the TableModel belongs to is able to
// raise events (if it can't, the TableModel shouldn't raise
// events either)
if (this.Table != null)
{
return this.Table.CanRaiseEvents;
}
return true;
}
}
///
/// Gets whether the TableModel is enabled
///
internal bool Enabled
{
get
{
if (this.Table == null)
{
return true;
}
return this.Table.Enabled;
}
}
///
/// Updates the Row's Index property so that it matches the Rows
/// position in the RowCollection
///
/// The index to start updating from
internal void UpdateRowIndicies(int start)
{
if (start == -1)
{
start = 0;
}
for (int i=start; i
/// Raises the RowAdded event
///
/// A TableModelEventArgs that contains the event data
protected internal virtual void OnRowAdded(TableModelEventArgs e)
{
e.Row.InternalTableModel = this;
e.Row.InternalIndex = e.RowFromIndex;
e.Row.ClearSelection();
this.UpdateRowIndicies(e.RowFromIndex);
if (this.CanRaiseEvents)
{
if (this.Table != null)
{
this.Table.OnRowAdded(e);
}
if (RowAdded != null)
{
RowAdded(this, e);
}
}
}
///
/// Raises the RowRemoved event
///
/// A TableModelEventArgs that contains the event data
protected internal virtual void OnRowRemoved(TableModelEventArgs e)
{
if (e.Row != null && e.Row.TableModel == this)
{
e.Row.InternalTableModel = null;
e.Row.InternalIndex = -1;
if (e.Row.AnyCellsSelected)
{
e.Row.ClearSelection();
this.Selections.RemoveRow(e.Row);
}
}
this.UpdateRowIndicies(e.RowFromIndex);
if (this.CanRaiseEvents)
{
if (this.Table != null)
{
this.Table.OnRowRemoved(e);
}
if (RowRemoved != null)
{
RowRemoved(this, e);
}
}
}
///
/// Raises the SelectionChanged event
///
/// A SelectionEventArgs that contains the event data
protected virtual void OnSelectionChanged(SelectionEventArgs e)
{
if (this.CanRaiseEvents)
{
if (this.Table != null)
{
this.Table.OnSelectionChanged(e);
}
if (SelectionChanged != null)
{
SelectionChanged(this, e);
}
}
}
///
/// Raises the RowHeightChanged event
///
/// An EventArgs that contains the event data
protected virtual void OnRowHeightChanged(EventArgs e)
{
if (this.CanRaiseEvents)
{
if (this.Table != null)
{
this.Table.OnRowHeightChanged(e);
}
if (RowHeightChanged != null)
{
RowHeightChanged(this, e);
}
}
}
///
/// Raises the RowPropertyChanged event
///
/// A RowEventArgs that contains the event data
internal void OnRowPropertyChanged(RowEventArgs e)
{
if (this.Table != null)
{
this.Table.OnRowPropertyChanged(e);
}
}
///
/// Raises the CellAdded event
///
/// A RowEventArgs that contains the event data
internal void OnCellAdded(RowEventArgs e)
{
if (this.Table != null)
{
this.Table.OnCellAdded(e);
}
}
///
/// Raises the CellRemoved event
///
/// A RowEventArgs that contains the event data
internal void OnCellRemoved(RowEventArgs e)
{
if (this.Table != null)
{
this.Table.OnCellRemoved(e);
}
}
///
/// Raises the CellPropertyChanged event
///
/// A CellEventArgs that contains the event data
internal void OnCellPropertyChanged(CellEventArgs e)
{
if (this.Table != null)
{
this.Table.OnCellPropertyChanged(e);
}
}
#endregion
#region Selection
///
/// Represents the collection of selected Rows and Cells in a TableModel.
///
public class Selection
{
#region Class Data
///
/// The TableModel that owns the Selection
///
private TableModel owner;
///
/// The list of Rows that have selected Cells
///
private ArrayList rows;
///
/// The starting cell of a selection that uses the shift key
///
private CellPos shiftSelectStart;
///
/// The ending cell of a selection that uses the shift key
///
private CellPos shiftSelectEnd;
#endregion
#region Constructor
///
/// Initializes a new instance of the TableModel.Selection class
/// that belongs to the specified TableModel
///
/// A TableModel representing the tableModel that owns
/// the Selection
public Selection(TableModel owner)
{
if (owner == null)
{
throw new ArgumentNullException("owner", "owner cannot be null");
}
this.owner = owner;
this.rows = new ArrayList();
this.shiftSelectStart = CellPos.Empty;
this.shiftSelectEnd = CellPos.Empty;
}
#endregion
#region Methods
#region Add
///
/// Replaces the currently selected Cells with the Cell at the specified
/// row and column indexes
///
/// The row index of the Cell to be selected
/// The column index of the Cell to be selected
public void SelectCell(int row, int column)
{
// don't bother going any further if the cell
// is already selected
if (this.rows.Count == 1)
{
Row r = (Row) this.rows[0];
if (r.InternalIndex == row && r.SelectedCellCount == 1)
{
if (column >= 0 && column < r.Cells.Count)
{
if (r.Cells[column].Selected)
{
return;
}
}
}
}
this.SelectCells(row, column, row, column);
}
///
/// Replaces the currently selected Cells with the Cell at the specified CellPos
///
/// A CellPos thst specifies the row and column indicies of
/// the Cell to be selected
public void SelectCell(CellPos cellPos)
{
this.SelectCell(cellPos.Row, cellPos.Column);
}
///
/// Replaces the currently selected Cells with the Cells located between the specified
/// start and end row/column indicies
///
/// The row index of the start Cell
/// The column index of the start Cell
/// The row index of the end Cell
/// The column index of the end Cell
public void SelectCells(int startRow, int startColumn, int endRow, int endColumn)
{
int[] oldSelectedIndicies = this.SelectedIndicies;
this.InternalClear();
if (this.InternalAddCells(startRow, startColumn, endRow, endColumn))
{
this.owner.OnSelectionChanged(new SelectionEventArgs(this.owner, oldSelectedIndicies, this.SelectedIndicies));
}
this.shiftSelectStart = new CellPos(startRow, startColumn);
this.shiftSelectEnd = new CellPos(endRow, endColumn);
}
///
/// Replaces the currently selected Cells with the Cells located between the specified
/// start and end CellPos
///
/// A CellPos that specifies the start Cell
/// A CellPos that specifies the end Cell
public void SelectCells(CellPos start, CellPos end)
{
this.SelectCells(start.Row, start.Column, end.Row, end.Column);
}
///
/// Adds the Cell at the specified row and column indicies to the current selection
///
/// The row index of the Cell to add to the selection
/// The column index of the Cell to add to the selection
public void AddCell(int row, int column)
{
this.AddCells(row, column, row, column);
}
///
/// Adds the Cell at the specified row and column indicies to the current selection
///
/// A CellPos that specifies the Cell to add to the selection
public void AddCell(CellPos cellPos)
{
this.AddCell(cellPos.Row, cellPos.Column);
}
///
/// Adds the Cells located between the specified start and end row/column indicies
/// to the current selection
///
/// The row index of the start Cell
/// The column index of the start Cell
/// The row index of the end Cell
/// The column index of the end Cell
public void AddCells(int startRow, int startColumn, int endRow, int endColumn)
{
int[] oldSelectedIndicies = this.SelectedIndicies;
if (InternalAddCells(startRow, startColumn, endRow, endColumn))
{
this.owner.OnSelectionChanged(new SelectionEventArgs(this.owner, oldSelectedIndicies, this.SelectedIndicies));
}
this.shiftSelectStart = new CellPos(startRow, startColumn);
this.shiftSelectEnd = new CellPos(endRow, endColumn);
}
///
/// Adds the Cells located between the specified start and end CellPos to the
/// current selection
///
/// A CellPos that specifies the start Cell
/// A CellPos that specifies the end Cell
public void AddCells(CellPos start, CellPos end)
{
this.AddCells(start.Row, start.Column, end.Row, end.Column);
}
///
/// Adds the Cells located between the specified start and end CellPos to the
/// current selection without raising an event
///
/// A CellPos that specifies the start Cell
/// A CellPos that specifies the end Cell
/// true if any Cells were added, false otherwise
private bool InternalAddCells(CellPos start, CellPos end)
{
return this.InternalAddCells(start.Row, start.Column, end.Row, end.Column);
}
///
/// Adds the Cells located between the specified start and end row/column indicies
/// to the current selection without raising an event
///
/// The row index of the start Cell
/// The column index of the start Cell
/// The row index of the end Cell
/// The column index of the end Cell
/// true if any Cells were added, false otherwise
private bool InternalAddCells(int startRow, int startColumn, int endRow, int endColumn)
{
this.Normalise(ref startRow, ref endRow);
this.Normalise(ref startColumn, ref endColumn);
bool anyAdded = false;
bool anyAddedInRow = false;
for (int i=startRow; i<=endRow; i++)
{
if (i >= this.owner.Rows.Count)
{
break;
}
Row r = this.owner.Rows[i];
for (int j=startColumn; j<=endColumn; j++)
{
if (j >= r.Cells.Count)
{
break;
}
if (!r.Cells[j].Selected && r.Cells[j].Enabled)
{
if (this.owner.Table != null && !this.owner.Table.IsCellEnabled(i, j))
{
continue;
}
r.Cells[j].SetSelected(true);
r.InternalSelectedCellCount++;
anyAdded = true;
anyAddedInRow = true;
}
}
if (anyAddedInRow && !this.rows.Contains(r))
{
this.rows.Add(r);
}
anyAddedInRow = false;
}
return anyAdded;
}
///
/// Adds the Cells between the last selection start Cell and the Cell at the
/// specified row/column indicies to the current selection. Any Cells that are
/// between the last start and end Cells that are not in the new area are
/// removed from the current selection
///
/// The row index of the shift selected Cell
/// The column index of the shift selected Cell
public void AddShiftSelectedCell(int row, int column)
{
int[] oldSelectedIndicies = this.SelectedIndicies;
if (this.shiftSelectStart == CellPos.Empty)
{
this.shiftSelectStart = new CellPos(0, 0);
}
bool changed = false;
if (this.shiftSelectEnd != CellPos.Empty)
{
changed = this.InternalRemoveCells(this.shiftSelectStart, this.shiftSelectEnd);
changed |= this.InternalAddCells(this.shiftSelectStart, new CellPos(row, column));
}
else
{
changed = this.InternalAddCells(0, 0, row, column);
}
if (changed)
{
this.owner.OnSelectionChanged(new SelectionEventArgs(this.owner, oldSelectedIndicies, this.SelectedIndicies));
}
this.shiftSelectEnd = new CellPos(row, column);
}
///
/// Adds the Cells between the last selection start Cell and the Cell at the
/// specified CellPas to the current selection. Any Cells that are
/// between the last start and end Cells that are not in the new area are
/// removed from the current selection
///
/// A CellPos that specifies the shift selected Cell
public void AddShiftSelectedCell(CellPos cellPos)
{
this.AddShiftSelectedCell(cellPos.Row, cellPos.Column);
}
///
/// Ensures that the first index is smaller than the second index,
/// performing a swap if necessary
///
/// The first index
/// The second index
private void Normalise(ref int a, ref int b)
{
if (a < 0)
{
a = 0;
}
if (b < 0)
{
b = 0;
}
if (b < a)
{
int temp = a;
a = b;
b = temp;
}
}
#endregion
#region Clear
///
/// Removes all selected Rows and Cells from the selection
///
public void Clear()
{
if (this.rows.Count > 0)
{
int[] oldSelectedIndicies = this.SelectedIndicies;
this.InternalClear();
this.shiftSelectStart = CellPos.Empty;
this.shiftSelectEnd = CellPos.Empty;
this.owner.OnSelectionChanged(new SelectionEventArgs(this.owner, oldSelectedIndicies, this.SelectedIndicies));
}
}
///
/// Removes all selected Rows and Cells from the selection without raising an event
///
private void InternalClear()
{
if (this.rows.Count > 0)
{
for (int i=0; i
/// Removes the Cell at the specified row and column indicies from the current selection
///
/// The row index of the Cell to remove from the selection
/// The column index of the Cell to remove from the selection
public void RemoveCell(int row, int column)
{
this.RemoveCells(row, column, row, column);
}
///
/// Removes the Cell at the specified row and column indicies from the current selection
///
/// A CellPos that specifies the Cell to remove from the selection
public void RemoveCell(CellPos cellPos)
{
this.RemoveCell(cellPos.Row, cellPos.Column);
}
///
/// Removes the Cells located between the specified start and end row/column indicies
/// from the current selection
///
/// The row index of the start Cell
/// The column index of the start Cell
/// The row index of the end Cell
/// The column index of the end Cell
public void RemoveCells(int startRow, int startColumn, int endRow, int endColumn)
{
if (this.rows.Count > 0)
{
int[] oldSelectedIndicies = this.SelectedIndicies;
if (this.InternalRemoveCells(startRow, startColumn, endRow, endColumn))
{
this.owner.OnSelectionChanged(new SelectionEventArgs(this.owner, oldSelectedIndicies, this.SelectedIndicies));
}
this.shiftSelectStart = new CellPos(startRow, startColumn);
this.shiftSelectEnd = new CellPos(endRow, endColumn);
}
}
///
/// Removes the Cells located between the specified start and end CellPos from the
/// current selection
///
/// A CellPos that specifies the start Cell
/// A CellPos that specifies the end Cell
public void RemoveCells(CellPos start, CellPos end)
{
this.RemoveCells(start.Row, start.Column, end.Row, end.Column);
}
///
/// Removes the Cells located between the specified start and end CellPos from the
/// current selection without raising an event
///
/// A CellPos that specifies the start Cell
/// A CellPos that specifies the end Cell
/// true if any Cells were added, false otherwise
private bool InternalRemoveCells(CellPos start, CellPos end)
{
return this.InternalRemoveCells(start.Row, start.Column, end.Row, end.Column);
}
///
/// Removes the Cells located between the specified start and end row/column indicies
/// from the current selection without raising an event
///
/// The row index of the start Cell
/// The column index of the start Cell
/// The row index of the end Cell
/// The column index of the end Cell
/// true if any Cells were added, false otherwise
private bool InternalRemoveCells(int startRow, int startColumn, int endRow, int endColumn)
{
this.Normalise(ref startRow, ref endRow);
this.Normalise(ref startColumn, ref endColumn);
bool anyRemoved = false;
for (int i=startRow; i<=endRow; i++)
{
if (i >= this.owner.Rows.Count)
{
break;
}
Row r = this.owner.Rows[i];
for (int j=startColumn; j<=endColumn; j++)
{
if (j >= r.Cells.Count)
{
break;
}
if (r.Cells[j].Selected)
{
r.Cells[j].SetSelected(false);
r.InternalSelectedCellCount--;
anyRemoved = true;
}
}
if (!r.AnyCellsSelected)
{
if (this.rows.Contains(r))
{
this.rows.Remove(r);
}
}
}
return anyRemoved;
}
///
/// Removes the specified Row from the selection
///
/// The Row to be removed from the selection
internal void RemoveRow(Row row)
{
if (this.rows.Contains(row))
{
int[] oldSelectedIndicies = this.SelectedIndicies;
this.rows.Remove(row);
this.owner.OnSelectionChanged(new SelectionEventArgs(this.owner, oldSelectedIndicies, this.SelectedIndicies));
}
}
#endregion
#region Queries
///
/// Returns whether the Cell at the specified row and column indicies is
/// currently selected
///
/// The row index of the specified Cell
/// The column index of the specified Cell
/// true if the Cell at the specified row and column indicies is
/// selected, false otherwise
public bool IsCellSelected(int row, int column)
{
if (row < 0 || row >= this.owner.Rows.Count)
{
return false;
}
return this.owner.Rows[row].IsCellSelected(column);
}
///
/// Returns whether the Cell at the specified CellPos is currently selected
///
/// A CellPos the represents the row and column indicies
/// of the Cell to check
/// true if the Cell at the specified CellPos is currently selected,
/// false otherwise
public bool IsCellSelected(CellPos cellPos)
{
return this.IsCellSelected(cellPos.Row, cellPos.Column);
}
///
/// Returns whether the Row at the specified index in th TableModel is
/// currently selected
///
/// The index of the Row to check
/// true if the Row at the specified index is currently selected,
/// false otherwise
public bool IsRowSelected(int index)
{
if (index < 0 || index >= this.owner.Rows.Count)
{
return false;
}
return this.owner.Rows[index].AnyCellsSelected;
}
#endregion
#endregion
#region Properties
///
/// Gets an array that contains the currently selected Rows
///
public Row[] SelectedItems
{
get
{
if (this.rows.Count == 0)
{
return new Row[0];
}
this.rows.Sort(new RowComparer());
return (Row[]) this.rows.ToArray(typeof(Row));
}
}
///
/// Gets an array that contains the indexes of the currently selected Rows
///
public int[] SelectedIndicies
{
get
{
if (this.rows.Count == 0)
{
return new int[0];
}
this.rows.Sort(new RowComparer());
int[] indicies = new int[this.rows.Count];
for (int i=0; i
/// Returns a Rectange that bounds the currently selected Rows
///
public Rectangle SelectionBounds
{
get
{
if (this.rows.Count == 0)
{
return Rectangle.Empty;
}
int[] indicies = this.SelectedIndicies;
return this.CalcSelectionBounds(indicies[0], indicies[indicies.Length-1]);
}
}
///
///
///
///
///
///
internal Rectangle CalcSelectionBounds(int start, int end)
{
this.Normalise(ref start, ref end);
Rectangle bounds = new Rectangle();
if (this.owner.Table != null && this.owner.Table.ColumnModel != null)
{
bounds.Width = this.owner.Table.ColumnModel.VisibleColumnsWidth;
}
bounds.Y = start * this.owner.RowHeight;
if (start == end)
{
bounds.Height = this.owner.RowHeight;
}
else
{
bounds.Height = ((end + 1) * this.owner.RowHeight) - bounds.Y;
}
return bounds;
}
#endregion
}
#endregion
}
}