//////////////////////////////////////////////////////////////////////////////////// // File: Header.cs // Author: Sergei Pavlovsky // // Copyright (c) 2004 by Sergei Pavlovsky (sergei_vp@hotmail.com, sergei_vp@ukr.net) // // This file is provided "as is" with no expressed or implied warranty. // The author accepts no liability if it causes any damage whatsoever. // // This code is free and may be used in any way you desire. If the source code in // this file is used in any commercial application then a simple email would be // nice. // // Revisions: // 06/24/2004 - Bugfix. Control was flickering on resizing. // //////////////////////////////////////////////////////////////////////////////////// using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Data; using System.Windows.Forms; using System.Windows.Forms.Design; using System.Runtime.InteropServices; using System.Diagnostics; using System.Runtime.Serialization; using System.ComponentModel.Design; using System.Drawing.Design; using System.Security.Permissions; namespace SP.Windows { #region Common /// /// ErrMsg class /// internal abstract class ErrMsg { public static string NegVal() { return "Value cannot be negative."; } public static string NullVal() { return "Value cannot be null."; } public static string InvVal(string sValue) { return string.Format("Value of \"{0}\" is invalid.", sValue); } public static string IndexOutOfRange() { return "Index is out of range."; } public static string SectionIsAlreadyAttached(string sText) { return "Section \"" + sText + "\" is already added to the collection."; } public static string SectionDoesNotExist(string sText) { return "Section \"" + sText + "\" does not exist in the collection"; } public static string FailedToInsertItem() { return "Failed to insert item."; } public static string FailedToRemoveItem() { return "Failed to remove item."; } public static string FailedToChangeItem() { return "Failed to change item."; } } #endregion Common #region Header Section /// /// Types /// [Serializable] public enum HeaderSectionSortMarks : int { Non = 0, Up = NativeHeader.HDF_SORTUP, Down = NativeHeader.HDF_SORTDOWN } /// /// HeaderSection class. /// [ Description("HeaderSection component"), DefaultProperty("Text"), ToolboxItem(false), DesignTimeVisible(false), SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode) ] public class HeaderSection : Component, ICloneable { /// /// Data fields /// // Owner collection private HeaderSectionCollection collection = null; [ Description("Collection which section is kept in."), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false) ] internal HeaderSectionCollection Collection { get { return this.collection; } set { this.collection = value; } } // Owner header control [ Description("Owner header control."), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false) ] public Header Header { get { return collection != null ? collection.Header : null; } } // Index [ Description("Index of the section."), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false) ] public int Index { get { return collection != null ? collection.IndexOf(this) : -1; } } // Width private int cxWidth = 100; internal void _SetWidth(int cx) { if ( cx < 0 ) throw new ArgumentOutOfRangeException("cx", cx, ErrMsg.NegVal()); this.cxWidth = cx; } [ Category("Data"), Description("Specifies section width.") ] public int Width { get { return this.cxWidth; } set { if ( value != this.cxWidth ) { _SetWidth(value); // Notify owner header control Header owner = this.Header; if ( owner != null ) { owner._OnSectionWidthChanged(this); } } } } // TODO Support owner drawing HDF_OWNERDRAW // Format private int fFormat = NativeHeader.HDF_LEFT; internal void _SetFormat(int fFormat) { this.fFormat = fFormat; } [ Description("Raw window styles."), Browsable(false) ] internal int Format { get { if ( this._GetActualRightToLeft() == RightToLeft.Yes ) return this.fFormat|NativeHeader.HDF_RTLREADING; else return this.fFormat; } } // Text private string text = null; internal void _SetText(string text) { this.text = text; if ( this.text != null ) this.fFormat |= NativeHeader.HDF_STRING; else this.fFormat &= (~NativeHeader.HDF_STRING); } [ Category("Data"), Description("Text to be displayed."), DefaultValue("Section") ] public string Text { get { return this.text; } set { if ( value != this.text ) { _SetText(value); // Notify owner header control Header owner = this.Header; if ( owner != null ) { owner._OnSectionTextChanged(this); } } } } // ImageIndex private int iImage = -1; internal void _SetImageIndex(int index) { this.iImage = index; if ( this.iImage >= 0 ) this.fFormat |= NativeHeader.HDF_IMAGE; else { if ( this.iImage != -1 ) throw new ArgumentException(ErrMsg.InvVal(index.ToString()), "value"); this.fFormat &= (~NativeHeader.HDF_IMAGE); } } [ Category("Data"), Description("Index of image associated with section."), TypeConverter(typeof(ImageIndexConverter)), // Editor(typeof(ImageIndexEditor), typeof(UITypeEditor)), Localizable(true), DefaultValue(-1) ] public int ImageIndex { get { return this.iImage; } set { if ( value != this.iImage ) { _SetImageIndex(value); // Notify owner header control Header owner = this.Header; if ( owner != null ) { owner._OnSectionImageIndexChanged(this); } } } } // Bitmap private Bitmap bitmap = null; private IntPtr hBitmap = IntPtr.Zero; internal IntPtr _GetHBitmap() { if ( this.hBitmap == IntPtr.Zero && this.bitmap != null ) { this.hBitmap = this.bitmap.GetHbitmap(); } return this.hBitmap; } internal void _SetBitmap(Bitmap bitmap) { if ( this.hBitmap != IntPtr.Zero ) { NativeWindowCommon.DeleteObject(this.hBitmap); this.hBitmap = IntPtr.Zero; } this.bitmap = bitmap; if ( this.bitmap != null ) this.fFormat |= NativeHeader.HDF_BITMAP; else this.fFormat &= (~NativeHeader.HDF_BITMAP); } [ Category("Data"), Description("Bitmap to be drawn on the section."), ] public Bitmap Bitmap { get { return this.bitmap; } set { if ( value != this.bitmap ) { _SetBitmap(value); // Notify owner header control Header owner = this.Header; if ( owner != null ) { owner._OnSectionBitmapChanged(this); } } } } // RightToLeft private RightToLeft enRightToLeft = RightToLeft.No; internal RightToLeft _GetActualRightToLeft() { Header owner = this.Header; return ( this.enRightToLeft == RightToLeft.Inherit && owner != null ) ? owner.RightToLeft : this.enRightToLeft; } internal void _SetRightToLeft(RightToLeft enRightToLeft) { this.enRightToLeft = enRightToLeft; } [ Category("Appearance"), Description("Right to left layout."), ] public RightToLeft RightToLeft { get { return enRightToLeft; } set { if ( this.enRightToLeft != value ) { _SetRightToLeft(value); // Notify owner header control Header owner = this.Header; if ( owner != null ) { owner._OnSectionRightToLeftChanged(this); } } } } // Content align internal HorizontalAlignment _GetContentAlign() { switch ( fFormat & NativeHeader.HDF_JUSTIFYMASK ) { case NativeHeader.HDF_LEFT: return HorizontalAlignment.Left; case NativeHeader.HDF_RIGHT: return HorizontalAlignment.Right; case NativeHeader.HDF_CENTER: return HorizontalAlignment.Center; } return HorizontalAlignment.Left; } internal void _SetContentAlign(HorizontalAlignment enValue) { int nFlag; switch ( enValue ) { case HorizontalAlignment.Left: nFlag = NativeHeader.HDF_LEFT; break; case HorizontalAlignment.Right: nFlag = NativeHeader.HDF_RIGHT; break; case HorizontalAlignment.Center: nFlag = NativeHeader.HDF_CENTER; break; default: throw new NotSupportedException(ErrMsg.InvVal(enValue.ToString()), null); } this.fFormat &= (~NativeHeader.HDF_JUSTIFYMASK); this.fFormat |= nFlag; } [ Category("Appearance"), Description("Specifies content alignment."), ] public HorizontalAlignment ContentAlign { get { return _GetContentAlign(); } set { if ( value != _GetContentAlign() ) { _SetContentAlign(value); // Notify owner header control Header owner = this.Header; if ( owner != null ) { owner._OnSectionContentAlignChanged(this); } } } } // Image align internal LeftRightAlignment _GetImageAlign() { if ( (this.fFormat & NativeHeader.HDF_BITMAP_ON_RIGHT) != 0 ) return LeftRightAlignment.Right; else return LeftRightAlignment.Left; } internal void _SetImageAlign(LeftRightAlignment enValue) { int nFlag; const int fMask = NativeHeader.HDF_BITMAP_ON_RIGHT; switch ( enValue ) { case LeftRightAlignment.Left: nFlag = 0; break; case LeftRightAlignment.Right: nFlag = NativeHeader.HDF_BITMAP_ON_RIGHT; break; default: throw new NotSupportedException(ErrMsg.InvVal(enValue.ToString()), null); } this.fFormat &= (~fMask); this.fFormat |= nFlag; } [ Category("Appearance"), Description("Specifies image placement."), ] public LeftRightAlignment ImageAlign { get { return _GetImageAlign(); } set { if ( value != _GetImageAlign() ) { _SetImageAlign(value); // Notify owner header control Header owner = this.Header; if ( owner != null ) { owner._OnSectionImageAlignChanged(this); } } } } // Sort mark internal HeaderSectionSortMarks _GetSortMark() { const int fSortMask = NativeHeader.HDF_SORTUP|NativeHeader.HDF_SORTDOWN; return (HeaderSectionSortMarks)(this.fFormat & fSortMask); } internal void _SetSortMark(HeaderSectionSortMarks enValue) { const int fSortMask = NativeHeader.HDF_SORTUP|NativeHeader.HDF_SORTDOWN; int nFlag; switch ( enValue ) { case HeaderSectionSortMarks.Non: nFlag = 0; break; case HeaderSectionSortMarks.Up: nFlag = NativeHeader.HDF_SORTUP; break; case HeaderSectionSortMarks.Down: nFlag = NativeHeader.HDF_SORTDOWN; break; default: throw new NotSupportedException(ErrMsg.InvVal(enValue.ToString()), null); } this.fFormat &= (~fSortMask); this.fFormat |= nFlag; } [ Category("Appearance"), Description("Defines sort mark to be shown on the section."), ] public HeaderSectionSortMarks SortMark { get { return _GetSortMark(); } set { if ( value != _GetSortMark() ) { _SetSortMark(value); // Notify owner header control Header owner = this.Header; if ( owner != null ) { owner._OnSectionSortMarkChanged(this); } } } } // Tag internal void _SetTag(object tag) { this.tag = tag; } private object tag = null; [ Browsable(false) ] public object Tag { get { return this.tag; } set { if ( this.tag != value ) { this.tag = value; } } } /// /// Construction & finalization /// public HeaderSection() { } public HeaderSection(string text, int cxWidth) { _SetText(text); _SetWidth(cxWidth); } public HeaderSection(string text, int cxWidth, int iImage) { _SetText(text); _SetWidth(cxWidth); _SetImageIndex(iImage); } public HeaderSection(string text, int cxWidth, object tag) { _SetText(text); _SetWidth(cxWidth); _SetTag(tag); } public HeaderSection(string text, int cxWidth, int iImage, object tag) { _SetText(text); _SetWidth(cxWidth); _SetImageIndex(iImage); _SetTag(tag); } public HeaderSection(string text, int cxWidth, Bitmap bitmap) { _SetText(text); _SetWidth(cxWidth); _SetBitmap(bitmap); } public HeaderSection(string text, int cxWidth, int iImage, Bitmap bitmap) { _SetText(text); _SetWidth(cxWidth); _SetImageIndex(iImage); _SetBitmap(bitmap); } public HeaderSection(string text, int cxWidth, int iImage, Bitmap bitmap, HorizontalAlignment enContentAlign) { _SetText(text); _SetWidth(cxWidth); _SetImageIndex(iImage); _SetBitmap(bitmap); _SetContentAlign(enContentAlign); } public HeaderSection(string text, int cxWidth, int iImage, Bitmap bitmap, HorizontalAlignment enContentAlign, LeftRightAlignment enImageAlign) { _SetText(text); _SetWidth(cxWidth); _SetImageIndex(iImage); _SetBitmap(bitmap); _SetContentAlign(enContentAlign); _SetImageAlign(enImageAlign); } public HeaderSection(string text, int cxWidth, int iImage, Bitmap bitmap, HorizontalAlignment enContentAlign, LeftRightAlignment enImageAlign, object tag) { _SetText(text); _SetWidth(cxWidth); _SetImageIndex(iImage); _SetBitmap(bitmap); _SetContentAlign(enContentAlign); _SetImageAlign(enImageAlign); _SetTag(tag); } public HeaderSection(string text, int cxWidth, int iImage, Bitmap bitmap, RightToLeft enRightToLeft, HorizontalAlignment enContentAlign, LeftRightAlignment enImageAlign, HeaderSectionSortMarks enSortMark, object tag) { _SetText(text); _SetWidth(cxWidth); _SetImageIndex(iImage); _SetBitmap(bitmap); _SetRightToLeft(enRightToLeft); _SetContentAlign(enContentAlign); _SetImageAlign(enImageAlign); _SetSortMark(enSortMark); _SetTag(tag); } protected HeaderSection(int cxWidth, string text, int iImage, Bitmap bitmap, RightToLeft enRightToLeft, int fFormat, object tag) { _SetText(text); _SetWidth(cxWidth); _SetImageIndex(iImage); _SetBitmap(bitmap); _SetRightToLeft(enRightToLeft); _SetFormat(fFormat); _SetTag(tag); } ~HeaderSection() { Dispose(false); } /// /// Overrides /// public override string ToString() { return "HeaderSection: {" + this.text + "}"; } protected override void Dispose(bool bDisposing) { if ( this.hBitmap != IntPtr.Zero ) { NativeWindowCommon.DeleteObject(this.hBitmap); this.hBitmap = IntPtr.Zero; } if ( bDisposing && this.collection != null ) { this.collection.Remove(this); } base.Dispose(bDisposing); } /// /// ICloneable implementation /// public virtual object Clone() { return new HeaderSection(this.cxWidth, this.text, this.iImage, this.bitmap, this.enRightToLeft, this.fFormat, this.tag); } /// /// Operations /// internal void ComposeNativeData(int iOrder, out NativeHeader.HDITEM item) { item = new NativeHeader.HDITEM(); // Width item.mask = NativeHeader.HDI_WIDTH; item.cxy = this.cxWidth; // Text if ( this.text != null ) { item.mask |= NativeHeader.HDI_TEXT; item.lpszText = this.text; item.cchTextMax = 0; } // ImageIndex if ( this.iImage >= 0 ) { item.mask |= NativeHeader.HDI_IMAGE; item.iImage = this.iImage; } // Bitmap if ( this.bitmap != null && this.bitmap.GetHbitmap() != IntPtr.Zero ) { item.mask |= NativeHeader.HDI_BITMAP; item.hbm = this._GetHBitmap(); } // Format item.mask |= NativeHeader.HDI_FORMAT; item.fmt = this.Format; // Order if ( iOrder >= 0 ) { item.mask |= NativeHeader.HDI_ORDER; item.iOrder = iOrder; } // item.lParam; // item.type; // item.pvFilter; } } #endregion // HeaderSection #region Header Sections' Collection /// /// HeaderSectionCollection class. /// // [Serializable] public class HeaderSectionCollection : IList { /// /// Data fields /// private Header owner = null; public Header Header { get { return this.owner; } } private ArrayList alSectionsByOrder = null; private ArrayList alSectionsByRawIndex = null; public int Count { get { return this.alSectionsByOrder.Count; } } public HeaderSection this[int index] { get { return (HeaderSection)this.alSectionsByOrder[index]; } set { if ( index < 0 || index >= this.alSectionsByOrder.Count ) throw new ArgumentOutOfRangeException("index", index, ErrMsg.IndexOutOfRange()); _SetSection(index, (HeaderSection)value); } } /// /// Construction /// internal HeaderSectionCollection(Header owner) { this.owner = owner; this.alSectionsByOrder = new ArrayList(); this.alSectionsByRawIndex = new ArrayList(); } /// /// Helpers /// private void BindSection(HeaderSection item) { if ( item == null ) { throw new ArgumentNullException("item", ErrMsg.NullVal()); } if ( item.Collection != null ) { throw new ArgumentException(ErrMsg.SectionIsAlreadyAttached(item.Text), "item"); } item.Collection = this; } private void UnbindSection(HeaderSection item) { if ( item == null ) { throw new ArgumentNullException("item", ErrMsg.NullVal()); } if ( item.Collection != this ) { throw new ArgumentException(ErrMsg.SectionDoesNotExist(item.Text), "item"); } item.Collection = null; } /// /// Operations /// internal int _FindSectionRawIndex(HeaderSection item) { return this.alSectionsByRawIndex.IndexOf(item); } internal HeaderSection _GetSectionByRawIndex(int iSection) { return (HeaderSection)this.alSectionsByRawIndex[iSection]; } internal void _Move(int iFrom, int iTo) { Debug.Assert( iFrom >= 0 || iFrom < this.alSectionsByOrder.Count ); Debug.Assert( iTo >= 0 || iTo < this.alSectionsByOrder.Count ); Debug.Assert( this.alSectionsByOrder.Count == this.alSectionsByRawIndex.Count ); HeaderSection item = (HeaderSection)this.alSectionsByOrder[iFrom]; this.alSectionsByOrder.RemoveAt(iFrom); this.alSectionsByOrder.Insert(iTo, item); } internal void _SetSection(int index, HeaderSection item) { Debug.Assert( index >= 0 || index < this.alSectionsByOrder.Count ); Debug.Assert( this.alSectionsByOrder.Count == this.alSectionsByRawIndex.Count ); // Bind item to the collection BindSection(item); HeaderSection itemOld = (HeaderSection)this.alSectionsByOrder[index]; int iSection = this.alSectionsByRawIndex.IndexOf(itemOld); try { this.alSectionsByOrder[index] = item; this.alSectionsByRawIndex[iSection] = item; UnbindSection(itemOld); // Notify owner if ( this.owner != null ) this.owner._OnSectionChanged(iSection, item); } catch { if ( itemOld.Collection == null ) BindSection(itemOld); this.alSectionsByOrder[index] = itemOld; this.alSectionsByRawIndex[iSection] = itemOld; UnbindSection(item); throw; } } public void Insert(int index, HeaderSection item) { Debug.Assert( this.alSectionsByOrder.Count == this.alSectionsByRawIndex.Count ); if ( index < 0 || index > this.alSectionsByOrder.Count ) throw new ArgumentOutOfRangeException("index", index, ErrMsg.IndexOutOfRange()); // Bind item to the collection BindSection(item); try { this.alSectionsByOrder.Insert(index, item); this.alSectionsByRawIndex.Insert(index, item); try { // Notify owner if ( this.owner != null ) this.owner._OnSectionInserted(index, item); } catch { this.alSectionsByOrder.Remove(item); this.alSectionsByRawIndex.Remove(item); throw; } } catch { if ( this.alSectionsByOrder.Count > this.alSectionsByRawIndex.Count ) this.alSectionsByOrder.RemoveAt(index); UnbindSection(item); throw; } } public int Add(HeaderSection item) { int index = this.alSectionsByOrder.Count; Insert(index, item); return index; } public void RemoveAt(int index) { Debug.Assert( this.alSectionsByOrder.Count == this.alSectionsByRawIndex.Count ); if ( index < 0 || index >= this.alSectionsByOrder.Count ) throw new ArgumentOutOfRangeException("index", index, ErrMsg.IndexOutOfRange()); HeaderSection item = (HeaderSection)this.alSectionsByOrder[index]; int iSectionRemoved = this.alSectionsByRawIndex.IndexOf(item); Debug.Assert( iSectionRemoved >= 0 ); UnbindSection(item); this.alSectionsByOrder.RemoveAt(index); this.alSectionsByRawIndex.RemoveAt(iSectionRemoved); if ( this.owner != null ) this.owner._OnSectionRemoved(iSectionRemoved, item); } public virtual void Remove(HeaderSection item) { int index = this.alSectionsByOrder.IndexOf(item); if ( index != -1 ) RemoveAt(index); } public void Move(int iFrom, int iTo) { if ( iFrom < 0 || iFrom >= this.alSectionsByOrder.Count ) throw new ArgumentOutOfRangeException("iFrom", iFrom, ErrMsg.IndexOutOfRange()); if ( iTo < 0 || iTo >= this.alSectionsByOrder.Count ) throw new ArgumentOutOfRangeException("iTo", iTo, ErrMsg.IndexOutOfRange()); _Move(iFrom, iTo); } public void Clear() { Debug.Assert( this.alSectionsByOrder.Count == this.alSectionsByRawIndex.Count ); foreach( HeaderSection item in this.alSectionsByOrder ) { UnbindSection(item); } this.alSectionsByOrder.Clear(); this.alSectionsByRawIndex.Clear(); if ( this.owner != null ) this.owner._OnAllSectionsRemoved(); } internal void Clear(bool bDisposeItems) { Debug.Assert( this.alSectionsByOrder.Count == this.alSectionsByRawIndex.Count ); foreach( HeaderSection item in this.alSectionsByOrder ) { UnbindSection(item); if ( bDisposeItems ) item.Dispose(); } this.alSectionsByOrder.Clear(); this.alSectionsByRawIndex.Clear(); if ( this.owner != null ) this.owner._OnAllSectionsRemoved(); } public int IndexOf(HeaderSection item) { return this.alSectionsByOrder.IndexOf(item); } public bool Contains(HeaderSection item) { return this.alSectionsByOrder.IndexOf(item) != -1; } public void CopyTo(Array aDest, int index) { this.alSectionsByOrder.CopyTo(aDest, index); } /// /// Implementation: IEnumerable /// IEnumerator IEnumerable.GetEnumerator() { return this.alSectionsByOrder.GetEnumerator(); } /// /// Implementation: ICollection /// bool ICollection.IsSynchronized { get { return true; } } object ICollection.SyncRoot { get { return this; } } /// /// Implementation: IList /// bool IList.IsFixedSize { get { return false; } } bool IList.IsReadOnly { get { return false; } } object IList.this[int index] { get { return this.alSectionsByOrder[index]; } set { _SetSection(index, (HeaderSection)value); } } void IList.Insert(int index, object value) { Insert(index, (HeaderSection)value); } int IList.Add(object value) { return Add((HeaderSection)value); } void IList.Remove(object value) { Remove((HeaderSection)value); } bool IList.Contains(object value) { return this.alSectionsByOrder.Contains(value); } int IList.IndexOf(object value) { return this.alSectionsByOrder.IndexOf(value); } } // HeaderSectionCollection class #endregion // HeaderSectionCollection #region Header Event Arguments' classes /// /// HeaderSectionEventArgs class /// [Serializable] public class HeaderSectionEventArgs : EventArgs { // Fields private HeaderSection item = null; public HeaderSection Item { get { return this.item; } } // Fields private MouseButtons enButton = MouseButtons.None; public MouseButtons Button { get { return this.enButton; } } // Construction public HeaderSectionEventArgs(HeaderSection item) { this.item = item; } public HeaderSectionEventArgs(HeaderSection item, MouseButtons enButton) { this.item = item; this.enButton = enButton; } } // HeaderSectionEventArgs public delegate void HeaderSectionEventHandler( object sender, HeaderSectionEventArgs ea); /// /// HeaderSectionConformableEventArgs class /// [Serializable] public class HeaderSectionConformableEventArgs : HeaderSectionEventArgs { // Fields private bool bAccepted = true; public bool Accepted { get { return this.bAccepted; } set { this.bAccepted = value; } } // Construction public HeaderSectionConformableEventArgs(HeaderSection item) : base(item) { } public HeaderSectionConformableEventArgs(HeaderSection item, MouseButtons enButton) : base(item, enButton) { } } // HeaderSectionConformableEventArgs public delegate void HeaderSectionConformableEventHandler( object sender, HeaderSectionConformableEventArgs ea); /// /// HeaderSectionWidthEventArgs class /// [Serializable] public class HeaderSectionWidthEventArgs : HeaderSectionEventArgs { // Fields private int cxWidth = 0; public int Width { get { return this.cxWidth; } } // Construction public HeaderSectionWidthEventArgs(HeaderSection item) : base(item) { } public HeaderSectionWidthEventArgs(HeaderSection item, MouseButtons enButton) : base(item, enButton) { } public HeaderSectionWidthEventArgs(HeaderSection item, MouseButtons enButton, int cxWidth) : base(item, enButton) { this.cxWidth = cxWidth; } } // HeaderWidthItemEventArgs public delegate void HeaderSectionWidthEventHandler( object sender, HeaderSectionWidthEventArgs ea); /// /// HeaderSectionWidthConformableEventArgs class /// [Serializable] public class HeaderSectionWidthConformableEventArgs : HeaderSectionWidthEventArgs { // Fields private bool bAccepted = true; public bool Accepted { get { return this.bAccepted; } set { this.bAccepted = value; } } // Construction public HeaderSectionWidthConformableEventArgs(HeaderSection item) : base(item) { } public HeaderSectionWidthConformableEventArgs(HeaderSection item, MouseButtons enButton) : base(item, enButton) { } public HeaderSectionWidthConformableEventArgs(HeaderSection item, MouseButtons enButton, int cxWidth) : base(item, enButton, cxWidth) { } } // HeaderSectionWidthConformableEventArgs public delegate void HeaderSectionWidthConformableEventHandler( object sender, HeaderSectionWidthConformableEventArgs ea); /// /// HeaderSectionOrderEventArgs class /// [Serializable] public class HeaderSectionOrderEventArgs : HeaderSectionEventArgs { // Fields private int iOrder = -1; public int Order { get { return this.iOrder; } } // Construction public HeaderSectionOrderEventArgs(HeaderSection item) : base(item) { } public HeaderSectionOrderEventArgs(HeaderSection item, MouseButtons enButton) : base(item, enButton) { } public HeaderSectionOrderEventArgs(HeaderSection item, MouseButtons enButton, int iOrder) : base(item, enButton) { this.iOrder = iOrder; } } // HeaderSectionOrderEventArgs public delegate void HeaderSectionOrderEventHandler( object sender, HeaderSectionOrderEventArgs ea); /// /// HeaderSectionOrderConformableEventArgs class /// [Serializable] public class HeaderSectionOrderConformableEventArgs : HeaderSectionOrderEventArgs { // Fields private bool bAccepted = true; public bool Accepted { get { return this.bAccepted; } set { this.bAccepted = value; } } // Construction public HeaderSectionOrderConformableEventArgs(HeaderSection item) : base(item) { } public HeaderSectionOrderConformableEventArgs(HeaderSection item, MouseButtons enButton) : base(item, enButton) { } public HeaderSectionOrderConformableEventArgs(HeaderSection item, MouseButtons enButton, int iOrder) : base(item, enButton, iOrder) { } } // HeaderSectionOrderConformableEventArgs public delegate void HeaderSectionOrderConformableEventHandler( object sender, HeaderSectionOrderConformableEventArgs ea); public class HeaderCustomDrawEventArgs: HeaderSectionEventArgs { private readonly IntPtr _hdc; private readonly Rectangle _rc; public HeaderCustomDrawEventArgs( HeaderSection section, IntPtr hdc, Rectangle rc ) : base( section ) { _hdc = hdc; _rc = rc; } public IntPtr Hdc { get { return _hdc; } } public Rectangle Bounds { get { return _rc; } } } public delegate void HeaderCustomDrawEventHandler( object sender, HeaderCustomDrawEventArgs ea ); #endregion // HeaderEventArgs #region Header control /// /// Header class. /// [ Description("SP Header Control"), DefaultProperty("Sections"), DefaultEvent("AfterSectionTrack"), Designer(typeof(HeaderDesigner)), SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode) ] public class Header : Control { /// /// Types /// [Flags] public enum HitTestArea : int { NoWhere = NativeHeader.HHT_NOWHERE, OnHeader = NativeHeader.HHT_ONHEADER, OnDivider = NativeHeader.HHT_ONDIVIDER, OnDividerOpen = NativeHeader.HHT_ONDIVOPEN, OnFilter = NativeHeader.HHT_ONFILTER, OnFilterButton = NativeHeader.HHT_ONFILTERBUTTON, Above = NativeHeader.HHT_ABOVE, Below = NativeHeader.HHT_BELOW, ToLeft = NativeHeader.HHT_TOLEFT, ToRight = NativeHeader.HHT_TORIGHT } public struct HitTestInfo { public HitTestArea fArea; public HeaderSection section; } /// /// Data Fields /// private int fStyle = NativeHeader.WS_CHILD; // Clickable [ Category("Behavior"), Description("Determines if control will generate events " + "when user clicks on its column titles." ), DefaultValue(false) ] public bool Clickable { get { return (this.fStyle & NativeHeader.HDS_BUTTONS) != 0; } set { bool bOldValue = (this.fStyle & NativeHeader.HDS_BUTTONS) != 0; if ( value != bOldValue ) { if ( value ) this.fStyle |= NativeHeader.HDS_BUTTONS; else this.fStyle &= (~NativeHeader.HDS_BUTTONS); if ( this.IsHandleCreated ) { UpdateWndStyle(); } } } } // HotTrack [ Category("Behavior"), Description("Enables or disables hot tracking." ), DefaultValue(false) ] public bool HotTrack { get { return (this.fStyle & NativeHeader.HDS_HOTTRACK) != 0; } set { bool bOldValue = (this.fStyle & NativeHeader.HDS_HOTTRACK) != 0; if ( value != bOldValue ) { if ( value ) this.fStyle |= NativeHeader.HDS_HOTTRACK; else this.fStyle &= (~NativeHeader.HDS_HOTTRACK); if ( this.IsHandleCreated ) { UpdateWndStyle(); } } } } // Flat [ Category("Appearance"), Description("Causes the header control to be drawn flat when " + "Microsoft® Windows® XP is running in classic mode." ), DefaultValue(false) ] public bool Flat { get { return (this.fStyle & NativeHeader.HDS_FLAT) != 0; } set { bool bOldValue = (this.fStyle & NativeHeader.HDS_FLAT) != 0; if ( value != bOldValue ) { if ( value ) this.fStyle |= NativeHeader.HDS_FLAT; else this.fStyle &= (~NativeHeader.HDS_FLAT); if ( this.IsHandleCreated ) { UpdateWndStyle(); } } } } // AllowDragSections [ Category("Behavior"), Description("Determines if user will be able to drag header column " + "on another position." ), DefaultValue(false) ] public bool AllowDragSections { get { return (this.fStyle & NativeHeader.HDS_DRAGDROP) != 0; } set { bool bOldValue = (this.fStyle & NativeHeader.HDS_DRAGDROP) != 0; if ( value != bOldValue ) { if ( value ) this.fStyle |= NativeHeader.HDS_DRAGDROP; else this.fStyle &= (~NativeHeader.HDS_DRAGDROP); if ( this.IsHandleCreated ) { UpdateWndStyle(); } } } } // FullDragSections [ Category("Behavior"), Description("Causes the header control to display column contents " + "even while the user resizes a column." ), DefaultValue(false) ] public bool FullDragSections { get { return (this.fStyle & NativeHeader.HDS_FULLDRAG) != 0; } set { bool bOldValue = (this.fStyle & NativeHeader.HDS_FULLDRAG) != 0; if ( value != bOldValue ) { if ( value ) this.fStyle |= NativeHeader.HDS_FULLDRAG; else this.fStyle &= (~NativeHeader.HDS_FULLDRAG); if ( this.IsHandleCreated ) { UpdateWndStyle(); } } } } // Sections private HeaderSectionCollection colSections = null; [ Category("Data"), Description("Sections of the header." ), MergableProperty(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Localizable(true) ] public HeaderSectionCollection Sections { get { return this.colSections; } } private ImageList imageList = null; [ Category("Data"), Description("Images for header's sections." ), DefaultValue(null) ] public ImageList ImageList { get { return this.imageList; } set { if ( this.imageList != value ) { EventHandler ehRecreateHandle = new EventHandler(this.OnImageListRecreateHandle); EventHandler ehDetachImageList = new EventHandler(this.OnDetachImageList); if ( this.imageList != null ) { this.imageList.RecreateHandle -= ehRecreateHandle; this.imageList.Disposed -= ehDetachImageList; } this.imageList = value; if ( this.imageList != null ) { this.imageList.RecreateHandle += ehRecreateHandle; this.imageList.Disposed += ehDetachImageList; } if ( IsHandleCreated ) { HandleRef hrThis = new HandleRef(this, this.Handle); UpdateWndImageList(ref hrThis, this.imageList); } } } } private int cxBitmapMargin = SystemInformation.Border3DSize.Width; [ Category("Appearance"), Description("Width of the margin that surrounds a bitmap " + "within an existing header control." ), DefaultValue(2) ] public int BitmapMargin { get { return this.cxBitmapMargin; } set { if ( this.cxBitmapMargin != value ) { if ( value < 0 ) throw new ArgumentOutOfRangeException("value", value, ErrMsg.NegVal()); this.cxBitmapMargin = value; if ( IsHandleCreated ) { HandleRef hrThis = new HandleRef(this, this.Handle); UpdateWndBitmapMargin(ref hrThis, this.cxBitmapMargin); } } } } /// /// Construction & finalization /// public Header() : base() { this.SetStyle(ControlStyles.UserPaint, false); //this.SetStyle(ControlStyles.UserMouse, false); // ??? this.SetStyle(ControlStyles.StandardClick, false); this.SetStyle(ControlStyles.StandardDoubleClick, false); this.SetStyle(ControlStyles.Opaque, true); this.SetStyle(ControlStyles.ResizeRedraw, this.DesignMode); this.SetStyle(ControlStyles.Selectable, false); //this.SetStyle(ControlStyles.AllPaintingInWmPaint, false); // ??? this.colSections = new HeaderSectionCollection(this); } /// /// Clean up any resources being used. /// protected override void Dispose(bool disposing) { if ( disposing ) { if ( this.imageList != null ) { this.imageList.RecreateHandle -= new EventHandler(this.OnImageListRecreateHandle); this.imageList.Disposed -= new EventHandler(this.OnDetachImageList); this.imageList = null; } this.colSections.Clear(true); } base.Dispose( disposing ); } /// /// Helpers /// private int ExtractIndexFromNMHEADER(ref NativeHeader.NMHEADER nmh) { return nmh.iItem; } private MouseButtons ExtractMouseButtonFromNMHEADER(ref NativeHeader.NMHEADER nmh) { switch ( nmh.iButton ) { case 0: return MouseButtons.Left; case 1: return MouseButtons.Right; case 2: return MouseButtons.Middle; } return MouseButtons.None; } private void ExtractSectionDataFromNMHEADER(ref NativeHeader.NMHEADER nmh, ref NativeHeader.HDITEM2 item) { if ( nmh.pitem != IntPtr.Zero ) { item = (NativeHeader.HDITEM2)Marshal.PtrToStructure( nmh.pitem, typeof(NativeHeader.HDITEM2)); } } private static void UpdateWndImageList(ref HandleRef hrThis, ImageList imageList) { Debug.Assert( hrThis.Handle != IntPtr.Zero ); IntPtr hIL = (imageList != null) ? imageList.Handle : IntPtr.Zero; NativeHeader.SetImageList(hrThis.Handle, new HandleRef(imageList, hIL).Handle); } private static void UpdateWndBitmapMargin(ref HandleRef hrThis, int cxMargin) { Debug.Assert( hrThis.Handle != IntPtr.Zero ); NativeHeader.SetBitmapMargin(hrThis.Handle, cxMargin); } private static void UpdateWndStyle(ref HandleRef hrThis, int fNewStyle) { Debug.Assert( hrThis.Handle != IntPtr.Zero ); const int fOptions = NativeHeader.SWP_NOSIZE| NativeHeader.SWP_NOMOVE| NativeHeader.SWP_NOZORDER| NativeHeader.SWP_NOACTIVATE| NativeHeader.SWP_FRAMECHANGED; int fStyle = NativeHeader.GetWindowLong(hrThis.Handle, NativeHeader.GWL_STYLE); fStyle &= ~(NativeHeader.HDS_BUTTONS| NativeHeader.HDS_HOTTRACK| NativeHeader.HDS_FLAT| NativeHeader.HDS_DRAGDROP| NativeHeader.HDS_FULLDRAG); fStyle |= fNewStyle; NativeHeader.SetWindowLong(hrThis.Handle, NativeHeader.GWL_STYLE, fStyle); NativeHeader.SetWindowPos(hrThis.Handle, IntPtr.Zero, 0, 0, 0, 0, fOptions); } private void UpdateWndStyle() { HandleRef hrThis = new HandleRef(this, this.Handle); UpdateWndStyle(ref hrThis, this.fStyle); } /// /// Internal notifications /// protected override void OnHandleCreated(EventArgs ea) { HandleRef hrThis = new HandleRef(this, this.Handle); // Set Window Style UpdateWndStyle(ref hrThis, this.fStyle); // Set Bitmap Margin UpdateWndBitmapMargin(ref hrThis, this.cxBitmapMargin); // Set ImageList UpdateWndImageList(ref hrThis, this.imageList); // Add items for ( int i = 0; i < this.colSections.Count; i++ ) { HeaderSection item = colSections[i]; NativeHeader.HDITEM hdi; item.ComposeNativeData(i, out hdi); int nResult = NativeHeader.InsertItem(this.Handle, i, ref hdi); Debug.Assert( nResult >= 0 ); if ( nResult < 0 ) throw new InvalidOperationException(ErrMsg.FailedToInsertItem(), new Win32Exception()); } base.OnHandleCreated(ea); } protected override void OnHandleDestroyed(EventArgs ea) { // Collect item parameters from native window base.OnHandleDestroyed(ea); } protected override void OnEnabledChanged(EventArgs ea) { base.OnEnabledChanged(ea); } protected override void OnFontChanged(EventArgs ea) { base.OnFontChanged(ea); } internal void _OnSectionInserted(int index, HeaderSection item) { if ( this.IsHandleCreated ) { NativeHeader.HDITEM hdi; hdi.lpszText = null; item.ComposeNativeData(index, out hdi); int iResult = NativeHeader.InsertItem(new HandleRef(this, this.Handle).Handle, index, ref hdi); Debug.Assert( iResult == index ); if ( iResult < 0 ) throw new InvalidOperationException(ErrMsg.FailedToInsertItem(), new Win32Exception()); } } internal void _OnSectionRemoved(int iRawIndex, HeaderSection item) { if ( this.IsHandleCreated ) { HandleRef hrThis = new HandleRef(this, this.Handle); bool bResult = NativeHeader.DeleteItem(hrThis.Handle, iRawIndex); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToRemoveItem(), new Win32Exception()); } } } internal void _OnAllSectionsRemoved() { if ( this.IsHandleCreated ) { BeginUpdate(); try { HandleRef hrThis = new HandleRef(this, this.Handle); while ( NativeHeader.GetItemCount(this.Handle) != 0 ) { bool bResult = NativeHeader.DeleteItem(hrThis.Handle, 0); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToRemoveItem(), new Win32Exception()); } } } finally { EndUpdate(); } } } internal void _OnSectionChanged(int iRawIndex, HeaderSection item) { if ( this.IsHandleCreated ) { NativeHeader.HDITEM hdi; item.ComposeNativeData(-1, out hdi); HandleRef hrThis = new HandleRef(this, this.Handle); bool bResult = NativeHeader.SetItem(hrThis.Handle, iRawIndex, ref hdi); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToChangeItem(), new Win32Exception()); } } } internal void _OnSectionWidthChanged(HeaderSection item) { if ( this.IsHandleCreated ) { int iSection = this.colSections._FindSectionRawIndex(item); Debug.Assert( iSection >= 0 ); NativeHeader.HDITEM hdi = new NativeHeader.HDITEM(); hdi.mask = NativeHeader.HDI_WIDTH; hdi.cxy = item.Width; HandleRef hrThis = new HandleRef(this, this.Handle); bool bResult = NativeHeader.SetItem(hrThis.Handle, iSection, ref hdi); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToChangeItem(), new Win32Exception()); } } } internal void _OnSectionTextChanged(HeaderSection item) { if ( this.IsHandleCreated ) { int iSection = this.colSections._FindSectionRawIndex(item); Debug.Assert( iSection >= 0 ); NativeHeader.HDITEM hdi = new NativeHeader.HDITEM(); hdi.mask = NativeHeader.HDI_FORMAT|NativeHeader.HDI_TEXT; hdi.fmt = item.Format; hdi.lpszText = item.Text; HandleRef hrThis = new HandleRef(this, this.Handle); bool bResult = NativeHeader.SetItem(hrThis.Handle, iSection, ref hdi); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToChangeItem(), new Win32Exception()); } } } internal void _OnSectionImageIndexChanged(HeaderSection item) { if ( this.IsHandleCreated ) { int iSection = this.colSections._FindSectionRawIndex(item); Debug.Assert( iSection >= 0 ); NativeHeader.HDITEM hdi = new NativeHeader.HDITEM(); hdi.mask = NativeHeader.HDI_FORMAT|NativeHeader.HDI_IMAGE; hdi.fmt = item.Format; hdi.iImage = item.ImageIndex; HandleRef hrThis = new HandleRef(this, this.Handle); bool bResult = NativeHeader.SetItem(hrThis.Handle, iSection, ref hdi); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToChangeItem(), new Win32Exception()); } } } internal void _OnSectionBitmapChanged(HeaderSection item) { if ( this.IsHandleCreated ) { int iSection = this.colSections._FindSectionRawIndex(item); Debug.Assert( iSection >= 0 ); NativeHeader.HDITEM hdi = new NativeHeader.HDITEM(); hdi.mask = NativeHeader.HDI_FORMAT|NativeHeader.HDI_BITMAP; hdi.fmt = item.Format; hdi.hbm = item._GetHBitmap(); HandleRef hrThis = new HandleRef(this, this.Handle); bool bResult = NativeHeader.SetItem(hrThis.Handle, iSection, ref hdi); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToChangeItem(), new Win32Exception()); } } } internal void _OnSectionRightToLeftChanged(HeaderSection item) { if ( this.IsHandleCreated ) { int iSection = this.colSections._FindSectionRawIndex(item); Debug.Assert( iSection >= 0 ); NativeHeader.HDITEM hdi = new NativeHeader.HDITEM(); hdi.mask = NativeHeader.HDI_FORMAT; hdi.fmt = item.Format; HandleRef hrThis = new HandleRef(this, this.Handle); bool bResult = NativeHeader.SetItem(hrThis.Handle, iSection, ref hdi); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToChangeItem(), new Win32Exception()); } } } internal void _OnSectionContentAlignChanged(HeaderSection item) { if ( this.IsHandleCreated ) { int iSection = this.colSections._FindSectionRawIndex(item); Debug.Assert( iSection >= 0 ); NativeHeader.HDITEM hdi = new NativeHeader.HDITEM(); hdi.mask = NativeHeader.HDI_FORMAT; hdi.fmt = item.Format; HandleRef hrThis = new HandleRef(this, this.Handle); bool bResult = NativeHeader.SetItem(hrThis.Handle, iSection, ref hdi); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToChangeItem(), new Win32Exception()); } } } internal void _OnSectionImageAlignChanged(HeaderSection item) { if ( this.IsHandleCreated ) { int iSection = this.colSections._FindSectionRawIndex(item); Debug.Assert( iSection >= 0 ); NativeHeader.HDITEM hdi = new NativeHeader.HDITEM(); hdi.mask = NativeHeader.HDI_FORMAT; hdi.fmt = item.Format; HandleRef hrThis = new HandleRef(this, this.Handle); bool bResult = NativeHeader.SetItem(hrThis.Handle, iSection, ref hdi); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToChangeItem(), new Win32Exception()); } } } internal void _OnSectionSortMarkChanged(HeaderSection item) { if ( this.IsHandleCreated ) { int iSection = this.colSections._FindSectionRawIndex(item); Debug.Assert( iSection >= 0 ); NativeHeader.HDITEM hdi = new NativeHeader.HDITEM(); hdi.mask = NativeHeader.HDI_FORMAT; hdi.fmt = item.Format; HandleRef hrThis = new HandleRef(this, this.Handle); bool bResult = NativeHeader.SetItem(hrThis.Handle, iSection, ref hdi); Debug.Assert( bResult ); if ( !bResult ) { throw new InvalidOperationException(ErrMsg.FailedToChangeItem(), new Win32Exception()); } } } private void OnImageListRecreateHandle(object sender, EventArgs ea) { if ( IsHandleCreated ) { HandleRef hrThis = new HandleRef(this, this.Handle); UpdateWndImageList(ref hrThis, this.imageList); } } private void OnDetachImageList(object sender, EventArgs ea) { if ( sender == this.imageList ) { this.imageList = null; if ( IsHandleCreated ) { HandleRef hrThis = new HandleRef(this, this.Handle); UpdateWndImageList(ref hrThis, this.imageList); } } } /// /// Events /// [ Description("Occurs when user clicks on the section.") ] public event HeaderSectionEventHandler SectionClick; protected virtual void OnSectionClick(HeaderSectionEventArgs ea) { if ( this.SectionClick != null ) this.SectionClick(this, ea); } [ Description("Occurs when user performs double clicks on the section.") ] public event HeaderSectionEventHandler SectionDblClick; protected virtual void OnSectionDblClick(HeaderSectionEventArgs ea) { if ( this.SectionDblClick != null ) this.SectionDblClick(this, ea); } [ Description("Occurs when user performs double click on section's divider.") ] public event HeaderSectionEventHandler DividerDblClick; protected virtual void OnDividerDblClick(HeaderSectionEventArgs ea) { if ( this.DividerDblClick != null ) this.DividerDblClick(this, ea); } [ Description("Occurs when user is about to start resizing of the section.") ] public event HeaderSectionWidthConformableEventHandler BeforeSectionTrack; protected void OnBeforeSectionTrack(HeaderSectionWidthConformableEventArgs ea) { if ( this.BeforeSectionTrack != null ) { Delegate[] aHandlers = this.BeforeSectionTrack.GetInvocationList(); foreach( HeaderSectionWidthConformableEventHandler handler in aHandlers ) { try { handler(this, ea); } catch ( Exception ) { ea.Accepted = false; } if ( !ea.Accepted ) break; } } } [ Description("Occurs when user is resizing the section.") ] public event HeaderSectionWidthConformableEventHandler SectionTracking; protected void OnSectionTracking(HeaderSectionWidthConformableEventArgs ea) { if ( this.SectionTracking != null ) { Delegate[] aHandlers = this.SectionTracking.GetInvocationList(); foreach( HeaderSectionWidthConformableEventHandler handler in aHandlers ) { try { handler(this, ea); } catch ( Exception ) { ea.Accepted = false; } if ( !ea.Accepted ) break; } } } [ Description("Occurs when user has section resized.") ] public event HeaderSectionWidthEventHandler AfterSectionTrack; protected virtual void OnAfterSectionTrack(HeaderSectionWidthEventArgs ea) { if ( this.AfterSectionTrack != null ) this.AfterSectionTrack(this, ea); } [ Description("Occurs when user is about to start dragging of the " + "section to another position.") ] public event HeaderSectionOrderConformableEventHandler BeforeSectionDrag; protected void OnBeforeSectionDrag(HeaderSectionOrderConformableEventArgs ea) { if ( this.BeforeSectionDrag != null ) { Delegate[] aHandlers = this.BeforeSectionDrag.GetInvocationList(); foreach( HeaderSectionOrderConformableEventHandler handler in aHandlers ) { try { handler(this, ea); } catch ( Exception ) { ea.Accepted = false; } if ( !ea.Accepted ) break; } } } [ Description("Occurs when user has drugged the section to another position") ] public event HeaderSectionOrderConformableEventHandler AfterSectionDrag; protected virtual void OnAfterSectionDrag(HeaderSectionOrderConformableEventArgs ea) { if ( this.AfterSectionDrag != null ) { Delegate[] aHandlers = this.AfterSectionDrag.GetInvocationList(); foreach( HeaderSectionOrderConformableEventHandler handler in aHandlers ) { try { handler(this, ea); } catch ( Exception ) { ea.Accepted = false; } if ( !ea.Accepted ) break; } } } public event HeaderCustomDrawEventHandler CustomDrawSection; protected virtual void OnCustomDrawSection(HeaderCustomDrawEventArgs ea) { if ( this.CustomDrawSection != null ) { this.CustomDrawSection( this, ea ); } } /// /// Operations /// protected override Size DefaultSize { get { return new Size(168, 24); } } protected override void CreateHandle() { if ( !this.RecreatingHandle ) { InitCommonControlsHelper.Init(InitCommonControlsHelper.Classes.Header); } base.CreateHandle(); } protected override CreateParams CreateParams { get { CreateParams createParams = base.CreateParams; createParams.ClassName = NativeHeader.WC_HEADER; createParams.Style &= ~(NativeHeader.HDS_BUTTONS| NativeHeader.HDS_HOTTRACK| NativeHeader.HDS_FLAT| NativeHeader.HDS_DRAGDROP| NativeHeader.HDS_FULLDRAG); createParams.Style |= this.fStyle; return createParams; } } protected override void WndProc(ref Message msg) { switch ( msg.Msg ) { // Handle notifications case (NativeHeader.WM_NOTIFY + NativeHeader.OCM__BASE): { NativeWindowCommon.NMHDR nmhdr = (NativeWindowCommon.NMHDR)msg.GetLParam(typeof(NativeWindowCommon.NMHDR)); if ( nmhdr.code == NativeHeader.HDN_ITEMCHANGING ) { NativeHeader.NMHEADER nmh = (NativeHeader.NMHEADER)msg.GetLParam(typeof(NativeHeader.NMHEADER)); int iSection = ExtractIndexFromNMHEADER(ref nmh); HeaderSection item = this.colSections._GetSectionByRawIndex(iSection); MouseButtons enButton = ExtractMouseButtonFromNMHEADER(ref nmh); int cxWidth = 0; NativeHeader.HDITEM2 hdi = new NativeHeader.HDITEM2(); hdi.mask = 0; ExtractSectionDataFromNMHEADER(ref nmh, ref hdi); if ( (hdi.mask & NativeHeader.HDI_WIDTH) != 0 && this.FullDragSections ) { cxWidth = hdi.cxy; HeaderSectionWidthConformableEventArgs ea = new HeaderSectionWidthConformableEventArgs(item, enButton, cxWidth); OnSectionTracking(ea); msg.Result = ea.Accepted ? (IntPtr)0 : (IntPtr)1; return; } } else if ( nmhdr.code == NativeHeader.HDN_ITEMCHANGED ) { NativeHeader.NMHEADER nmh = (NativeHeader.NMHEADER)msg.GetLParam(typeof(NativeHeader.NMHEADER)); int iSection = ExtractIndexFromNMHEADER(ref nmh); HeaderSection item = this.colSections._GetSectionByRawIndex(iSection); MouseButtons enButton = ExtractMouseButtonFromNMHEADER(ref nmh); int cxWidth = 0; NativeHeader.HDITEM2 hdi = new NativeHeader.HDITEM2(); hdi.mask = 0; ExtractSectionDataFromNMHEADER(ref nmh, ref hdi); if ( (hdi.mask & NativeHeader.HDI_WIDTH) != 0 && this.FullDragSections ) { cxWidth = hdi.cxy; HeaderSectionWidthEventArgs ea = new HeaderSectionWidthEventArgs(item, enButton, cxWidth); item._SetWidth(cxWidth); OnAfterSectionTrack(ea); } } else if ( nmhdr.code == NativeHeader.HDN_ITEMCLICK ) { NativeHeader.NMHEADER nmh = (NativeHeader.NMHEADER)msg.GetLParam(typeof(NativeHeader.NMHEADER)); int iSection = ExtractIndexFromNMHEADER(ref nmh); MouseButtons enButton = ExtractMouseButtonFromNMHEADER(ref nmh); HeaderSection item = this.colSections._GetSectionByRawIndex(iSection); HeaderSectionEventArgs ea = new HeaderSectionEventArgs(item, enButton); OnSectionClick(ea); } else if ( nmhdr.code == NativeHeader.HDN_ITEMDBLCLICK ) { NativeHeader.NMHEADER nmh = (NativeHeader.NMHEADER)msg.GetLParam(typeof(NativeHeader.NMHEADER)); int iSection = ExtractIndexFromNMHEADER(ref nmh); MouseButtons enButton = ExtractMouseButtonFromNMHEADER(ref nmh); HeaderSection item = this.colSections._GetSectionByRawIndex(iSection); HeaderSectionEventArgs ea = new HeaderSectionEventArgs(item, enButton); OnSectionDblClick(ea); } else if ( nmhdr.code == NativeHeader.HDN_DIVIDERDBLCLICK ) { NativeHeader.NMHEADER nmh = (NativeHeader.NMHEADER)msg.GetLParam(typeof(NativeHeader.NMHEADER)); int iSection = ExtractIndexFromNMHEADER(ref nmh); MouseButtons enButton = ExtractMouseButtonFromNMHEADER(ref nmh); HeaderSection item = this.colSections._GetSectionByRawIndex(iSection); HeaderSectionEventArgs ea = new HeaderSectionEventArgs(item, enButton); OnDividerDblClick(ea); } else if ( nmhdr.code == NativeHeader.HDN_BEGINTRACK ) { NativeHeader.NMHEADER nmh = (NativeHeader.NMHEADER)msg.GetLParam(typeof(NativeHeader.NMHEADER)); int iSection = ExtractIndexFromNMHEADER(ref nmh); HeaderSection item = this.colSections._GetSectionByRawIndex(iSection); MouseButtons enButton = ExtractMouseButtonFromNMHEADER(ref nmh); int cxWidth = 0; NativeHeader.HDITEM2 hdi = new NativeHeader.HDITEM2(); hdi.mask = 0; ExtractSectionDataFromNMHEADER(ref nmh, ref hdi); if ( (hdi.mask & NativeHeader.HDI_WIDTH) != 0 ) { cxWidth = hdi.cxy; } HeaderSectionWidthConformableEventArgs ea = new HeaderSectionWidthConformableEventArgs(item, enButton, cxWidth); OnBeforeSectionTrack(ea); msg.Result = ea.Accepted ? (IntPtr)0 : (IntPtr)1; return; } else if ( nmhdr.code == NativeHeader.HDN_TRACK ) { NativeHeader.NMHEADER nmh = (NativeHeader.NMHEADER)msg.GetLParam(typeof(NativeHeader.NMHEADER)); int iSection = ExtractIndexFromNMHEADER(ref nmh); HeaderSection item = this.colSections._GetSectionByRawIndex(iSection); MouseButtons enButton = ExtractMouseButtonFromNMHEADER(ref nmh); int cxWidth = 0; NativeHeader.HDITEM2 hdi = new NativeHeader.HDITEM2(); hdi.mask = 0; ExtractSectionDataFromNMHEADER(ref nmh, ref hdi); if ( (hdi.mask & NativeHeader.HDI_WIDTH) != 0 ) { cxWidth = hdi.cxy; } HeaderSectionWidthConformableEventArgs ea = new HeaderSectionWidthConformableEventArgs(item, enButton, cxWidth); OnSectionTracking(ea); msg.Result = ea.Accepted ? (IntPtr)0 : (IntPtr)1; return; } else if ( nmhdr.code == NativeHeader.HDN_ENDTRACK ) { NativeHeader.NMHEADER nmh = (NativeHeader.NMHEADER)msg.GetLParam(typeof(NativeHeader.NMHEADER)); int iSection = ExtractIndexFromNMHEADER(ref nmh); HeaderSection item = this.colSections._GetSectionByRawIndex(iSection); MouseButtons enButton = ExtractMouseButtonFromNMHEADER(ref nmh); int cxWidth = 0; NativeHeader.HDITEM2 hdi = new NativeHeader.HDITEM2(); hdi.mask = 0; ExtractSectionDataFromNMHEADER(ref nmh, ref hdi); if ( (hdi.mask & NativeHeader.HDI_WIDTH) != 0 ) { cxWidth = hdi.cxy; } HeaderSectionWidthEventArgs ea = new HeaderSectionWidthEventArgs(item, enButton, cxWidth); item._SetWidth(cxWidth); OnAfterSectionTrack(ea); } else if ( nmhdr.code == NativeHeader.HDN_BEGINDRAG ) { NativeHeader.NMHEADER nmh = (NativeHeader.NMHEADER)msg.GetLParam(typeof(NativeHeader.NMHEADER)); int iSection = ExtractIndexFromNMHEADER(ref nmh); if ( iSection < 0 ) { return; } HeaderSection item = this.colSections._GetSectionByRawIndex(iSection); MouseButtons enButton = MouseButtons.Left; // Microsoft bugfix // MouseButtons enButton = ExtractMouseButtonFromNMHEADER(ref nmh); int iOrder = this.colSections.IndexOf(item); HeaderSectionOrderConformableEventArgs ea = new HeaderSectionOrderConformableEventArgs(item, enButton, iOrder); OnBeforeSectionDrag(ea); msg.Result = ea.Accepted ? (IntPtr)0 : (IntPtr)1; return; } else if ( nmhdr.code == NativeHeader.HDN_ENDDRAG ) { NativeHeader.NMHEADER nmh = (NativeHeader.NMHEADER)msg.GetLParam(typeof(NativeHeader.NMHEADER)); int iSection = ExtractIndexFromNMHEADER(ref nmh); HeaderSection item = this.colSections._GetSectionByRawIndex(iSection); MouseButtons enButton = ExtractMouseButtonFromNMHEADER(ref nmh); NativeHeader.HDITEM2 hdi = new NativeHeader.HDITEM2(); hdi.mask = 0; ExtractSectionDataFromNMHEADER(ref nmh, ref hdi); Debug.Assert( (hdi.mask & NativeHeader.HDI_ORDER) != 0 ); int iNewOrder = hdi.iOrder; bool accepted = HandleEndDrag( item, enButton, iNewOrder ); msg.Result = accepted ? (IntPtr)0 : (IntPtr)1; return; } else if ( nmhdr.code == NativeHeader.NM_CUSTOMDRAW ) { NativeHeader.NMCUSTOMDRAW customDraw = (NativeHeader.NMCUSTOMDRAW)msg.GetLParam(typeof(NativeHeader.NMCUSTOMDRAW)); switch( customDraw.dwDrawStage ) { case NativeHeader.CDDS_PREPAINT: msg.Result = (IntPtr) NativeHeader.CDRF_NOTIFYITEMDRAW; return; case NativeHeader.CDDS_ITEMPREPAINT: msg.Result = (IntPtr) NativeHeader.CDRF_NOTIFYPOSTPAINT; return; case NativeHeader.CDDS_ITEMPOSTPAINT: HeaderSection section = this.colSections._GetSectionByRawIndex(customDraw.dwItemSpec); Rectangle rc = Rectangle.FromLTRB( customDraw.rcLeft, customDraw.rcTop, customDraw.rcRight, customDraw.rcBottom ); HeaderCustomDrawEventArgs ea = new HeaderCustomDrawEventArgs( section, customDraw.hdc, rc ); OnCustomDrawSection( ea ); msg.Result = (IntPtr) NativeHeader.CDRF_DODEFAULT; return; } } // else if ( nmhdr.code == NativeHeader.HDN_GETDISPINFO ) // { // } // else if ( nmhdr.code == NativeHeader.HDN_FILTERCHANGE ) // { // } // else if ( nmhdr.code == NativeHeader.HDN_FILTERBTNCLICK ) // { // } } break; case NativeHeader.WM_SETCURSOR: DefWndProc(ref msg); return; } base.WndProc(ref msg); } public bool HandleEndDrag( HeaderSection item, MouseButtons enButton, int iNewOrder ) { HeaderSectionOrderConformableEventArgs ea = new HeaderSectionOrderConformableEventArgs(item, enButton, iNewOrder); OnAfterSectionDrag(ea); // Update orders if ( ea.Accepted ) { int iOldOrder = this.colSections.IndexOf(item); if ( iOldOrder >= 0 ) { this.colSections._Move(iOldOrder, iNewOrder); } } return ea.Accepted; } /// /// Operations /// public void BeginUpdate() { if ( this.IsHandleCreated ) { HandleRef hrThis = new HandleRef(this, this.Handle); NativeWindowCommon.SendMessage(hrThis.Handle, NativeWindowCommon.WM_SETREDRAW, 0, 0); } } public void EndUpdate() { if ( this.IsHandleCreated ) { HandleRef hrThis = new HandleRef(this, this.Handle); NativeWindowCommon.SendMessage(hrThis.Handle, NativeWindowCommon.WM_SETREDRAW, 1, 0); } } public Rectangle GetSectionRect(HeaderSection item) { int iSection = this.colSections._FindSectionRawIndex(item); Debug.Assert( iSection >= 0 ); HandleRef hrThis = new HandleRef(this, this.Handle); NativeHeader.RECT rc; bool bResult = NativeHeader.GetItemRect(hrThis.Handle, iSection, out rc); Debug.Assert( bResult ); if ( !bResult ) throw new Win32Exception(); return Rectangle.FromLTRB(rc.left, rc.top, rc.right, rc.bottom); } public void CalculateLayout(Rectangle rectArea, out Rectangle rectPosition) { NativeHeader.HDLAYOUT hdl = new NativeHeader.HDLAYOUT(); hdl.prc = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeHeader.RECT))); hdl.pwpos = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeHeader.WINDOWPOS))); try { HandleRef hrThis = new HandleRef(this, this.Handle); NativeHeader.RECT rc = new NativeHeader.RECT(); rc.left = rectArea.Left; rc.top = rectArea.Top; rc.right = rectArea.Right; rc.bottom = rectArea.Bottom; Marshal.StructureToPtr(rc, hdl.prc, false); bool bResult = NativeHeader.Layout(hrThis.Handle, ref hdl); Debug.Assert( bResult ); if ( !bResult ) throw new Win32Exception(); NativeHeader.WINDOWPOS wp = (NativeHeader.WINDOWPOS)Marshal.PtrToStructure(hdl.pwpos, typeof(NativeHeader.WINDOWPOS)); rectPosition = new Rectangle(wp.x, wp.y, wp.cx, wp.cy); } finally { if ( hdl.prc != IntPtr.Zero ) Marshal.FreeHGlobal(hdl.prc); if ( hdl.pwpos != IntPtr.Zero ) Marshal.FreeHGlobal(hdl.pwpos); } } public int SetHotDivider(int x, int y) { HandleRef hrThis = new HandleRef(this, this.Handle); return NativeHeader.SetHotDivider(hrThis.Handle, true, (y << 16) | x); } public int SetHotDivider(int iDevider) { HandleRef hrThis = new HandleRef(this, this.Handle); return NativeHeader.SetHotDivider(hrThis.Handle, false, iDevider); } public HitTestInfo HitTest(int x, int y) { return HitTest(new Point(x, y)); } public HitTestInfo HitTest(Point point) { HandleRef hrThis = new HandleRef(this, this.Handle); Point pointClient = PointToClient(point); NativeHeader.HDHITTESTINFO htiRaw = new NativeHeader.HDHITTESTINFO(); htiRaw.pt.x = pointClient.X; htiRaw.pt.y = pointClient.Y; htiRaw.iItem = -1; htiRaw.flags = 0; NativeHeader.HitTest(hrThis.Handle, ref htiRaw); HitTestInfo hti = new HitTestInfo(); hti.fArea = (HitTestArea)htiRaw.flags; if ( htiRaw.iItem >= 0 ) { hti.section = this.colSections._GetSectionByRawIndex(htiRaw.iItem); } return hti; } } #endregion // Header control }