えムナウのプログラミングのページ

えムナウ の とどけもの

 Logo えムナウBlog@AILight
えムナウBlog@Wankuma

目次

利用状況

イメージ ギャラリー

カテゴリ

Links
 

inetaj

MSMVPロゴ
MSMVP Visual C# 2005/01-2007/12
SpreadControlのUserControlです。

プログラムです。

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.ComponentModel.Design.Serialization;

namespace SpreadControl
{
        /// <summary>
        /// SpreadControl の概要の説明です。
        /// 
        /// 2004/06/27
        /// CurrentCell プロパティ対応
        /// HitTest メソッド対応
        /// マウスクリックによるセル移動対応
        /// 上下キーよるセル移動対応
        /// Tab・SHIFT+Tabキーよるセル移動対応
        /// 2004/07/14
        /// Cell プロパティにText/Font/ForeColor/BackColor追加
        /// デフォルトインデクサによるCellプロパティの変更を可能にした 
        /// DataプロパティでCellプロパティの変更を可能にした 
        /// Dataプロパティは一次元配列で columns=3/rows=2 だと6要素できる
        /// 0=0,0 / 1=0,1 / 2=0,2 / 3=1,0 / 4=1,1 / 5=1,2 に対応する 
        /// 2004/07/15
        /// BlockRange プロパティ作成
        /// 描画・入力・HitTest メソッド・セル移動をブロック対応
        /// 2004/07/20 バグ修正
        /// デザインモードでCulumns/Rowsを変更したときにグリッドが対応しない。
        /// デザインモードでCulumns/Rowsを変更後グリッドにエラーが表示される。
        /// フォント変更時にPreferredRowHeightが追従しない。
        /// </summary>
        public class SpreadControl : System.Windows.Forms.UserControl ,ISupportInitialize
        {
                #region ローカル変数
                private bool init ;
                private int columns ;
                private int rows ;
                private int preferredColumnWidth ;
                private int preferredRowHeight ;
                private int currentColumnIndex ;
                private int currentRowIndex ;
                private Cell[] item ;
                private Cell[] inititem ;
                private CellRangeCollection rangecollection ;

                private int oldcolumns ;
                private int oldrows ;
                #endregion

                #region コンポーネント デザイナで生成された変数
                private System.Windows.Forms.TextBox textBox1;

                /// <summary>
                /// 必要なデザイナ変数です。
                /// </summary>
                private System.ComponentModel.Container components = null;
                #endregion

                #region クラスの生成・消滅
                public SpreadControl()
                {
                        init = true ;

                        // この呼び出しは、Windows.Forms フォーム デザイナで必要です。
                        InitializeComponent();

                        // TODO: InitComponent 呼び出しの後に初期化処理を追加してください。
                        columns = 3 ;
                        rows = 2 ;
                        preferredColumnWidth = 75 ;
                        preferredRowHeight = 15 ;
                        currentColumnIndex = 0 ;
                        currentRowIndex = 0 ;
                        inititem = null ;
                        item = new Cell[rows * columns] ;
                        for ( int i=0 ; i<rows * columns ; i++ )
                        {
                                item[i] = new Cell() ;
                                item[i].PropertyChange += new System.EventHandler(this.Cell_PropertyChange);
                        }
                        rangecollection = new CellRangeCollection() ;
                        rangecollection.PropertyChange += new System.EventHandler(this.CellRange_PropertyChange);

                        oldcolumns = 3 ;
                        oldrows = 2 ;
                }

                /// <summary>
                /// 使用されているリソースに後処理を実行します。
                /// </summary>
                protected override void Dispose( bool disposing )
                {
                        if( disposing )
                        {
                                if( components != null )
                                        components.Dispose();
                        }
                        base.Dispose( disposing );
                }

                private void SpreadControl_Load(object sender, System.EventArgs e)
                {
                        textBox1.BorderStyle = BorderStyle.None ;
                        ResizeDisplay() ;
                }
                #endregion

