| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
-
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Drawing;
- using System.Drawing.Design;
- using System.Drawing.Drawing2D;
- using System.Runtime;
- using System.Windows.Forms;
- namespace Dongke.WinForm.Controls
- {
- internal partial class trvTreeView : TreeView, IDKControl, IAsyncControl
- {
- #region 构造函数
- public trvTreeView()
- {
- InitializeComponent();
- }
- public trvTreeView(IContainer container)
- {
- container.Add(this);
- InitializeComponent();
- }
- #endregion
- #region 成员变量
- private int indexUnchecked;
- private int indexChecked;
- private int indexIndeterminate;
- private bool useCustomImages;
- private bool useShowImage;
- #endregion
- #region 属性
- [Category("CheckState")]
- [DefaultValue(true)]
- public bool UseShowImage
- {
- get { return this.useShowImage; }
- set {this.useShowImage = value; }
- }
- [Category("CheckState")]
- [DefaultValue(false)]
- public bool UseCustomImages
- {
- get { return this.useCustomImages; }
- set { this.useCustomImages = value; }
- }
- [Category("CheckState")]
- [TypeConverter(typeof(TreeViewImageIndexConverter))]
- [Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
- [DefaultValue(0)]
- public int CheckedImageIndex
- {
- get
- {
- if (base.ImageList == null)
- return -1;
- if (this.indexChecked >= this.ImageList.Images.Count)
- return Math.Max(0, this.ImageList.Images.Count - 1);
- return this.indexChecked;
- }
- set
- {
- if (value == -1)
- value = 0;
- if (value < 0)
- throw new ArgumentException(string.Format("Index out of bounds! ({0}) index must be equal to or greater then {1}.", value.ToString(), "0"));
- if (this.indexChecked != value)
- {
- this.indexChecked = value;
- if (base.IsHandleCreated)
- base.RecreateHandle();
- }
- }
- }
- [Category("CheckState")]
- [TypeConverter(typeof(TreeViewImageIndexConverter))]
- [Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
- [DefaultValue(0)]
- public int UncheckedImageIndex
- {
- get
- {
- if (base.ImageList == null)
- return -1;
- if (this.indexUnchecked >= this.ImageList.Images.Count)
- return Math.Max(0, this.ImageList.Images.Count - 1);
- return this.indexUnchecked;
- }
- set
- {
- if (value == -1)
- value = 0;
- if (value < 0)
- throw new ArgumentException(string.Format("Index out of bounds! ({0}) index must be equal to or greater then {1}.", value.ToString(), "0"));
- if (this.indexUnchecked != value)
- {
- this.indexUnchecked = value;
- if (base.IsHandleCreated)
- base.RecreateHandle();
- }
- }
- }
- [Category("CheckState")]
- [TypeConverter(typeof(TreeViewImageIndexConverter))]
- [Editor("System.Windows.Forms.Design.ImageIndexEditor, System.Design, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
- [DefaultValue(0)]
- public int IndeterminateImageIndex
- {
- get
- {
- if (base.ImageList == null)
- return -1;
- if (this.indexIndeterminate >= this.ImageList.Images.Count)
- return Math.Max(0, this.ImageList.Images.Count - 1);
- return this.indexIndeterminate;
- }
- set
- {
- if (value == -1)
- value = 0;
- if (value < 0)
- throw new ArgumentException(string.Format("Index out of bounds! ({0}) index must be equal to or greater then {1}.", value.ToString(), "0"));
- if (this.indexIndeterminate != value)
- {
- this.indexIndeterminate = value;
- if (base.IsHandleCreated)
- base.RecreateHandle();
- }
- }
- }
- #endregion
- #region 事件
- protected override void OnAfterCheck(TreeViewEventArgs e)
- {
- base.OnAfterCheck(e);
- TreeNode node = e.Node;
- if (node != null)
- {
- TriStateTreeNode clickedNode = node as TriStateTreeNode;
- if (clickedNode != null)
- {
- if (clickedNode.CheckboxVisible)
- {
- ToggleNodeState(clickedNode);
- }
- }
- }
- }
- /// <summary>
- /// Paints the node specified.
- /// </summary>
- /// <param name="node"></param>
- /// <param name="gx"></param>
- private void PaintTreeNode(TriStateTreeNode node, Graphics gx)
- {
- if (this.CheckBoxes)
- {
- // calculate boundaries
- Rectangle ncRect = new Rectangle(node.Bounds.X - 35, node.Bounds.Y, 15, 15);
-
- // make sure the default checkboxes are gone
- ClearCheckbox(ncRect, gx);
- // draw lines, if we are supposed to
- if (this.ShowLines)
- {
- DrawNodeLines(node, ncRect, gx);
- }
- if (node.CheckboxVisible)
- {
- // now draw the checkboxes
- switch (node.CheckState)
- {
- case CheckState.Unchecked: // Normal
- DrawCheckbox(ncRect, gx, ButtonState.Normal | ButtonState.Flat);
- break;
- case CheckState.Checked: // Checked
- DrawCheckbox(ncRect, gx, ButtonState.Checked | ButtonState.Flat);
- break;
- case CheckState.Indeterminate: // Pushed
- DrawCheckbox(ncRect, gx, ButtonState.Pushed | ButtonState.Flat);
- break;
- }
- }
- }
- }
- /// <summary>
- /// Deletes the default checkboxes which are drawn when the treeview.Checkboxes property
- /// is set tot true.
- /// </summary>
- /// <param name="bounds"></param>
- /// <param name="gx"></param>
- private void ClearCheckbox(Rectangle bounds, Graphics gx)
- {
- // make sure the default checkboxes are gone.
- using (Brush brush = new SolidBrush(this.BackColor))
- {
- gx.FillRectangle(brush, bounds);
- }
- }
- /// <summary>
- /// Draws thee node lines before the checkboxes are drawn
- /// </summary>
- /// <param name="gx">Graphics context</param>
- private void DrawNodeLines(TriStateTreeNode node, Rectangle bounds, Graphics gx)
- {
- // determine type of line to draw
- NodeLineType lineType = node.NodeLineType;
- if (lineType == NodeLineType.None) { return; }
- using (Pen pen = new Pen(SystemColors.ControlDark, 1))
- {
- pen.DashStyle = DashStyle.Dot;
- gx.DrawLine(pen, new Point(bounds.X, bounds.Y + 8), new Point(bounds.X + 15, bounds.Y + 8));
- if (lineType == NodeLineType.WithChildren && node.IsExpanded)
- {
- gx.DrawLine(pen, new Point(bounds.X + 8, bounds.Y + 8), new Point(bounds.X + 8, bounds.Y + 16));
- }
- }
- }
- /// <summary>
- /// Draws a checkbox in the desired state and style
- /// </summary>
- /// <param name="bounds">boundaries of the checkbox</param>
- /// <param name="gx">graphics context object</param>
- /// <param name="buttonState">state to draw the checkbox in</param>
- private void DrawCheckbox(Rectangle bounds, Graphics gx, ButtonState buttonState)
- {
- // get the right image index
- //System.Windows.Forms.VisualStyles.CheckBoxState imageIndexss = System.Windows.Forms.VisualStyles.CheckBoxState.MixedPressed;
- //if ((buttonState & ButtonState.Normal) == ButtonState.Normal)
- // imageIndex = this.indexUnchecked;
- //if ((buttonState & ButtonState.Checked) == ButtonState.Checked)
- // imageIndex = this.indexChecked;
- //if ((buttonState & ButtonState.Pushed) == ButtonState.Pushed)
- // imageIndex = this.indexIndeterminate;
- // if we don't have custom images, or no imagelist, draw default images
- if (!this.useCustomImages || (this.useCustomImages && null == this.ImageList))
- {
- //ControlPaint.DrawMixedCheckBox(gx, bounds, buttonState);
- CheckBoxRenderer.DrawCheckBox(gx, bounds.Location, System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal);
- return;
- }
- // get the right image index
- int imageIndex = -1;
- if ((buttonState & ButtonState.Normal) == ButtonState.Normal)
- imageIndex = this.indexUnchecked;
- if ((buttonState & ButtonState.Checked) == ButtonState.Checked)
- imageIndex = this.indexChecked;
- if ((buttonState & ButtonState.Pushed) == ButtonState.Pushed)
- imageIndex = this.indexIndeterminate;
-
- if (imageIndex > -1 && imageIndex < this.ImageList.Images.Count)
- {
- // index is valid so draw the image
- this.ImageList.Draw(gx, bounds.X, bounds.Y, bounds.Width + 1, bounds.Height + 1, imageIndex);
- }
- else
- {
- // index is not valid so draw default image
- ControlPaint.DrawMixedCheckBox(gx, bounds, buttonState);
- }
- }
- /// <summary>
- /// Ovveride the WindowProcedure in order to intercept the itemdraw event
- /// </summary>
- /// <param name="m"></param>
- protected override void WndProc(ref Message m)
- {
- const int WM_NOTIFY = 0x4E;
- int iResult = 0;
- bool bHandled = false;
- if (m.Msg == (0x2000 | WM_NOTIFY))
- {
- if (m.WParam.Equals(this.Handle))
- {
- iResult = HandleNotify(m);
- m.Result = new IntPtr(iResult);
- bHandled = (iResult != 0);
- }
- }
- if (!bHandled)
- base.WndProc(ref m);
- }
- #endregion
- #region 私有方法
- /// <summary>
- /// Toggles node state between checked & unchecked
- /// </summary>
- /// <param name="node"></param>
- private void ToggleNodeState(TriStateTreeNode node)
- {
- // no need to toggle state for non-existing node ( or non-tristatetreenode! )
- if (null == node) return;
- // toggle state
- CheckState nextState;
- switch (node.CheckState)
- {
- case CheckState.Unchecked:
- nextState = CheckState.Checked;
- break;
- default:
- nextState = CheckState.Unchecked;
- break;
- }
- // notify the treeview that an update is about to take place
- BeginUpdate();
- // update the node state, and dependend nodes
- node.SetCheckedState(nextState);
- // force a redraw
- EndUpdate();
- }
- private int HandleNotify(Message msg)
- {
- const int NM_FIRST = 0;
- const int NM_CUSTOMDRAW = NM_FIRST - 12;
- // Drawstage
- const int CDDS_PREPAINT = 0x1;
- const int CDDS_POSTPAINT = 0x2;
- const int CDDS_ITEM = 0x10000;
- const int CDDS_ITEMPREPAINT = (CDDS_ITEM | CDDS_PREPAINT);
- const int CDDS_ITEMPOSTPAINT = (CDDS_ITEM | CDDS_POSTPAINT);
- // Custom draw return flags
- const int CDRF_DODEFAULT = 0x0;
- const int CDRF_NOTIFYPOSTPAINT = 0x10;
- const int CDRF_NOTIFYITEMDRAW = 0x20;
- NMHDR tNMHDR;
- NMTVCUSTOMDRAW tNMTVCUSTOMDRAW;
- int iResult = 0;
- object obj;
- TreeNode node;
- TriStateTreeNode tsNode;
- try
- {
- if (!msg.LParam.Equals(IntPtr.Zero))
- {
- obj = msg.GetLParam(typeof(NMHDR));
- if (obj is NMHDR)
- {
- tNMHDR = (NMHDR)obj;
- if (tNMHDR.code == NM_CUSTOMDRAW)
- {
- obj = msg.GetLParam(typeof(NMTVCUSTOMDRAW));
- if (obj is NMTVCUSTOMDRAW)
- {
- tNMTVCUSTOMDRAW = (NMTVCUSTOMDRAW)obj;
- switch (tNMTVCUSTOMDRAW.nmcd.dwDrawStage)
- {
- case CDDS_PREPAINT:
- iResult = CDRF_NOTIFYITEMDRAW;
- break;
- case CDDS_ITEMPREPAINT:
- iResult = CDRF_NOTIFYPOSTPAINT;
- break;
- case CDDS_ITEMPOSTPAINT:
- node = TreeNode.FromHandle(this, tNMTVCUSTOMDRAW.nmcd.dwItemSpec);
- tsNode = node as TriStateTreeNode;
- if (tsNode != null)
- {
- Graphics graph = Graphics.FromHdc(tNMTVCUSTOMDRAW.nmcd.hdc);
- PaintTreeNode(tsNode, graph);
- graph.Dispose();
- }
- iResult = CDRF_DODEFAULT;
- break;
- }
- }
- }
- }
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- return iResult;
- }
- #endregion
- #region 结构
- private struct RECT
- {
- internal int left;
- internal int top;
- internal int right;
- internal int bottom;
- }
- private struct NMHDR
- {
- internal IntPtr hwndFrom;
- internal IntPtr idFrom;
- internal int code;
- }
- private struct NMCUSTOMDRAW
- {
- internal NMHDR hdr;
- internal int dwDrawStage;
- internal IntPtr hdc;
- internal RECT rc;
- internal IntPtr dwItemSpec;
- internal int uItemState;
- internal IntPtr lItemlParam;
- }
- private struct NMTVCUSTOMDRAW
- {
- internal NMCUSTOMDRAW nmcd;
- internal int clrText;
- internal int clrTextBk;
- internal int iLevel;
- }
- #endregion
- #region IAsyncControl 成员
- #region 成员变量
- /// <summary>
- /// 异步处理开始时,控件状态
- /// </summary>
- private bool _asyncBeginStatus = false;
- private bool _asyncBeginFocused = false;
- #endregion
- #region 公有方法
- /// <summary>
- /// 开始异步处理
- /// </summary>
- /// <param name="doFocus">是否处理焦点</param>
- public virtual void BeginAsync(ref bool doFocus)
- {
- if (doFocus && this.Focused)
- {
- this._asyncBeginFocused = true;
- doFocus = false;
- }
- this._asyncBeginStatus = this.Enabled;
- this.Enabled = false;
- }
- /// <summary>
- /// 结束异步处理
- /// </summary>
- public virtual void EndAsync()
- {
- this.Enabled = this._asyncBeginStatus;
- if (this._asyncBeginFocused)
- {
- this.Focus();
- }
- }
- #endregion
- #endregion
- }
- }
|