//######################################################################################### //★★★★★★★ 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.ComponentModel; using System.Drawing; using System.Windows.Forms; using XPTable.Events; using XPTable.Models.Design; using XPTable.Renderers; namespace XPTable.Models { /// /// Represents a Cell that is displayed in a Table /// [DesignTimeVisible(true), TypeConverter(typeof(CellConverter))] public class Cell : IDisposable { #region EventHandlers /// /// Occurs when the value of a Cells property changes /// public event CellEventHandler PropertyChanged; #endregion #region Class Data // Cell state flags private static readonly int STATE_EDITABLE = 1; private static readonly int STATE_ENABLED = 2; private static readonly int STATE_SELECTED = 4; /// /// The text displayed in the Cell /// private string text; /// /// An object that contains data to be displayed in the Cell /// private object data; /// /// An object that contains data about the Cell /// private object tag; /// /// Stores information used by CellRenderers to record the current /// state of the Cell /// private object rendererData; /// /// The Row that the Cell belongs to /// private Row row; /// /// The index of the Cell /// private int index; /// /// Contains the current state of the the Cell /// private byte state; /// /// The Cells CellStyle settings /// private CellStyle cellStyle; /// /// The Cells CellCheckStyle settings /// private CellCheckStyle checkStyle; /// /// The Cells CellImageStyle settings /// private CellImageStyle imageStyle; /// /// The text displayed in the Cells tooltip /// private string tooltipText; /// /// Specifies whether the Cell has been disposed /// private bool disposed = false; #endregion #region Constructor /// /// Initializes a new instance of the Cell class with default settings /// public Cell() : base() { this.Init(); } /// /// Initializes a new instance of the Cell class with the specified text /// /// The text displayed in the Cell public Cell(string text) { this.Init(); this.text = text; } /// /// Initializes a new instance of the Cell class with the specified object /// /// The object displayed in the Cell public Cell(object value) { this.Init(); this.data = value; } /// /// Initializes a new instance of the Cell class with the specified text /// and object /// /// The text displayed in the Cell /// The object displayed in the Cell public Cell(string text, object value) { this.Init(); this.text = text; this.data = value; } /// /// Initializes a new instance of the Cell class with the specified text /// and check value /// /// The text displayed in the Cell /// Specifies whether the Cell is Checked public Cell(string text, bool check) { this.Init(); this.text = text; this.Checked = check; } /// /// Initializes a new instance of the Cell class with the specified text /// and Image value /// /// The text displayed in the Cell /// The Image displayed in the Cell public Cell(string text, Image image) { this.Init(); this.text = text; this.Image = image; } /// /// Initializes a new instance of the Cell class with the specified text, /// fore Color, back Color and Font /// /// The text displayed in the Cell /// The foreground Color of the Cell /// The background Color of the Cell /// The Font used to draw the text in the Cell public Cell(string text, Color foreColor, Color backColor, Font font) { this.Init(); this.text = text; this.ForeColor = foreColor; this.BackColor = backColor; this.Font = font; } /// /// Initializes a new instance of the Cell class with the specified text /// and CellStyle /// /// The text displayed in the Cell /// A CellStyle that specifies the visual appearance /// of the Cell public Cell(string text, CellStyle cellStyle) { this.Init(); this.text = text; this.cellStyle = cellStyle; } /// /// Initializes a new instance of the Cell class with the specified object, /// fore Color, back Color and Font /// /// The object displayed in the Cell /// The foreground Color of the Cell /// The background Color of the Cell /// The Font used to draw the text in the Cell public Cell(object value, Color foreColor, Color backColor, Font font) { this.Init(); this.data = value; this.ForeColor = foreColor; this.BackColor = backColor; this.Font = font; } /// /// Initializes a new instance of the Cell class with the specified text /// and CellStyle /// /// The object displayed in the Cell /// A CellStyle that specifies the visual appearance /// of the Cell public Cell(object value, CellStyle cellStyle) { this.Init(); this.data = value; this.cellStyle = cellStyle; } /// /// Initializes a new instance of the Cell class with the specified text, /// object, fore Color, back Color and Font /// /// The text displayed in the Cell /// The object displayed in the Cell /// The foreground Color of the Cell /// The background Color of the Cell /// The Font used to draw the text in the Cell public Cell(string text, object value, Color foreColor, Color backColor, Font font) { this.Init(); this.text = text; this.data = value; this.ForeColor = foreColor; this.BackColor = backColor; this.Font = font; } /// /// Initializes a new instance of the Cell class with the specified text, /// object and CellStyle /// /// The text displayed in the Cell /// The object displayed in the Cell /// A CellStyle that specifies the visual appearance /// of the Cell public Cell(string text, object value, CellStyle cellStyle) { this.Init(); this.text = text; this.data = value; this.cellStyle = cellStyle; } /// /// Initializes a new instance of the Cell class with the specified text, /// check value, fore Color, back Color and Font /// /// The text displayed in the Cell /// Specifies whether the Cell is Checked /// The foreground Color of the Cell /// The background Color of the Cell /// The Font used to draw the text in the Cell public Cell(string text, bool check, Color foreColor, Color backColor, Font font) { this.Init(); this.text = text; this.Checked = check; this.ForeColor = foreColor; this.BackColor = backColor; this.Font = font; } /// /// Initializes a new instance of the Cell class with the specified text, /// check value and CellStyle /// /// The text displayed in the Cell /// Specifies whether the Cell is Checked /// A CellStyle that specifies the visual appearance /// of the Cell public Cell(string text, bool check, CellStyle cellStyle) { this.Init(); this.text = text; this.Checked = check; this.cellStyle = cellStyle; } /// /// Initializes a new instance of the Cell class with the specified text, /// Image, fore Color, back Color and Font /// /// The text displayed in the Cell /// The Image displayed in the Cell /// The foreground Color of the Cell /// The background Color of the Cell /// The Font used to draw the text in the Cell public Cell(string text, Image image, Color foreColor, Color backColor, Font font) { this.Init(); this.text = text; this.Image = image; this.ForeColor = foreColor; this.BackColor = backColor; this.Font = font; } /// /// Initializes a new instance of the Cell class with the specified text, /// Image and CellStyle /// /// The text displayed in the Cell /// The Image displayed in the Cell /// A CellStyle that specifies the visual appearance /// of the Cell public Cell(string text, Image image, CellStyle cellStyle) { this.Init(); this.text = text; this.Image = image; this.cellStyle = cellStyle; } /// /// Initialise default values /// private void Init() { this.text = null; this.data = null; this.rendererData = null; this.tag = null; this.row = null; this.index = -1; this.cellStyle = null; this.checkStyle = null; this.imageStyle = null; this.tooltipText = null; this.state = (byte) (STATE_EDITABLE | STATE_ENABLED); } #endregion #region Methods /// /// Releases all resources used by the Cell /// public void Dispose() { if (!this.disposed) { this.text = null; this.data = null; this.tag = null; this.rendererData = null; if (this.row != null) { this.row.Cells.Remove(this); } this.row = null; this.index = -1; this.cellStyle = null; this.checkStyle = null; this.imageStyle = null; this.tooltipText = null; this.state = (byte) 0; this.disposed = true; } } /// /// Returns the state represented by the specified state flag /// /// A flag that represents the state to return /// The state represented by the specified state flag internal bool GetState(int flag) { return ((this.state & flag) != 0); } /// /// Sets the state represented by the specified state flag to the specified value /// /// A flag that represents the state to be set /// The new value of the state internal void SetState(int flag, bool value) { this.state = (byte) (value ? (this.state | flag) : (this.state & ~flag)); } #endregion #region Properties /// /// Gets or sets the text displayed by the Cell /// [Category("Appearance"), DefaultValue(null), Description("The text displayed by the cell")] public string Text { get { return this.text; } set { if (this.text == null || !this.text.Equals(value)) { string oldText = this.Text; this.text = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.ValueChanged, oldText)); } } } /// /// Gets or sets the Cells non-text data /// [Category("Appearance"), DefaultValue(null), Description("The non-text data displayed by the cell"), TypeConverter(typeof(StringConverter))] public object Data { get { return this.data; } set { if (this.data != value) { object oldData = this.Data; this.data = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.ValueChanged, oldData)); } } } /// /// Gets or sets the object that contains data about the Cell /// [Category("Appearance"), DefaultValue(null), Description("User defined data associated with the cell"), TypeConverter(typeof(StringConverter))] public object Tag { get { return this.tag; } set { this.tag = value; } } /// /// Gets or sets the CellStyle used by the Cell /// [Browsable(false), DefaultValue(null)] public CellStyle CellStyle { get { return this.cellStyle; } set { if (this.cellStyle != value) { CellStyle oldStyle = this.CellStyle; this.cellStyle = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.StyleChanged, oldStyle)); } } } /// /// Gets or sets whether the Cell is selected /// [Browsable(false)] public bool Selected { get { return this.GetState(STATE_SELECTED); } } /// /// Sets whether the Cell is selected /// /// A boolean value that specifies whether the /// cell is selected internal void SetSelected(bool selected) { this.SetState(STATE_SELECTED, selected); } /// /// Gets or sets the background Color for the Cell /// [Category("Appearance"), Description("The background color used to display text and graphics in the cell")] public Color BackColor { get { if (this.CellStyle == null) { if (this.Row != null) { return this.Row.BackColor; } return Color.Transparent; } return this.CellStyle.BackColor; } set { if (this.CellStyle == null) { this.CellStyle = new CellStyle(); } if (this.CellStyle.BackColor != value) { Color oldBackColor = this.BackColor; this.CellStyle.BackColor = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.BackColorChanged, oldBackColor)); } } } /// /// Specifies whether the BackColor property should be serialized at /// design time /// /// true if the BackColor property should be serialized, /// false otherwise private bool ShouldSerializeBackColor() { return (this.cellStyle != null && this.cellStyle.BackColor != Color.Empty); } /// /// Gets or sets the foreground Color for the Cell /// [Category("Appearance"), Description("The foreground color used to display text and graphics in the cell")] public Color ForeColor { get { if (this.CellStyle == null) { if (this.Row != null) { return this.Row.ForeColor; } return Color.Transparent; } else { if (this.CellStyle.ForeColor == Color.Empty || this.CellStyle.ForeColor == Color.Transparent) { if (this.Row != null) { return this.Row.ForeColor; } } return this.CellStyle.ForeColor; } } set { if (this.CellStyle == null) { this.CellStyle = new CellStyle(); } if (this.CellStyle.ForeColor != value) { Color oldForeColor = this.ForeColor; this.CellStyle.ForeColor = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.ForeColorChanged, oldForeColor)); } } } /// /// Specifies whether the ForeColor property should be serialized at /// design time /// /// true if the ForeColor property should be serialized, /// false otherwise private bool ShouldSerializeForeColor() { return (this.cellStyle != null && this.cellStyle.ForeColor != Color.Empty); } /// /// Gets or sets the Font used by the Cell /// [Category("Appearance"), Description("The font used to display text in the cell")] public Font Font { get { if (this.CellStyle == null) { if (this.Row != null) { return this.Row.Font; } return null; } else { if (this.CellStyle.Font == null) { if (this.Row != null) { return this.Row.Font; } } return this.CellStyle.Font; } } set { if (this.CellStyle == null) { this.CellStyle = new CellStyle(); } if (this.CellStyle.Font != value) { Font oldFont = this.Font; this.CellStyle.Font = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.FontChanged, oldFont)); } } } /// /// Specifies whether the Font property should be serialized at /// design time /// /// true if the Font property should be serialized, /// false otherwise private bool ShouldSerializeFont() { return (this.cellStyle != null && this.cellStyle.Font != null); } /// /// Gets or sets the amount of space between the Cells Border and its contents /// [Category("Appearance"), Description("The amount of space between the cells border and its contents")] public CellPadding Padding { get { if (this.CellStyle == null) { return CellPadding.Empty; } return this.CellStyle.Padding; } set { if (this.CellStyle == null) { this.CellStyle = new CellStyle(); } if (this.CellStyle.Padding != value) { CellPadding oldPadding = this.Padding; this.CellStyle.Padding = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.PaddingChanged, oldPadding)); } } } /// /// Specifies whether the Padding property should be serialized at /// design time /// /// true if the Padding property should be serialized, /// false otherwise private bool ShouldSerializePadding() { return this.Padding != CellPadding.Empty; } /// /// Gets or sets whether the Cell is in the checked state /// [Category("Appearance"), DefaultValue(false), Description("Indicates whether the cell is checked or unchecked"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), RefreshProperties(RefreshProperties.Repaint)] public bool Checked { get { if (this.checkStyle == null) { return false; } return this.checkStyle.Checked; } set { if (this.checkStyle == null) { this.checkStyle = new CellCheckStyle(); } if (this.checkStyle.Checked != value) { bool oldCheck = this.Checked; this.checkStyle.Checked = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.CheckStateChanged, oldCheck)); } } } /// /// Gets or sets the state of the Cells check box /// [Category("Appearance"), DefaultValue(CheckState.Unchecked), Description("Indicates the state of the cells check box"), RefreshProperties(RefreshProperties.Repaint)] public CheckState CheckState { get { if (this.checkStyle == null) { return CheckState.Unchecked; } return this.checkStyle.CheckState; } set { if (!Enum.IsDefined(typeof(CheckState), value)) { throw new InvalidEnumArgumentException("value", (int) value, typeof(CheckState)); } if (this.checkStyle == null) { this.checkStyle = new CellCheckStyle(); } if (this.checkStyle.CheckState != value) { CheckState oldCheckState = this.CheckState; this.checkStyle.CheckState = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.CheckStateChanged, oldCheckState)); } } } /// /// Gets or sets a value indicating whether the Cells check box /// will allow three check states rather than two /// [Category("Appearance"), DefaultValue(false), Description("Controls whether or not the user can select the indeterminate state of the cells check box"), RefreshProperties(RefreshProperties.Repaint)] public bool ThreeState { get { if (this.checkStyle == null) { return false; } return this.checkStyle.ThreeState; } set { if (this.checkStyle == null) { this.checkStyle = new CellCheckStyle(); } if (this.checkStyle.ThreeState != value) { bool oldThreeState = this.ThreeState; this.checkStyle.ThreeState = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.ThreeStateChanged, oldThreeState)); } } } /// /// Gets or sets the image that is displayed in the Cell /// [Category("Appearance"), DefaultValue(null), Description("The image that will be displayed in the cell")] public Image Image { get { if (this.imageStyle == null) { return null; } return this.imageStyle.Image; } set { if (this.imageStyle == null) { this.imageStyle = new CellImageStyle(); } if (this.imageStyle.Image != value) { Image oldImage = this.Image; this.imageStyle.Image = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.ImageChanged, oldImage)); } } } /// /// Gets or sets how the Cells image is sized within the Cell /// [Category("Appearance"), DefaultValue(ImageSizeMode.Normal), Description("Controls how the image is sized within the cell")] public ImageSizeMode ImageSizeMode { get { if (this.imageStyle == null) { return ImageSizeMode.Normal; } return this.imageStyle.ImageSizeMode; } set { if (this.imageStyle == null) { this.imageStyle = new CellImageStyle(); } if (this.imageStyle.ImageSizeMode != value) { ImageSizeMode oldSizeMode = this.ImageSizeMode; this.imageStyle.ImageSizeMode = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.ImageSizeModeChanged, oldSizeMode)); } } } /// /// Gets or sets a value indicating whether the Cells contents are able /// to be edited /// [Category("Appearance"), Description("Controls whether the cells contents are able to be changed by the user")] public bool Editable { get { if (!this.GetState(STATE_EDITABLE)) { return false; } if (this.Row == null) { return this.Enabled; } return this.Enabled && this.Row.Editable; } set { bool editable = this.Editable; this.SetState(STATE_EDITABLE, value); if (editable != value) { this.OnPropertyChanged(new CellEventArgs(this, CellEventType.EditableChanged, editable)); } } } /// /// Specifies whether the Editable property should be serialized at /// design time /// /// true if the Editable property should be serialized, /// false otherwise private bool ShouldSerializeEditable() { return !this.GetState(STATE_EDITABLE); } /// /// Gets or sets a value indicating whether the Cell /// can respond to user interaction /// [Category("Appearance"), Description("Indicates whether the cell is enabled")] public bool Enabled { get { if (!this.GetState(STATE_ENABLED)) { return false; } if (this.Row == null) { return true; } return this.Row.Enabled; } set { bool enabled = this.Enabled; this.SetState(STATE_ENABLED, value); if (enabled != value) { this.OnPropertyChanged(new CellEventArgs(this, CellEventType.EnabledChanged, enabled)); } } } /// /// Specifies whether the Enabled property should be serialized at /// design time /// /// true if the Enabled property should be serialized, /// false otherwise private bool ShouldSerializeEnabled() { return !this.GetState(STATE_ENABLED); } /// /// Gets or sets the text displayed in the Cells tooltip /// [Category("Appearance"), DefaultValue(null), Description("The text displayed in the cells tooltip")] public string ToolTipText { get { return this.tooltipText; } set { if (this.tooltipText != value) { string oldToolTip = this.tooltipText; this.tooltipText = value; this.OnPropertyChanged(new CellEventArgs(this, CellEventType.ToolTipTextChanged, oldToolTip)); } } } /// /// Gets or sets the information used by CellRenderers to record the current /// state of the Cell /// protected internal object RendererData { get { return this.rendererData; } set { this.rendererData = value; } } /// /// Gets the Row that the Cell belongs to /// [Browsable(false)] public Row Row { get { return this.row; } } /// /// Gets or sets the Row that the Cell belongs to /// internal Row InternalRow { get { return this.row; } set { this.row = value; } } /// /// Gets the index of the Cell within its Row /// [Browsable(false)] public int Index { get { return this.index; } } /// /// Gets or sets the index of the Cell within its Row /// internal int InternalIndex { get { return this.index; } set { this.index = value; } } /// /// Gets whether the Cell is able to raise events /// protected internal bool CanRaiseEvents { get { // check if the Row that the Cell belongs to is able to // raise events (if it can't, the Cell shouldn't raise // events either) if (this.Row != null) { return this.Row.CanRaiseEvents; } return true; } } #endregion #region Events /// /// Raises the PropertyChanged event /// /// A CellEventArgs that contains the event data protected virtual void OnPropertyChanged(CellEventArgs e) { e.SetColumn(this.Index); if (this.Row != null) { e.SetRow(this.Row.Index); } if (this.CanRaiseEvents) { if (this.Row != null) { this.Row.OnCellPropertyChanged(e); } if (PropertyChanged != null) { PropertyChanged(this, e); } } } #endregion } }