                #region コンポーネント デザイナで生成されたコード 
                /// <summary>
                /// デザイナ サポートに必要なメソッドです。このメソッドの内容を 
                /// コード]エディタで変更しないでください。
                /// </summary>
                private void InitializeComponent()
                {
                        this.textBox1 = new System.Windows.Forms.TextBox();
                        this.SuspendLayout();
                        // 
                        // textBox1
                        // 
                        this.textBox1.AutoSize = false;
                        this.textBox1.Location = new System.Drawing.Point(0, 24);
                        this.textBox1.Name = "textBox1";
                        this.textBox1.TabIndex = 0;
                        this.textBox1.Text = "textBox1";
                        // 
                        // SpreadControl
                        // 
                        this.AutoScroll = true;
                        this.Controls.Add(this.textBox1);
                        this.Name = "SpreadControl";
                        this.Load += new System.EventHandler(this.SpreadControl_Load);
                        this.Enter += new System.EventHandler(this.SpreadControl_Enter);
                        this.FontChanged += new System.EventHandler(this.SpreadControl_FontChanged);
                        this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.SpreadControl_MouseUp);
                        this.Paint += new System.Windows.Forms.PaintEventHandler(this.SpreadControl_Paint);
                        this.Leave += new System.EventHandler(this.SpreadControl_Leave);
                        this.ResumeLayout(false);

                }
                #endregion

                #region ローカルメソッド
                private bool IncludeClient(Rectangle rectcheck)
                {
                        Rectangle rect = ClientRectangle ;
                        rect.Offset( -AutoScrollPosition.X, -AutoScrollPosition.Y ) ;
                        if ( rect.Left <= rectcheck.Left &&
                                rect.Top <= rectcheck.Top &&
                                rect.Right >= rectcheck.Right &&
                                rect.Bottom >= rectcheck.Bottom )
                        {
                                return true ;
                        }
                        return false ;
                }

                private void ResizeDisplay()
                {
                        textBox1.Size = new Size(preferredColumnWidth - 1, preferredRowHeight - 1) ;
                        textBox1.Visible = false ;
                        if ( preferredColumnWidth < textBox1.Size.Width + 1 )
                        {
                                preferredColumnWidth = textBox1.Size.Width + 1 ;
                        }
                        if ( preferredRowHeight < textBox1.Size.Height + 1 )
                        {
                                preferredRowHeight = textBox1.Size.Height + 1 ;
                        }
                        AutoScrollMinSize = new Size( preferredColumnWidth * columns + 1, preferredRowHeight * rows + 1 ) ;
                        Refresh() ;
                }

                private void ResizeData()
                {
                        Cell[] newitem = new Cell[rows * columns] ;
                        for ( int i=0 ; i<rows * columns ; i++ )
                        {
                                newitem[i] = new Cell() ;
                        }

                        for ( int i=0 ; i<oldrows && i<rows ; i++ )
                        {
                                for ( int j=0 ; j<oldcolumns && j<columns ; j++ )
                                {
                                        newitem[i * columns + j] = item[i * oldcolumns + j] ;
                                }
                        }
                        for ( int i=0 ; i<rows * columns ; i++ )
                        {
                                newitem[i].PropertyChange += new System.EventHandler(this.Cell_PropertyChange);
                        }
                        item = newitem ;
                        oldcolumns = columns ;
                        oldrows = rows ;
                        ResizeDisplay() ;
                }

                private void EnterTextBox()
                {
                        Rectangle rect = new Rectangle( currentColumnIndex * preferredColumnWidth,
                                currentRowIndex * preferredRowHeight,
                                preferredColumnWidth, preferredRowHeight ) ;
                        if ( !IncludeClient( rect ) )
                        {
                                AutoScrollPosition = new Point(rect.Right + 1 - ClientRectangle.Right,
                                        rect.Bottom + 1 - ClientRectangle.Bottom ) ;
                        }
                        textBox1.Location = new Point( AutoScrollPosition.X + currentColumnIndex * preferredColumnWidth + 1,
                                AutoScrollPosition.Y + currentRowIndex * preferredRowHeight + 1 ) ;
                        CellRange blockrange = SearchBlock( currentColumnIndex, currentRowIndex ) ; 
                        textBox1.Multiline = false ;
                        if ( blockrange == null )
                        {
                                textBox1.Size = new Size(preferredColumnWidth - 1, preferredRowHeight - 1) ;
                        }
                        else
                        {
                                textBox1.Size = new Size(preferredColumnWidth * (blockrange.Right - blockrange.Left + 1) - 1,
                                        preferredRowHeight * (blockrange.Bottom - blockrange.Top + 1)  - 1) ;
                                if ( blockrange.Bottom - blockrange.Top != 0)
                                {
                                        textBox1.Multiline = true ;
                                }
                        }
                        textBox1.Visible = true ;
                        textBox1.Text = this[currentRowIndex,currentColumnIndex].Text ;
                        textBox1.BackColor = this[currentRowIndex,currentColumnIndex].BackColor ;
                        textBox1.ForeColor = this[currentRowIndex,currentColumnIndex].ForeColor ;
                        textBox1.Font = this[currentRowIndex,currentColumnIndex].Font ;
                        textBox1.Focus() ;
                }

                private void LeaveTextBox()
                {
                        this[currentRowIndex,currentColumnIndex].Text = textBox1.Text ;
                        textBox1.Visible = false ;
                }

                private CellRange SearchBlock( int column, int row )
                {
                        CellRange blockrange = null ; 
                        foreach ( CellRange range in rangecollection )
                        {
                                if ( range.Contains( column, row ) )
                                {
                                        blockrange = range ;
                                }
                        }
                        return blockrange ;
                }

                private void MoveIndex( int column, int row )
                {
                        CellRange blockrange = SearchBlock( column, row ) ; 
                        if ( blockrange != null )
                        {
                                column = blockrange.Left ;
                                row = blockrange.Top ;
                        }
                        currentColumnIndex = column ;
                        currentRowIndex  = row ;
                }

                private void MoveTo( int column, int row )
                {
                        LeaveTextBox() ;
                        MoveIndex( column, row ) ;
                        EnterTextBox() ;
                }

                private void MoveTo( SpreadCell cell )
                {
                        MoveTo( cell.ColumnNumber, cell.RowNumber ) ;
                }

                private void MoveUp()
                {
                        LeaveTextBox() ;
                        int row, column ;
                        row = currentRowIndex ;
                        column = currentColumnIndex ;
                        row -- ;
                        if ( row < 0 )
                        {
                                row = 0 ;
                        }
                        MoveIndex( column, row ) ;
                        EnterTextBox() ;
                }

                private void MoveDown()
                {
                        LeaveTextBox() ;
                        int row, column ;
                        row = currentRowIndex ;
                        column = currentColumnIndex ;
                        do 
                        {
                                row ++ ;
                                if ( row >= rows )
                                {
                                        row = rows - 1 ;
                                        MoveIndex( column, row ) ;
                                        break ;
                                }
                                MoveIndex( column, row ) ;
                        } while ( currentRowIndex != row ) ;
                        EnterTextBox() ;
                }

                private void MoveLeft()
                {
                        LeaveTextBox() ;
                        int row, column ;
                        row = currentRowIndex ;
                        column = currentColumnIndex ;
                        do 
                        {
                                column -- ;
                                if ( column < 0 )
                                {
                                        column = columns - 1 ;
                                        row -- ;
                                }
                                if ( row < 0 )
                                {
                                        column = 0 ;
                                        row = 0 ;
                                        MoveIndex( column, row ) ;
                                        break ;
                                }
                                MoveIndex( column, row ) ;
                        } while ( currentRowIndex != row && currentColumnIndex != column ) ;
                        EnterTextBox() ;
                }

                private void MoveRight()
                {
                        LeaveTextBox() ;
                        int row, column ;
                        int oldrow, oldcolumn ;
                        row = currentRowIndex ;
                        column = currentColumnIndex ;
                        oldrow = currentRowIndex ;
                        oldcolumn = currentColumnIndex ;
                        do 
                        {
                                column ++ ;
                                if ( column >= columns )
                                {
                                        column = 0 ;
                                        row ++ ;
                                }
                                if ( row >= rows )
                                {
                                        column = columns - 1 ;
                                        row = rows - 1 ;
                                        MoveIndex( column, row ) ;
                                        break ;
                                }
                                MoveIndex( column, row ) ;
                        } while ( currentRowIndex == oldrow && currentColumnIndex == oldcolumn ) ;
                        EnterTextBox() ;
                }

                #endregion

                #region 公開プロパティ
                [Browsable(false)]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
                public SpreadCell CurrentCell
                {
                        get
                        {
                                SpreadCell cell = new SpreadCell( currentColumnIndex, currentRowIndex ) ;
                                return cell ;
                        }
                        set
                        {
                                if ( value.ColumnNumber >= 0 &&
                                        value.ColumnNumber < columns &&
                                        value.RowNumber >= 0 &&
                                        value.RowNumber <= rows )
                                {
                                        MoveTo( value ) ;
                                }
                        }
                }

                [Description("行数を示します。"),Category("配置")]
                [RefreshProperties(RefreshProperties.All)]
                public int Rows
                {
                        get
                        {
                                return rows ;
                        }
                        set
                        {
                                rows = value ;
                                if ( DesignMode == true || init == false )
                                {
                                        ResizeData() ;
                                }
                                else
                                {
                                        oldrows = rows ;
                                }
                        }
                }

                [Description("列数を示します。"),Category("配置")]
                [RefreshProperties(RefreshProperties.All)]
                public int Columns
                {
                        get
                        {
                                return columns ;
                        }
                        set
                        {
                                columns = value ;
                                if ( DesignMode == true || init == false )
                                {
                                        ResizeData() ;
                                }
                                else
                                {
                                        oldcolumns = columns ;
                                }
                        }
                }

                [Description("行の適切な高さを示します。"),Category("配置")]
                [RefreshProperties(RefreshProperties.Repaint)]
                public int PreferredRowHeight
                {
                        get
                        {
                                return preferredRowHeight ;
                        }
                        set
                        {
                                preferredRowHeight = value ;
                                if ( init == false )
                                {
                                        ResizeDisplay() ;
                                }
                        }
                }

                [Description("列の適切な幅を示します。"),Category("配置")]
                [RefreshProperties(RefreshProperties.Repaint)]
                public int PreferredColumnWidth
                {
                        get
                        {
                                return preferredColumnWidth ;
                        }
                        set
                        {
                                preferredColumnWidth = value ;
                                if ( init == false )
                                {
                                        ResizeDisplay() ;
                                }
                        }
                }

                public Cell this [int rowindex,int columnindex]
                {
                        get 
                        {
                                if ( rowindex >= 0 && rowindex < rows &&
                                        columnindex >= 0 && columnindex < columns )
                                {
                                        return item[rowindex * columns + columnindex] ;
                                }
                                return null ;
                        }
                        set 
                        {
                                if ( rowindex >= 0 && rowindex < rows &&
                                        columnindex >= 0 && columnindex < columns )
                                {
                                        item[rowindex * columns + columnindex] = value ;
                                }
                        }
                }

                [Description("セルの表示を取得設定します。"),Category("配置")]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
                public Cell[] Data
                {
                        get 
                        {
                                return item ;
                        }
                        set
                        {
                                if ( init == false )
                                {
                                        item = value ;
                                }
                                else
                                {
                                        inititem = value ;
                                }
                        }
                }

                [Description("セルブロックのコレクションです。"),Category("設定")]
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
                public CellRangeCollection BlockRange
                {
                        get 
                        {
                                return rangecollection ;
                        }
                        set
                        {
                                rangecollection = value ;
                        }
                }
                #endregion

                #region 公開メソッド
                public HitTestInfo HitTest( int x, int y )
                {
                        HitTestInfo hittestinfo = new HitTestInfo() ;
                        x -= AutoScrollPosition.X ;
                        y -= AutoScrollPosition.Y ;
                        int px = x / preferredColumnWidth ;
                        int py = y / preferredRowHeight ;

                        if ( px >= columns || py >= rows )
                        {
                                return hittestinfo ;
                        }
                        CellRange blockrange = SearchBlock( px, py ) ; 
                        if ( blockrange != null )
                        {
                                px = blockrange.Left ;
                                py = blockrange.Top ;
                        }
                        hittestinfo = new HitTestInfo(px, py, HitTestType.Cell) ;
                        return hittestinfo ;
                }

                public HitTestInfo HitTest( Point position )
                {
                        return HitTest( position.X, position.Y ) ;
                }

                public void BeginInit()
                {
                        init = true ;
                }

                public void EndInit()
                {
                        oldcolumns = columns ;
                        oldrows = rows ;
                        init = false ;
                        if ( inititem != null )
                        {
                                item = inititem ;
                                inititem = null ;
                        }

                        ResizeData() ;
                }

                public Cell     GetCell( int rowindex,int columnindex )
                {
                        if ( rowindex >= 0 && rowindex < rows &&
                                columnindex >= 0 && columnindex < columns )
                        {
                                return item[rowindex * columns + columnindex] ;
                        }
                        return null ;
                }

                public void     SetCell( Cell cell, int rowindex,int columnindex )
                {
                        if ( rowindex >= 0 && rowindex < rows &&
                                columnindex >= 0 && columnindex < columns )
                        {
                                item[rowindex * columns + columnindex] = cell ;
                        }
                }
                #endregion

                #region イベント処理
                private void PaintOneBlock( Graphics g, Rectangle rect, Cell cell )
                {
                        Pen pen = new Pen(cell.ForeColor,1) ;
                        Brush brush = new SolidBrush(cell.ForeColor) ;
                        Brush brushback = new SolidBrush(cell.BackColor) ;
                        g.FillRectangle( brushback, rect ) ;
                        Rectangle rectcell = new Rectangle( rect.X - 1, rect.Y - 1, rect.Width + 1, rect.Height + 1 ) ;
                        Rectangle recttext = new Rectangle( rect.X - 2, rect.Y, rect.Width + 1, rect.Height + 1 ) ;
                        g.DrawString( cell.Text, cell.Font, brush, recttext ) ;
                        g.DrawRectangle( pen, rectcell ) ;
                }

                private void SpreadControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
                {
                        int px, sx, py, sy ;
                        Rectangle rect ;
                        if ( DesignMode == true || init == false )
                        {
                                for ( int i=0 ; i<rows ; i++ ) 
                                {
                                        for ( int j=0 ; j<columns ; j++ ) 
                                        {
                                                CellRange blockrange = SearchBlock( j, i ) ; 
                                                if ( blockrange == null )
                                                {
                                                        py = AutoScrollPosition.Y + i * preferredRowHeight + 1 ;
                                                        sy = preferredRowHeight - 1 ; 
                                                        px = AutoScrollPosition.X + j * preferredColumnWidth + 1 ;
                                                        sx = preferredColumnWidth - 1 ; 
                                                        rect = new Rectangle( px, py, sx, sy ) ;
                                                        PaintOneBlock( e.Graphics, rect, this[i,j] ) ;
                                                }
                                                else if ( blockrange.Top == i && blockrange.Left == j )
                                                {
                                                        if ( blockrange.Right >= columns )
                                                        {
                                                                blockrange.Right = columns - 1 ;
                                                        }
                                                        if ( blockrange.Bottom >= rows )
                                                        {
                                                                blockrange.Bottom = rows - 1 ;
                                                        }
                                                        py = AutoScrollPosition.Y + i * preferredRowHeight + 1 ;
                                                        sy = preferredRowHeight * (blockrange.Bottom - i + 1)  - 1 ; 
                                                        px = AutoScrollPosition.X + j * preferredColumnWidth + 1 ;
                                                        sx = preferredColumnWidth * (blockrange.Right - j + 1) - 1 ; 
                                                        rect = new Rectangle( px, py, sx, sy ) ;
                                                        PaintOneBlock( e.Graphics, rect, this[i,j] ) ;
                                                }
                                        }
                                }
                        }
                }

                private void SpreadControl_Enter(object sender, System.EventArgs e)
                {
                        EnterTextBox() ;
                }

                private void SpreadControl_Leave(object sender, System.EventArgs e)
                {
                        LeaveTextBox() ;
                        Refresh() ;
                }

                private void SpreadControl_FontChanged(object sender, System.EventArgs e)
                {
                        textBox1.AutoSize = false ;
                        textBox1.Font = Font ;
                        preferredRowHeight = textBox1.PreferredHeight ;
                        ResizeDisplay() ;
                }

                private void SpreadControl_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
                {
                        HitTestInfo hittestinfo = HitTest( e.X, e.Y ) ;
                        if ( hittestinfo.Type == HitTestType.Cell )
                        {
                                MoveTo( hittestinfo.Column, hittestinfo.Row ) ;
                        }
                }

                protected override bool ProcessCmdKey(ref Message m,Keys keyData)
                {
                        const int WM_KEYDOWN = 0x0100;
                        if ( m.Msg == WM_KEYDOWN )
                        {
                                switch ( keyData )
                                {
                                        case Keys.Tab :
                                        {
                                                MoveRight() ;
                                                return true ;
                                        }
                                        case Keys.Shift | Keys.Tab:
                                        {
                                                MoveLeft() ;
                                                return true ;
                                        }
                                        case Keys.Up:
                                        {
                                                MoveUp() ;
                                                return true ;
                                        }
                                        case Keys.Down :
                                        {
                                                MoveDown() ;
                                                return true ;
                                        }
                                }
                        }
                        return base.ProcessCmdKey(ref m,keyData) ;
                }

                private void Cell_PropertyChange(object sender, System.EventArgs e)
                {
                        Refresh() ;
                }

                private void CellRange_PropertyChange(object sender, System.EventArgs e)
                {
                        Refresh() ;
                }
                #endregion
        }

        #region ヒットテストクラス
        [Serializable]
        [TypeConverter(typeof(HitTestTypeConverter))]
        public enum HitTestType 
        {
                None = 0 ,
                Cell = 1
        }
        internal class HitTestTypeConverter : ExpandableObjectConverter 
        {
                public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
                {
                        if (destinationType == typeof(string)) return true;
                        return base.CanConvertTo(context, destinationType);
                }
                public override object ConvertTo(ITypeDescriptorContext context, 
                        System.Globalization.CultureInfo culture, object value, Type destType) 
                {
                        if (destType == typeof(string) && value is HitTestType) 
                        {
                                HitTestType ic = (HitTestType)value;
                                switch ( ic )
                                {
                                        case HitTestType.None: return "None" ;
                                        case HitTestType.Cell: return "Cell" ;
                                }
                                return "" ;
                        }
                        return base.ConvertTo(context, culture, value, destType);
                }   
        }

        [Serializable]
        [TypeConverter(typeof(HitTestInfoConverter))]
        public class HitTestInfo
        {
                private int _column ;
                private int _row ;
                private HitTestType _type ;

                public HitTestInfo()
                {
                        _column = -1 ;
                        _row = -1 ;
                        _type = HitTestType.None ;
                }

                public HitTestInfo(int column, int row, HitTestType type)
                {
                        _column = column ;
                        _row = row ;
                        _type = type ;
                }

                public int Column               { get { return _column ; } }
                public int Row                  { get { return _row ; } }
                public HitTestType Type { get { return _type ; } }
        }
        internal class HitTestInfoConverter : ExpandableObjectConverter 
        {
                public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
                {
                        if (destinationType == typeof(string)) return true;
                        return base.CanConvertTo(context, destinationType);
                }
                public override object ConvertTo(ITypeDescriptorContext context, 
                        System.Globalization.CultureInfo culture, object value, Type destType) 
                {
                        if (destType == typeof(string) && value is HitTestInfo) 
                        {
                                HitTestInfo ic = (HitTestInfo)value;
                                return ic.Column.ToString() + "," + ic.Row.ToString() + "," + ic.Type.ToString() ;
                        }
                        return base.ConvertTo(context, culture, value, destType);
                }   
        }
        #endregion

        #region スプレッドシートセルクラス
        [Serializable]
        [TypeConverter(typeof(SpreadCellConverter))]
        public class SpreadCell
        {
                private int _columnNumber ;
                private int _rowNumber ;

                public SpreadCell()
                {
                        _columnNumber = -1 ;
                        _rowNumber = -1 ;
                }

                public SpreadCell(int column, int row)
                {
                        _columnNumber = column ;
                        _rowNumber = row ;
                }

                public int ColumnNumber         { get { return _columnNumber ; } }
                public int RowNumber            { get { return _rowNumber ; } }
        }
        internal class SpreadCellConverter : ExpandableObjectConverter 
        {
                public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
                {
                        if (destinationType == typeof(string)) return true;
                        return base.CanConvertTo(context, destinationType);
                }
                public override object ConvertTo(ITypeDescriptorContext context, 
                        System.Globalization.CultureInfo culture, object value, Type destType) 
                {
                        if (destType == typeof(string) && value is SpreadCell) 
                        {
                                SpreadCell ic = (SpreadCell)value;
                                return ic.ColumnNumber.ToString() + "," + ic.RowNumber.ToString() ;
                        }
                        return base.ConvertTo(context, culture, value, destType);
                }   
        }
        #endregion

        #region セルプロパティクラス
        [Serializable]
        [TypeConverter(typeof(CellConverter))]
        public class Cell 
        {
                private string _text ;
                private Font _font ;
                private Color _forecolor ;
                private Color _backcolor ;

                public Cell()
                {
                        _text = "" ;
                        _font = TextBox.DefaultFont ;
                        _forecolor = TextBox.DefaultForeColor ;
                        _backcolor = TextBox.DefaultBackColor ;
                }

                public Cell(string text, Font font, Color forecolor, Color backcolor)
                {
                        _text = text ;
                        _font = font ;
                        _forecolor = forecolor ;
                        _backcolor = backcolor ;
                        RaisePropertyChange() ;
                }

                [Description("セルのテキストです。"),Category("表示")]
                public string Text
                {
                        get
                        {
                                return _text ;
                        }
                        set
                        {
                                _text = value ;
                                RaisePropertyChange() ;
                        }
                }
                [Description("セルでテキストを表示するフォントです。"),Category("表示")]
                public Font Font
                {
                        get
                        {
                                return _font ;
                        }
                        set
                        {
                                _font = value ;
                                RaisePropertyChange() ;
                        }
                }
                [Description("セルでテキストを表示するために使用する前景色です。"),Category("表示")]
                public Color ForeColor
                {
                        get
                        {
                                return _forecolor ;
                        }
                        set
                        {
                                _forecolor = value ;
                                RaisePropertyChange() ;
                        }
                }
                [Description("セルでテキストを表示するために使用する背景色です。"),Category("表示")]
                public Color BackColor
                {
                        get
                        {
                                return _backcolor ;
                        }
                        set
                        {
                                _backcolor = value ;
                                RaisePropertyChange() ;
                        }
                }

                private EventHandler onPropertyChange ;
                [Description("プロパティ変更されたときに発生します。"),Category("アクション")]
                public event EventHandler PropertyChange 
                { add { onPropertyChange += value; } remove { onPropertyChange -= value; } }
                protected virtual void OnPropertyChange(EventArgs e) 
                {
                        if (onPropertyChange != null) onPropertyChange(this, e);
                }
                private void RaisePropertyChange()
                {
                        EventArgs e = new EventArgs() ;
                        OnPropertyChange( e ) ;
                }
        }
        internal class CellConverter : ExpandableObjectConverter 
        {
                public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
                {
                        if (destinationType == typeof(string)) return true;
                        if (destinationType == typeof(InstanceDescriptor)) return true;
                        return base.CanConvertTo(context, destinationType);
                }
                public override object ConvertTo(ITypeDescriptorContext context, 
                        System.Globalization.CultureInfo culture, object value, Type destType) 
                {
                        if (destType == typeof(string) && value is Cell) 
                        {
                                Cell ic = (Cell)value;
                                return ic.Text + "," + ic.Font.ToString() + "," +
                                        ic.ForeColor.ToString()  + "," + ic.BackColor.ToString() ;
                        }
                        if (destType == typeof(InstanceDescriptor) && value is Cell) 
                        {
                                Cell ic = (Cell)value;
                                System.Reflection.ConstructorInfo ctor = typeof(Cell).GetConstructor(new Type[] {
                                        typeof(string), typeof(Font), typeof(Color), typeof(Color) } ) ;
                                if (ctor != null) 
                                {
                                        return new InstanceDescriptor(ctor, new object[] {ic.Text, ic.Font, ic.ForeColor, ic.BackColor}) ;
                                }
                        }
                        return base.ConvertTo(context, culture, value, destType);
                }   
        }
        #endregion

        #region セル範囲クラス
        [Serializable]
        [TypeConverter(typeof(CellRangeConverter))]
        public class CellRange 
        {
                private int _left ;
                private int _top ;
                private int _right ;
                private int _bottom ;

                public CellRange()
                {
                        _left = 0 ;
                        _top = 0 ;
                        _right = 0 ;
                        _bottom = 0 ;
                }

                public CellRange(int left, int top, int right, int bottom)
                {
                        _left = left ;
                        _top = top ;
                        _right = right ;
                        _bottom = bottom ;
                        RaisePropertyChange() ;
                }

                [Description("セル範囲の左端のカラム位置です。"),Category("表示")]
                [RefreshProperties(RefreshProperties.Repaint)]
                public int Left
                {
                        get
                        {
                                return _left ;
                        }
                        set
                        {
                                if ( value >= 0 )
                                {
                                        _left = value ;
                                        RaisePropertyChange() ;
                                }
                        }
                }

                [Description("セル範囲の上端の行位置です。"),Category("表示")]
                [RefreshProperties(RefreshProperties.Repaint)]
                public int Top
                {
                        get
                        {
                                return _top ;
                        }
                        set
                        {
                                if ( value >= 0 )
                                {
                                        _top = value ;
                                        if ( _top > _bottom )
                                        {
                                                _top = _bottom ;
                                                _bottom = value ;
                                        }
                                        RaisePropertyChange() ;
                                }
                        }
                }

                [Description("セル範囲の右端のカラム位置です。"),Category("表示")]
                [RefreshProperties(RefreshProperties.Repaint)]
                public int Right
                {
                        get
                        {
                                return _right ;
                        }
                        set
                        {
                                _right = value ;
                                if ( _left > _right )
                                {
                                        _right = _left ;
                                        _left = value ;
                                }
                                RaisePropertyChange() ;
                        }
                }

                [Description("セル範囲の下端の行位置です。"),Category("表示")]
                [RefreshProperties(RefreshProperties.Repaint)]
                public int Bottom
                {
                        get
                        {
                                return _bottom ;
                        }
                        set
                        {
                                _bottom = value ;
                                if ( _top > _bottom )
                                {
                                        _bottom = _top ;
                                        _top = value ;
                                }
                                RaisePropertyChange() ;
                        }
                }

                public bool Contains( int x, int y )
                {
                        if ( x >= _left && x <= _right && y >= _top && y <= _bottom )
                        {
                                return true ;
                        }
                        return false ;
                }

                private EventHandler onPropertyChange ;
                [Description("プロパティ変更されたときに発生します。"),Category("アクション")]
                public event EventHandler PropertyChange 
                { add { onPropertyChange += value; } remove { onPropertyChange -= value; } }
                protected virtual void OnPropertyChange(EventArgs e) 
                {
                        if (onPropertyChange != null) onPropertyChange(this, e);
                }
                private void RaisePropertyChange()
                {
                        EventArgs e = new EventArgs() ;
                        OnPropertyChange( e ) ;
                }
        }
        internal class CellRangeConverter : ExpandableObjectConverter 
        {
                public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
                {
                        if (destinationType == typeof(string)) return true;
                        if (destinationType == typeof(InstanceDescriptor)) return true;
                        return base.CanConvertTo(context, destinationType);
                }
                public override object ConvertTo(ITypeDescriptorContext context, 
                        System.Globalization.CultureInfo culture, object value, Type destType) 
                {
                        if (destType == typeof(string) && value is CellRange) 
                        {
                                CellRange ic = (CellRange)value;
                                return ic.Left.ToString() + "," + ic.Top.ToString() + "-" +
                                        ic.Right.ToString()  + "," + ic.Bottom.ToString() ;
                        }
                        if (destType == typeof(InstanceDescriptor) && value is CellRange) 
                        {
                                CellRange ic = (CellRange)value;
                                System.Reflection.ConstructorInfo ctor = typeof(CellRange).GetConstructor(new Type[] {
                                                typeof(int), typeof(int), typeof(int), typeof(int) } ) ;
                                if (ctor != null) 
                                {
                                        return new InstanceDescriptor(ctor, new object[] {ic.Left, ic.Top, ic.Right, ic.Bottom}) ;
                                }
                        }
                        return base.ConvertTo(context, culture, value, destType);
                }   
        }

        [Serializable()]
        public class CellRangeCollection : CollectionBase  
        {
                private void Adjust( ref CellRange range )
                {
                        int swap ;
                        if ( range.Left > range.Right )
                        {
                                swap = range.Left ;
                                range.Left = range.Right ;
                                range.Right = swap ;
                        }
                        if ( range.Top > range.Bottom )
                        {
                                swap = range.Top ;
                                range.Top = range.Bottom ;
                                range.Bottom = swap ;
                        }
                }

                public CellRange this[ int index ]  
                {
                        get  
                        {
                                return( (CellRange) List[index] );
                        }
                        set  
                        {
                                CellRange range = value ;
                                Adjust( ref value ) ;
                                List[index] = value;
                                range.PropertyChange += new System.EventHandler(this.CellRange_PropertyChange);
                                RaisePropertyChange() ;
                        }
                }

                public int Add( CellRange value )  
                {
                        CellRange range = value ;
                        Adjust( ref value ) ;
                        int pos = List.Add( value ) ;
                        range.PropertyChange += new System.EventHandler(this.CellRange_PropertyChange);
                        RaisePropertyChange() ;
                        return pos ;
                }

                public int IndexOf( CellRange value )  
                {
                        Adjust( ref value ) ;
                        return( List.IndexOf( value ) );
                }

                public void Insert( int index, CellRange value )  
                {
                        Adjust( ref value ) ;
                        CellRange range = value ;
                        List.Insert( index, value );
                        range.PropertyChange += new System.EventHandler(this.CellRange_PropertyChange);
                        RaisePropertyChange() ;
                }

                public void Remove( CellRange value )  
                {
                        Adjust( ref value ) ;
                        List.Remove( value );
                        RaisePropertyChange() ;
                }

                public bool Contains( CellRange value )  
                {
                        Adjust( ref value ) ;
                        return( List.Contains( value ) );
                }

                private EventHandler onPropertyChange ;
                [Description("プロパティ変更されたときに発生します。"),Category("アクション")]
                public event EventHandler PropertyChange 
                { add { onPropertyChange += value; } remove { onPropertyChange -= value; } }
                protected virtual void OnPropertyChange(EventArgs e) 
                {
                        if (onPropertyChange != null) onPropertyChange(this, e);
                }
                private void RaisePropertyChange()
                {
                        EventArgs e = new EventArgs() ;
                        OnPropertyChange( e ) ;
                }
                private void CellRange_PropertyChange(object sender, System.EventArgs e)
                {
                        RaisePropertyChange() ;
                }
        }
        #endregion
}