Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / WinForms / Managed / System / WinForms / UpDownBase.cs / 1 / UpDownBase.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Windows.Forms { using System.Runtime.Serialization.Formatters; using System.Threading; using System.Runtime.Remoting; using System.Runtime.InteropServices; using System.ComponentModel; using System.Diagnostics; using System; using System.Security.Permissions; using System.Windows.Forms.VisualStyles; using System.Drawing; using Microsoft.Win32; ////// /// [ ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch), Designer("System.Windows.Forms.Design.UpDownBaseDesigner, " + AssemblyRef.SystemDesign), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1012:AbstractTypesShouldNotHaveConstructors") // Shipped in Everett ] public abstract class UpDownBase : ContainerControl { private const int DefaultWheelScrollLinesPerPage = 1; private const int DefaultButtonsWidth = 16; private const int DefaultControlWidth = 120; private const int ThemedBorderWidth = 1; // width of custom border we draw when themed private const BorderStyle DefaultBorderStyle = BorderStyle.Fixed3D; private static readonly bool DefaultInterceptArrowKeys = true; private const LeftRightAlignment DefaultUpDownAlign = LeftRightAlignment.Right; private const int DefaultTimerInterval = 500; //////////////////////////////////////////////////////////////////////// // Member variables // //////////////////////////////////////////////////////////////////////// // Child controls internal UpDownEdit upDownEdit; // See nested class at end of this file internal UpDownButtons upDownButtons; // See nested class at end of this file // Intercept arrow keys? private bool interceptArrowKeys = DefaultInterceptArrowKeys; // If true, the updown buttons will be drawn on the left-hand side of the control. private LeftRightAlignment upDownAlign = DefaultUpDownAlign; // userEdit is true when the text of the control has been changed, // and the internal value of the control has not yet been updated. // We do not always want to keep the internal value up-to-date, // hence this variable. private bool userEdit = false; ///Implements the basic /// functionality required by an up-down control. ////// /// The current border for this edit control. /// private BorderStyle borderStyle = DefaultBorderStyle; // Mouse wheel movement private int wheelDelta = 0; // Indicates if the edit text is being changed private bool changingText = false; // Indicates whether we have doubleClicked private bool doubleClickFired = false; ////// /// public UpDownBase() { upDownButtons = new UpDownButtons(this); upDownEdit = new UpDownEdit(this); upDownEdit.BorderStyle = BorderStyle.None; upDownEdit.AutoSize = false; upDownEdit.KeyDown += new KeyEventHandler(this.OnTextBoxKeyDown); upDownEdit.KeyPress += new KeyPressEventHandler(this.OnTextBoxKeyPress); upDownEdit.TextChanged += new EventHandler(this.OnTextBoxTextChanged); upDownEdit.LostFocus += new EventHandler(this.OnTextBoxLostFocus); upDownEdit.Resize += new EventHandler(this.OnTextBoxResize); upDownButtons.TabStop = false; upDownButtons.Size = new Size(DefaultButtonsWidth, PreferredHeight); upDownButtons.UpDown += new UpDownEventHandler(this.OnUpDown); Controls.AddRange(new Control[] { upDownButtons, upDownEdit} ); SetStyle(ControlStyles.Opaque | ControlStyles.FixedHeight | ControlStyles.ResizeRedraw, true); SetStyle(ControlStyles.StandardClick, false); SetStyle(ControlStyles.UseTextForAccessibility, false); } //////////////////////////////////////////////////////////////////////// // Properties // //////////////////////////////////////////////////////////////////////// // AutoScroll is not relevant to an UpDownBase ////// Initializes a new instance of the ////// class. /// /// /// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override bool AutoScroll { get { return false; } set { // Don't allow AutoScroll to be set to anything } } // AutoScrollMargin is not relevant to an UpDownBase ////// /// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] new public Size AutoScrollMargin { get { return base.AutoScrollMargin; } set { base.AutoScrollMargin = value; } } // AutoScrollMinSize is not relevant to an UpDownBase ////// /// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] new public Size AutoScrollMinSize { get { return base.AutoScrollMinSize; } set { base.AutoScrollMinSize = value; } } ////// /// [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public override bool AutoSize { get { return base.AutoSize; } set { base.AutoSize = value; } } ///Override to re-expose AutoSize. ///[SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnAutoSizeChangedDescr)] [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)] new public event EventHandler AutoSizeChanged { add { base.AutoSizeChanged += value; } remove { base.AutoSizeChanged -= value; } } /// /// /// /// public override Color BackColor { get { return upDownEdit.BackColor; } set { base.BackColor = value; // Don't remove this or you will break serialization. See VSWhidbey #517574 upDownEdit.BackColor = value; Invalidate(); // VSWhidbey #335074 } } ////// Gets or sets the background color for the /// text box portion of the up-down control. /// ////// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override Image BackgroundImage { get { return base.BackgroundImage; } set { base.BackgroundImage = value; } } ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public event EventHandler BackgroundImageChanged { add { base.BackgroundImageChanged += value; } remove { base.BackgroundImageChanged -= value; } } /// /// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override ImageLayout BackgroundImageLayout { get { return base.BackgroundImageLayout; } set { base.BackgroundImageLayout = value; } } ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public event EventHandler BackgroundImageLayoutChanged { add { base.BackgroundImageLayoutChanged += value; } remove { base.BackgroundImageLayoutChanged -= value; } } /// /// /// [ SRCategory(SR.CatAppearance), DefaultValue(BorderStyle.Fixed3D), DispId(NativeMethods.ActiveX.DISPID_BORDERSTYLE), SRDescription(SR.UpDownBaseBorderStyleDescr) ] public BorderStyle BorderStyle { get { return borderStyle; } set { //valid values are 0x0 to 0x2 if (!ClientUtils.IsEnumValid(value, (int)value, (int)BorderStyle.None, (int)BorderStyle.Fixed3D)) { throw new InvalidEnumArgumentException("value", (int)value, typeof(BorderStyle)); } if (borderStyle != value) { borderStyle = value; RecreateHandle(); } } } ////// Gets or sets the border style for /// the up-down control. /// ////// /// protected bool ChangingText { get { return changingText; } set { changingText = value; } } ////// Gets or sets a value indicating whether the text /// property is being changed internally by its parent class. /// ////// /// /// public override ContextMenu ContextMenu { get { return base.ContextMenu; } set { base.ContextMenu = value; this.upDownEdit.ContextMenu = value; } } public override ContextMenuStrip ContextMenuStrip { get { return base.ContextMenuStrip; } set { base.ContextMenuStrip = value; this.upDownEdit.ContextMenuStrip = value; } } ////// /// /// protected override CreateParams CreateParams { [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] get { CreateParams cp = base.CreateParams; cp.Style &= (~NativeMethods.WS_BORDER); if (!Application.RenderWithVisualStyles) { switch (borderStyle) { case BorderStyle.Fixed3D: cp.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE; break; case BorderStyle.FixedSingle: cp.Style |= NativeMethods.WS_BORDER; break; } } return cp; } } ////// Returns the parameters needed to create the handle. Inheriting classes /// can override this to provide extra functionality. They should not, /// however, forget to call base.getCreateParams() first to get the struct /// filled up with the basic info. /// ////// /// Deriving classes can override this to configure a default size for their control. /// This is more efficient than setting the size in the control's constructor. /// protected override Size DefaultSize { get { return new Size(DefaultControlWidth, PreferredHeight); } } // DockPadding is not relevant to UpDownBase ////// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] new public DockPaddingEdges DockPadding { get { return base.DockPadding; } } ////// /// Returns true if this control has focus. /// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.ControlFocusedDescr) ] public override bool Focused { get { return upDownEdit.Focused; } } ////// /// /// public override Color ForeColor { get { return upDownEdit.ForeColor; } set { base.ForeColor = value; upDownEdit.ForeColor = value; } } ////// Indicates the foreground color for the control. /// ////// /// [ SRCategory(SR.CatBehavior), DefaultValue(true), SRDescription(SR.UpDownBaseInterceptArrowKeysDescr) ] public bool InterceptArrowKeys { get { return interceptArrowKeys; } set { interceptArrowKeys = value; } } ////// Gets or sets a value indicating whether /// the user can use the UP /// ARROW and DOWN ARROW keys to select values. /// ///public override Size MaximumSize { get { return base.MaximumSize; } set { base.MaximumSize = new Size(value.Width, 0); } } /// public override Size MinimumSize { get { return base.MinimumSize; } set { base.MinimumSize = new Size(value.Width, 0); } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler MouseEnter { add { base.MouseEnter += value; } remove { base.MouseEnter -= value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler MouseLeave { add { base.MouseLeave += value; } remove { base.MouseLeave -= value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler MouseHover { add { base.MouseHover += value; } remove { base.MouseHover -= value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event MouseEventHandler MouseMove { add { base.MouseMove += value; } remove { base.MouseMove -= value; } } /// /// /// [ SRCategory(SR.CatLayout), Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.UpDownBasePreferredHeightDescr) ] public int PreferredHeight { get { int height = FontHeight; // Adjust for the border style if (borderStyle != BorderStyle.None) { height += SystemInformation.BorderSize.Height * 4 + 3; } else { height += 3; } return height; } } ////// Gets the height of /// the up-down control. /// ////// /// [ SRCategory(SR.CatBehavior), DefaultValue(false), SRDescription(SR.UpDownBaseReadOnlyDescr) ] public bool ReadOnly { get { return upDownEdit.ReadOnly; } set { upDownEdit.ReadOnly = value; } } ////// Gets or sets /// a /// value /// indicating whether the text may only be changed by the /// use /// of the up or down buttons. /// ////// /// [ Localizable(true) ] public override string Text { get { return upDownEdit.Text; } set { upDownEdit.Text = value; // The text changed event will at this point be triggered. // After returning, the value of UserEdit will reflect // whether or not the current upDownEditbox text is in [....] // with any internally stored values. If UserEdit is true, // we must validate the text the user typed or set. ChangingText = false; // Details: Usually, the code in the Text changed event handler // sets ChangingText back to false. // If the text hasn't actually changed though, the event handler // never fires. ChangingText should always be false on exit from // this property. if (UserEdit) { ValidateEditText(); } } } ////// Gets or sets the text /// displayed in the up-down control. /// ////// /// [ Localizable(true), SRCategory(SR.CatAppearance), DefaultValue(HorizontalAlignment.Left), SRDescription(SR.UpDownBaseTextAlignDescr) ] public HorizontalAlignment TextAlign { get { return upDownEdit.TextAlign; } set { //valid values are 0x0 to 0x2 if (!ClientUtils.IsEnumValid(value, (int)value, (int)HorizontalAlignment.Left, (int)HorizontalAlignment.Center)) { throw new InvalidEnumArgumentException("value", (int)value, typeof(HorizontalAlignment)); } upDownEdit.TextAlign = value; } } internal TextBox TextBox { get { return upDownEdit; } } ////// Gets or /// sets the alignment of the text in the up-down /// control. /// ////// /// [ Localizable(true), SRCategory(SR.CatAppearance), DefaultValue(LeftRightAlignment.Right), SRDescription(SR.UpDownBaseAlignmentDescr) ] public LeftRightAlignment UpDownAlign { get { return upDownAlign; } set { //valid values are 0x0 to 0x1 if (!ClientUtils.IsEnumValid(value, (int)value, (int)LeftRightAlignment.Left, (int)LeftRightAlignment.Right)) { throw new InvalidEnumArgumentException("value", (int)value, typeof(LeftRightAlignment)); } if (upDownAlign != value) { upDownAlign = value; PositionControls(); Invalidate(); } } } internal UpDownButtons UpDownButtonsInternal { get { return upDownButtons; } } ////// Gets /// or sets the /// alignment /// of the up and down buttons on the up-down control. /// ////// /// protected bool UserEdit { get { return userEdit; } set { userEdit = value; } } //////////////////////////////////////////////////////////////////////// // Methods // //////////////////////////////////////////////////////////////////////// ////// Gets /// or sets a value indicating whether a value has been entered by the /// user. /// ////// /// public abstract void DownButton(); // GetPreferredSize and SetBoundsCore call this method to allow controls to self impose // constraints on their size. internal override Rectangle ApplyBoundsConstraints(int suggestedX, int suggestedY, int proposedWidth, int proposedHeight) { return base.ApplyBoundsConstraints(suggestedX,suggestedY, proposedWidth, PreferredHeight); } ////// When overridden in a derived class, handles the pressing of the down button /// on the up-down control. /// ////// /// /// protected virtual void OnChanged(object source, EventArgs e) { } ///When overridden in a derived class, raises the Changed event. /// event. ////// /// /// protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); PositionControls(); SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(this.UserPreferenceChanged); } ////// Initialize the updown. Adds the upDownEdit and updown buttons. /// ////// /// /// protected override void OnHandleDestroyed(EventArgs e) { SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(this.UserPreferenceChanged); base.OnHandleDestroyed(e); } ////// Tear down the updown. /// ////// /// Handles painting the buttons on the control. /// /// protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Rectangle editBounds = upDownEdit.Bounds; if (Application.RenderWithVisualStyles) { if (borderStyle != BorderStyle.None) { Rectangle bounds = ClientRectangle; Rectangle clipBounds = e.ClipRectangle; //Draw a themed textbox-like border, which is what the spin control does VisualStyleRenderer vsr = new VisualStyleRenderer(VisualStyleElement.TextBox.TextEdit.Normal); int border = ThemedBorderWidth; Rectangle clipLeft = new Rectangle(bounds.Left, bounds.Top, border, bounds.Height); Rectangle clipTop = new Rectangle(bounds.Left, bounds.Top, bounds.Width, border); Rectangle clipRight = new Rectangle(bounds.Right - border, bounds.Top, border, bounds.Height); Rectangle clipBottom = new Rectangle(bounds.Left, bounds.Bottom - border, bounds.Width, border); clipLeft.Intersect(clipBounds); clipTop.Intersect(clipBounds); clipRight.Intersect(clipBounds); clipBottom.Intersect(clipBounds); vsr.DrawBackground(e.Graphics, bounds, clipLeft); vsr.DrawBackground(e.Graphics, bounds, clipTop); vsr.DrawBackground(e.Graphics, bounds, clipRight); vsr.DrawBackground(e.Graphics, bounds, clipBottom); // Draw rectangle around edit control with background color using (Pen pen = new Pen(BackColor)) { Rectangle backRect = editBounds; backRect.X--; backRect.Y--; backRect.Width++; backRect.Height++; e.Graphics.DrawRectangle(pen, backRect); } } } else { // Draw rectangle around edit control with background color using (Pen pen = new Pen(BackColor, Enabled ? 2 : 1)) { Rectangle backRect = editBounds; backRect.Inflate(1, 1); if (!Enabled) { backRect.X--; backRect.Y--; backRect.Width++; backRect.Height++; } e.Graphics.DrawRectangle(pen, backRect); } } if (!Enabled && BorderStyle != BorderStyle.None && !upDownEdit.ShouldSerializeBackColor()) { //draws a grayed rectangled around the upDownEdit, since otherwise we will have a white //border around the upDownEdit, which is inconsistent with Windows' behavior //we only want to do this when BackColor is not serialized, since otherwise //we should display the backcolor instead of the usual grayed textbox. editBounds.Inflate(1, 1); ControlPaint.DrawBorder(e.Graphics, editBounds, SystemColors.Control, ButtonBorderStyle.Solid); } } ////// /// protected virtual void OnTextBoxKeyDown(object source, KeyEventArgs e) { this.OnKeyDown(e); if (interceptArrowKeys) { // Intercept up arrow if (e.KeyData == Keys.Up) { UpButton(); e.Handled = true; } // Intercept down arrow else if (e.KeyData == Keys.Down) { DownButton(); e.Handled = true; } } // Perform text validation if ENTER is pressed // if (e.KeyCode == Keys.Return && UserEdit) { ValidateEditText(); } } ///Raises the ////// event. /// /// protected virtual void OnTextBoxKeyPress(object source, KeyPressEventArgs e) { this.OnKeyPress(e); } ///Raises the ////// event. /// /// protected virtual void OnTextBoxLostFocus(object source, EventArgs e) { if (UserEdit) { ValidateEditText(); } } ///Raises the ///event. /// /// protected virtual void OnTextBoxResize(object source, EventArgs e) { this.Height = PreferredHeight; PositionControls(); } ///Raises the ///event. /// /// protected virtual void OnTextBoxTextChanged(object source, EventArgs e) { if (changingText) { Debug.Assert(UserEdit == false, "OnTextBoxTextChanged() - UserEdit == true"); ChangingText = false; } else { UserEdit = true; } this.OnTextChanged(e); OnChanged(source, new EventArgs()); } ///Raises the TextBoxTextChanged event. /// event. ////// Called from the UpDownButtons member. Provided for derived controls to have a finer way to handle the event. /// internal virtual void OnStartTimer() { } internal virtual void OnStopTimer() { } ////// Raises the protected override void OnMouseDown(MouseEventArgs e) { if (e.Clicks == 2 && e.Button == MouseButtons.Left) { doubleClickFired = true; } base.OnMouseDown(e); } ///event. /// /// /// protected override void OnMouseUp(MouseEventArgs mevent) { if (mevent.Button == MouseButtons.Left) { Point pt = PointToScreen(new Point(mevent.X, mevent.Y)); if (UnsafeNativeMethods.WindowFromPoint(pt.X, pt.Y) == Handle && !ValidationCancelled) { if (!doubleClickFired) { OnClick(mevent); OnMouseClick(mevent); } else { doubleClickFired = false; OnDoubleClick(mevent); OnMouseDoubleClick(mevent); } } doubleClickFired = false; } base.OnMouseUp(mevent); } ////// Raises the ///event. /// /// /// /// protected override void OnMouseWheel(MouseEventArgs e) { base.OnMouseWheel(e); HandledMouseEventArgs hme = e as HandledMouseEventArgs; if (hme != null) { if (hme.Handled) { return; } hme.Handled = true; } if ((ModifierKeys & (Keys.Shift | Keys.Alt)) != 0 || MouseButtons != MouseButtons.None) { return; // Do not scroll when Shift or Alt key is down, or when a mouse button is down. } int wheelScrollLines = SystemInformation.MouseWheelScrollLines; if (wheelScrollLines == 0) { return; // Do not scroll when the user system setting is 0 lines per notch } Debug.Assert(this.wheelDelta > -NativeMethods.WHEEL_DELTA, "wheelDelta is too smal"); Debug.Assert(this.wheelDelta < NativeMethods.WHEEL_DELTA, "wheelDelta is too big"); this.wheelDelta += e.Delta; float partialNotches; partialNotches = (float)this.wheelDelta / (float)NativeMethods.WHEEL_DELTA; if (wheelScrollLines == -1) { wheelScrollLines = DefaultWheelScrollLinesPerPage; } // Evaluate number of bands to scroll int scrollBands = (int)((float)wheelScrollLines * partialNotches); if (scrollBands != 0) { int absScrollBands; if (scrollBands > 0) { absScrollBands = scrollBands; while (absScrollBands > 0) { UpButton(); absScrollBands--; } this.wheelDelta -= (int)((float)scrollBands * ((float)NativeMethods.WHEEL_DELTA / (float)wheelScrollLines)); } else { absScrollBands = -scrollBands; while (absScrollBands > 0) { DownButton(); absScrollBands--; } this.wheelDelta -= (int)((float)scrollBands * ((float)NativeMethods.WHEEL_DELTA / (float)wheelScrollLines)); } } } ///Raises the ///event. /// /// /// Handle the layout event. The size of the upDownEdit control, and the /// position of the UpDown control must be modified. /// protected override void OnLayout(LayoutEventArgs e) { PositionControls(); base.OnLayout(e); } ////// /// /// protected override void OnFontChanged(EventArgs e) { // Clear the font height cache FontHeight = -1; Height = PreferredHeight; PositionControls(); base.OnFontChanged(e); } ////// Raises the FontChanged event. /// ////// /// /// Handles UpDown events, which are generated by clicking on /// the updown buttons in the child updown control. /// /// private void OnUpDown(object source, UpDownEventArgs e) { // Modify the value if (e.ButtonID == (int)ButtonID.Up) UpButton(); else if (e.ButtonID == (int)ButtonID.Down) DownButton(); } ////// /// Calculates the size and position of the upDownEdit control and /// the updown buttons. /// private void PositionControls() { Rectangle upDownEditBounds = Rectangle.Empty, upDownButtonsBounds = Rectangle.Empty; Rectangle clientArea = new Rectangle(Point.Empty, ClientSize); int totalClientWidth = clientArea.Width; bool themed = Application.RenderWithVisualStyles; BorderStyle borderStyle = BorderStyle; // determine how much to squish in - Fixed3d and FixedSingle have 2PX border int borderWidth = (borderStyle == BorderStyle.None) ? 0 : 2; clientArea.Inflate(-borderWidth, -borderWidth); // Reposition and resize the upDownEdit control // if (upDownEdit != null) { upDownEditBounds = clientArea; upDownEditBounds.Size = new Size(clientArea.Width - DefaultButtonsWidth, clientArea.Height); } // Reposition and resize the updown buttons // if (upDownButtons != null) { int borderFixup = (themed) ? 1: 2; if (borderStyle == BorderStyle.None) { borderFixup = 0; } upDownButtonsBounds = new Rectangle(/*x*/clientArea.Right - DefaultButtonsWidth+borderFixup, /*y*/clientArea.Top-borderFixup, /*w*/DefaultButtonsWidth, /*h*/clientArea.Height+(borderFixup*2)); } // Right to left translation LeftRightAlignment updownAlign = UpDownAlign; updownAlign = RtlTranslateLeftRight(updownAlign); // left/right updown align translation if (updownAlign == LeftRightAlignment.Left) { // if the buttons are aligned to the left, swap position of text box/buttons upDownButtonsBounds.X = totalClientWidth - upDownButtonsBounds.Right; upDownEditBounds.X = totalClientWidth - upDownEditBounds.Right; } // apply locations if (upDownEdit != null) { upDownEdit.Bounds = upDownEditBounds; } if (upDownButtons != null) { upDownButtons.Bounds = upDownButtonsBounds; upDownButtons.Invalidate(); } } ////// /// public void Select(int start, int length) { upDownEdit.Select(start, length); } ////// Selects a range of /// text in the up-down control. /// ////// Child controls run their /// private MouseEventArgs TranslateMouseEvent(Control child, MouseEventArgs e) { if (child != null && IsHandleCreated) { // same control as PointToClient or PointToScreen, just // with two specific controls in mind. NativeMethods.POINT point = new NativeMethods.POINT(e.X, e.Y); UnsafeNativeMethods.MapWindowPoints(new HandleRef(child, child.Handle), new HandleRef(this, Handle), point, 1); return new MouseEventArgs(e.Button, e.Clicks, point.x, point.y , e.Delta); } return e; } ////// /// public abstract void UpButton(); ////// When overridden in a derived class, handles the pressing of the up button on the up-down control. /// ////// /// protected abstract void UpdateEditText(); private void UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs pref) { if (pref.Category == UserPreferenceCategory.Locale) { UpdateEditText(); } } ////// When overridden /// in a derived class, updates the text displayed in the up-down control. /// ////// /// protected virtual void ValidateEditText() { } ////// When overridden in a /// derived class, validates the text displayed in the up-down control. /// ////// /// /// [EditorBrowsable(EditorBrowsableState.Advanced)] [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { switch (m.Msg) { case NativeMethods.WM_SETFOCUS: if (!HostedInWin32DialogManager) { if (ActiveControl == null) { SetActiveControlInternal(TextBox); } else { FocusActiveControlInternal(); } } else { if (TextBox.CanFocus){ UnsafeNativeMethods.SetFocus(new HandleRef(TextBox, TextBox.Handle)); } base.WndProc(ref m); } break; case NativeMethods.WM_KILLFOCUS: DefWndProc(ref m); break; default: base.WndProc(ref m); break; } } ////// /// /// This Function sets the ToolTip for this composite control. /// internal void SetToolTip(ToolTip toolTip, string caption) { toolTip.SetToolTip(this.upDownEdit , caption); toolTip.SetToolTip(this.upDownButtons , caption); } internal class UpDownEdit : TextBox{ ///////////////////////////////////////////////////////////////////// // Member variables // ///////////////////////////////////////////////////////////////////// // Parent control private UpDownBase parent; private bool doubleClickFired = false; ///////////////////////////////////////////////////////////////////// // Constructors // ///////////////////////////////////////////////////////////////////// internal UpDownEdit(UpDownBase parent) : base() { SetStyle(ControlStyles.FixedHeight | ControlStyles.FixedWidth, true); SetStyle(ControlStyles.Selectable, false); this.parent = parent; } protected override AccessibleObject CreateAccessibilityInstance() { return new UpDownEditAccessibleObject(this, parent); } protected override void OnMouseDown(MouseEventArgs e) { if (e.Clicks == 2 && e.Button == MouseButtons.Left) { doubleClickFired = true; } parent.OnMouseDown(parent.TranslateMouseEvent(this, e)); } ////// /// /// Handles detecting when the mouse button is released. /// /// protected override void OnMouseUp(MouseEventArgs e) { Point pt = new Point(e.X,e.Y); pt = PointToScreen(pt); MouseEventArgs me = parent.TranslateMouseEvent(this, e); if (e.Button == MouseButtons.Left) { if (!parent.ValidationCancelled && UnsafeNativeMethods.WindowFromPoint(pt.X, pt.Y) == Handle) { if (!doubleClickFired) { parent.OnClick(me); parent.OnMouseClick(me); } else { doubleClickFired = false; parent.OnDoubleClick(me); parent.OnMouseDoubleClick(me); } } doubleClickFired = false; } parent.OnMouseUp(me); } internal override void WmContextMenu(ref Message m) { // VSWhidbey 521337: want to make the SourceControl to be the UpDownBase, not the Edit. if (ContextMenu == null && ContextMenuStrip != null) { WmContextMenu(ref m, parent); } else { WmContextMenu(ref m, this); } } ////// /// protected override void OnKeyUp(KeyEventArgs e) { parent.OnKeyUp(e); } protected override void OnGotFocus(EventArgs e) { parent.SetActiveControlInternal(this); parent.OnGotFocus(e); } protected override void OnLostFocus(EventArgs e) { parent.OnLostFocus(e); } // [....]: Focus fixes. The XXXUpDown control will // also fire a Leave event. We don't want // to fire two of them. // protected override void OnLeave(EventArgs e) { // parent.OnLeave(e); // } // Create our own accessibility object to map the accessible name // back to our parent. They should track. internal class UpDownEditAccessibleObject : ControlAccessibleObject { UpDownBase parent; public UpDownEditAccessibleObject(UpDownEdit owner, UpDownBase parent) : base(owner) { this.parent = parent; } public override string Name { get { return parent.AccessibilityObject.Name; } set { parent.AccessibilityObject.Name = value; } } public override string KeyboardShortcut { get { return parent.AccessibilityObject.KeyboardShortcut; } } } } ///Raises the ////// event. /// /// /// Nested class UpDownButtons /// /// A control representing the pair of buttons on the end of the upDownEdit control. /// This class handles drawing the updown buttons, and detecting mouse actions /// on these buttons. Acceleration on the buttons is handled. The control /// sends UpDownEventArgss to the parent UpDownBase class when a button is pressed, /// or when the acceleration determines that another event should be generated. /// internal class UpDownButtons : Control { // ///////////////////////////////////////////////////////////////////// // Member variables // ///////////////////////////////////////////////////////////////////// // Parent control private UpDownBase parent; // Button state private ButtonID pushed = ButtonID.None; private ButtonID captured = ButtonID.None; private ButtonID mouseOver = ButtonID.None; // UpDown event handler private UpDownEventHandler upDownEventHandler; // Timer private Timer timer; // generates UpDown events private int timerInterval; // milliseconds between events private bool doubleClickFired = false; ///////////////////////////////////////////////////////////////////// // Constructors // ///////////////////////////////////////////////////////////////////// internal UpDownButtons(UpDownBase parent) : base() { SetStyle(ControlStyles.Opaque | ControlStyles.FixedHeight | ControlStyles.FixedWidth, true); SetStyle(ControlStyles.Selectable, false); this.parent = parent; } ///////////////////////////////////////////////////////////////////// // Methods // ///////////////////////////////////////////////////////////////////// ////// /// /// Adds a handler for the updown button event. /// public event UpDownEventHandler UpDown { add { upDownEventHandler += value; } remove { upDownEventHandler -= value; } } // Called when the mouse button is pressed - we need to start // spinning the value of the updown. // private void BeginButtonPress(MouseEventArgs e) { int half_height = Size.Height / 2; if (e.Y < half_height) { // Up button // pushed = captured = ButtonID.Up; Invalidate(); } else { // Down button // pushed = captured = ButtonID.Down; Invalidate(); } // Capture the mouse // CaptureInternal = true; // Generate UpDown event // OnUpDown(new UpDownEventArgs((int)pushed)); // Start the timer for new updown events // StartTimer(); } protected override AccessibleObject CreateAccessibilityInstance() { return new UpDownButtonsAccessibleObject(this); } // Called when the mouse button is released - we need to stop // spinning the value of the updown. // private void EndButtonPress() { pushed = ButtonID.None; captured = ButtonID.None; // Stop the timer StopTimer(); // Release the mouse CaptureInternal = false; // Redraw the buttons Invalidate(); } ////// /// /// Handles detecting mouse hits on the buttons. This method /// detects which button was hit (up or down), fires a /// updown event, captures the mouse, and starts a timer /// for repeated updown events. /// /// protected override void OnMouseDown(MouseEventArgs e) { // Begin spinning the value // // Focus the parent // this.parent.FocusInternal(); if (!parent.ValidationCancelled && e.Button == MouseButtons.Left) { BeginButtonPress(e); } if (e.Clicks == 2 && e.Button == MouseButtons.Left) { doubleClickFired = true; } // At no stage should a button be pushed, and the mouse // not captured. // Debug.Assert(!(pushed != ButtonID.None && captured == ButtonID.None), "Invalid button pushed/captured combination"); parent.OnMouseDown(parent.TranslateMouseEvent(this, e)); } ////// /// /// Handles detecting mouse movement. /// /// protected override void OnMouseMove(MouseEventArgs e) { // If the mouse is captured by the buttons (i.e. an updown button // was pushed, and the mouse button has not yet been released), // determine the new state of the buttons depending on where // the mouse pointer has moved. if (Capture) { // Determine button area Rectangle rect = ClientRectangle; rect.Height /= 2; if (captured == ButtonID.Down) { rect.Y += rect.Height; } // Test if the mouse has moved outside the button area if (rect.Contains(e.X, e.Y)) { // Inside button // Repush the button if necessary if (pushed != captured) { // Restart the timer StartTimer(); pushed = captured; Invalidate(); } } else { // Outside button // Retain the capture, but pop the button up whilst // the mouse remains outside the button and the // mouse button remains pressed. if (pushed != ButtonID.None) { // Stop the timer for updown events StopTimer(); pushed = ButtonID.None; Invalidate(); } } } //Logic for seeing which button is Hot if any Rectangle rectUp = ClientRectangle, rectDown = ClientRectangle; rectUp.Height /= 2; rectDown.Y += rectDown.Height / 2; //Check if the mouse is on the upper or lower button. Note that it could be in neither. if (rectUp.Contains(e.X, e.Y)) { mouseOver = ButtonID.Up; Invalidate(); } else if (rectDown.Contains(e.X, e.Y)) { mouseOver = ButtonID.Down; Invalidate(); } // At no stage should a button be pushed, and the mouse // not captured. Debug.Assert(!(pushed != ButtonID.None && captured == ButtonID.None), "Invalid button pushed/captured combination"); parent.OnMouseMove(parent.TranslateMouseEvent(this, e)); } ////// /// /// Handles detecting when the mouse button is released. /// /// protected override void OnMouseUp(MouseEventArgs e) { if (!parent.ValidationCancelled && e.Button == MouseButtons.Left) { EndButtonPress(); } // At no stage should a button be pushed, and the mouse // not captured. Debug.Assert(!(pushed != ButtonID.None && captured == ButtonID.None), "Invalid button pushed/captured combination"); Point pt = new Point(e.X,e.Y); pt = PointToScreen(pt); MouseEventArgs me = parent.TranslateMouseEvent(this, e); if (e.Button == MouseButtons.Left) { if (!parent.ValidationCancelled && UnsafeNativeMethods.WindowFromPoint(pt.X, pt.Y) == Handle) { if (!doubleClickFired) { this.parent.OnClick(me); } else { doubleClickFired = false; this.parent.OnDoubleClick(me); this.parent.OnMouseDoubleClick(me); } } doubleClickFired = false; } parent.OnMouseUp(me); } ////// /// /// Handles detecting when the mouse leaves. /// /// protected override void OnMouseLeave(EventArgs e) { mouseOver = ButtonID.None; Invalidate(); parent.OnMouseLeave(e); } ////// /// Handles painting the buttons on the control. /// /// protected override void OnPaint(PaintEventArgs e) { int half_height = ClientSize.Height / 2; /* Draw the up and down buttons */ if (Application.RenderWithVisualStyles) { VisualStyleRenderer vsr = new VisualStyleRenderer(mouseOver == ButtonID.Up ? VisualStyleElement.Spin.Up.Hot : VisualStyleElement.Spin.Up.Normal); if (!Enabled) { vsr.SetParameters(VisualStyleElement.Spin.Up.Disabled); } else if (pushed == ButtonID.Up) { vsr.SetParameters(VisualStyleElement.Spin.Up.Pressed); } vsr.DrawBackground(e.Graphics, new Rectangle(0, 0, DefaultButtonsWidth, half_height)); if (!Enabled) { vsr.SetParameters(VisualStyleElement.Spin.Down.Disabled); } else if (pushed == ButtonID.Down) { vsr.SetParameters(VisualStyleElement.Spin.Down.Pressed); } else { vsr.SetParameters(mouseOver == ButtonID.Up ? VisualStyleElement.Spin.Down.Hot : VisualStyleElement.Spin.Down.Normal); } vsr.DrawBackground(e.Graphics, new Rectangle(0, half_height, DefaultButtonsWidth, half_height)); } else { ControlPaint.DrawScrollButton(e.Graphics, new Rectangle(0, 0, DefaultButtonsWidth, half_height), ScrollButton.Up, pushed == ButtonID.Up ? ButtonState.Pushed : (Enabled ? ButtonState.Normal : ButtonState.Inactive)); ControlPaint.DrawScrollButton(e.Graphics, new Rectangle(0, half_height, DefaultButtonsWidth, half_height), ScrollButton.Down, pushed == ButtonID.Down ? ButtonState.Pushed : (Enabled ? ButtonState.Normal : ButtonState.Inactive)); } if (half_height != (ClientSize.Height + 1) / 2) { // When control has odd height, a line needs to be drawn below the buttons with the backcolor. using (Pen pen = new Pen(this.parent.BackColor)) { Rectangle clientRect = ClientRectangle; e.Graphics.DrawLine(pen, clientRect.Left, clientRect.Bottom - 1, clientRect.Right - 1, clientRect.Bottom - 1); } } base.OnPaint(e); // raise paint event, just in case this inner class goes public some day } ////// /// Occurs when the UpDown buttons are pressed and when the acceleration timer tick event is raised. /// protected virtual void OnUpDown(UpDownEventArgs upevent) { if (upDownEventHandler != null) upDownEventHandler(this, upevent); } ////// /// Starts the timer for generating updown events /// protected void StartTimer() { parent.OnStartTimer(); if (timer == null) { timer = new Timer(); // generates UpDown events // Add the timer handler timer.Tick += new EventHandler(TimerHandler); } this.timerInterval = DefaultTimerInterval; timer.Interval = this.timerInterval; timer.Start(); } ////// /// Stops the timer for generating updown events /// protected void StopTimer() { if (timer != null) { timer.Stop(); timer.Dispose(); timer = null; } parent.OnStopTimer(); } ////// /// Generates updown events when the timer calls this function. /// private void TimerHandler(object source, EventArgs args) { // Make sure we've got mouse capture if (!Capture) { EndButtonPress(); return; } OnUpDown(new UpDownEventArgs((int)pushed)); // Accelerate timer. this.timerInterval *= 7; this.timerInterval /= 10; if (this.timerInterval < 1) { this.timerInterval = 1; } timer.Interval = this.timerInterval; } internal class UpDownButtonsAccessibleObject : ControlAccessibleObject { private DirectionButtonAccessibleObject upButton; private DirectionButtonAccessibleObject downButton; public UpDownButtonsAccessibleObject(UpDownButtons owner) : base(owner) { } public override string Name { get { string baseName = base.Name; if (baseName == null || baseName.Length == 0) { return "Spinner"; } return baseName; } set { base.Name = value; } } ////// /// public override AccessibleRole Role { get { AccessibleRole role = Owner.AccessibleRole; if (role != AccessibleRole.Default) { return role; } return AccessibleRole.SpinButton; } } private DirectionButtonAccessibleObject UpButton { get { if (upButton == null) { upButton = new DirectionButtonAccessibleObject(this, true); } return upButton; } } private DirectionButtonAccessibleObject DownButton { get { if (downButton == null) { downButton = new DirectionButtonAccessibleObject(this, false); } return downButton; } } ///[To be supplied.] ////// /// public override AccessibleObject GetChild(int index) { // Up button // if (index == 0) { return UpButton; } // Down button // if (index == 1) { return DownButton; } return null; } ////// /// public override int GetChildCount() { return 2; } internal class DirectionButtonAccessibleObject : AccessibleObject { private bool up; private UpDownButtonsAccessibleObject parent; public DirectionButtonAccessibleObject(UpDownButtonsAccessibleObject parent, bool up) { this.parent = parent; this.up = up; } public override Rectangle Bounds { get { // Get button bounds // Rectangle bounds = ((UpDownButtons)parent.Owner).Bounds; bounds.Height /= 2; if (!up) { bounds.Y += bounds.Height; } // Convert to screen co-ords // return (((UpDownButtons)parent.Owner).ParentInternal).RectangleToScreen(bounds); } } public override string Name { get { if (up) { return SR.GetString(SR.UpDownBaseUpButtonAccName); } return SR.GetString(SR.UpDownBaseDownButtonAccName); } set { } } public override AccessibleObject Parent { [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] get { return parent; } } public override AccessibleRole Role { get { return AccessibleRole.PushButton; } } } } } // end class UpDownButtons // Button identifiers internal enum ButtonID { None = 0, Up = 1, Down = 2, } } // end class UpDownBase } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Windows.Forms { using System.Runtime.Serialization.Formatters; using System.Threading; using System.Runtime.Remoting; using System.Runtime.InteropServices; using System.ComponentModel; using System.Diagnostics; using System; using System.Security.Permissions; using System.Windows.Forms.VisualStyles; using System.Drawing; using Microsoft.Win32; ////// /// [ ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch), Designer("System.Windows.Forms.Design.UpDownBaseDesigner, " + AssemblyRef.SystemDesign), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1012:AbstractTypesShouldNotHaveConstructors") // Shipped in Everett ] public abstract class UpDownBase : ContainerControl { private const int DefaultWheelScrollLinesPerPage = 1; private const int DefaultButtonsWidth = 16; private const int DefaultControlWidth = 120; private const int ThemedBorderWidth = 1; // width of custom border we draw when themed private const BorderStyle DefaultBorderStyle = BorderStyle.Fixed3D; private static readonly bool DefaultInterceptArrowKeys = true; private const LeftRightAlignment DefaultUpDownAlign = LeftRightAlignment.Right; private const int DefaultTimerInterval = 500; //////////////////////////////////////////////////////////////////////// // Member variables // //////////////////////////////////////////////////////////////////////// // Child controls internal UpDownEdit upDownEdit; // See nested class at end of this file internal UpDownButtons upDownButtons; // See nested class at end of this file // Intercept arrow keys? private bool interceptArrowKeys = DefaultInterceptArrowKeys; // If true, the updown buttons will be drawn on the left-hand side of the control. private LeftRightAlignment upDownAlign = DefaultUpDownAlign; // userEdit is true when the text of the control has been changed, // and the internal value of the control has not yet been updated. // We do not always want to keep the internal value up-to-date, // hence this variable. private bool userEdit = false; ///Implements the basic /// functionality required by an up-down control. ////// /// The current border for this edit control. /// private BorderStyle borderStyle = DefaultBorderStyle; // Mouse wheel movement private int wheelDelta = 0; // Indicates if the edit text is being changed private bool changingText = false; // Indicates whether we have doubleClicked private bool doubleClickFired = false; ////// /// public UpDownBase() { upDownButtons = new UpDownButtons(this); upDownEdit = new UpDownEdit(this); upDownEdit.BorderStyle = BorderStyle.None; upDownEdit.AutoSize = false; upDownEdit.KeyDown += new KeyEventHandler(this.OnTextBoxKeyDown); upDownEdit.KeyPress += new KeyPressEventHandler(this.OnTextBoxKeyPress); upDownEdit.TextChanged += new EventHandler(this.OnTextBoxTextChanged); upDownEdit.LostFocus += new EventHandler(this.OnTextBoxLostFocus); upDownEdit.Resize += new EventHandler(this.OnTextBoxResize); upDownButtons.TabStop = false; upDownButtons.Size = new Size(DefaultButtonsWidth, PreferredHeight); upDownButtons.UpDown += new UpDownEventHandler(this.OnUpDown); Controls.AddRange(new Control[] { upDownButtons, upDownEdit} ); SetStyle(ControlStyles.Opaque | ControlStyles.FixedHeight | ControlStyles.ResizeRedraw, true); SetStyle(ControlStyles.StandardClick, false); SetStyle(ControlStyles.UseTextForAccessibility, false); } //////////////////////////////////////////////////////////////////////// // Properties // //////////////////////////////////////////////////////////////////////// // AutoScroll is not relevant to an UpDownBase ////// Initializes a new instance of the ////// class. /// /// /// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override bool AutoScroll { get { return false; } set { // Don't allow AutoScroll to be set to anything } } // AutoScrollMargin is not relevant to an UpDownBase ////// /// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] new public Size AutoScrollMargin { get { return base.AutoScrollMargin; } set { base.AutoScrollMargin = value; } } // AutoScrollMinSize is not relevant to an UpDownBase ////// /// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] new public Size AutoScrollMinSize { get { return base.AutoScrollMinSize; } set { base.AutoScrollMinSize = value; } } ////// /// [Browsable(true), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public override bool AutoSize { get { return base.AutoSize; } set { base.AutoSize = value; } } ///Override to re-expose AutoSize. ///[SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnAutoSizeChangedDescr)] [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)] new public event EventHandler AutoSizeChanged { add { base.AutoSizeChanged += value; } remove { base.AutoSizeChanged -= value; } } /// /// /// /// public override Color BackColor { get { return upDownEdit.BackColor; } set { base.BackColor = value; // Don't remove this or you will break serialization. See VSWhidbey #517574 upDownEdit.BackColor = value; Invalidate(); // VSWhidbey #335074 } } ////// Gets or sets the background color for the /// text box portion of the up-down control. /// ////// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override Image BackgroundImage { get { return base.BackgroundImage; } set { base.BackgroundImage = value; } } ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public event EventHandler BackgroundImageChanged { add { base.BackgroundImageChanged += value; } remove { base.BackgroundImageChanged -= value; } } /// /// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override ImageLayout BackgroundImageLayout { get { return base.BackgroundImageLayout; } set { base.BackgroundImageLayout = value; } } ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public event EventHandler BackgroundImageLayoutChanged { add { base.BackgroundImageLayoutChanged += value; } remove { base.BackgroundImageLayoutChanged -= value; } } /// /// /// [ SRCategory(SR.CatAppearance), DefaultValue(BorderStyle.Fixed3D), DispId(NativeMethods.ActiveX.DISPID_BORDERSTYLE), SRDescription(SR.UpDownBaseBorderStyleDescr) ] public BorderStyle BorderStyle { get { return borderStyle; } set { //valid values are 0x0 to 0x2 if (!ClientUtils.IsEnumValid(value, (int)value, (int)BorderStyle.None, (int)BorderStyle.Fixed3D)) { throw new InvalidEnumArgumentException("value", (int)value, typeof(BorderStyle)); } if (borderStyle != value) { borderStyle = value; RecreateHandle(); } } } ////// Gets or sets the border style for /// the up-down control. /// ////// /// protected bool ChangingText { get { return changingText; } set { changingText = value; } } ////// Gets or sets a value indicating whether the text /// property is being changed internally by its parent class. /// ////// /// /// public override ContextMenu ContextMenu { get { return base.ContextMenu; } set { base.ContextMenu = value; this.upDownEdit.ContextMenu = value; } } public override ContextMenuStrip ContextMenuStrip { get { return base.ContextMenuStrip; } set { base.ContextMenuStrip = value; this.upDownEdit.ContextMenuStrip = value; } } ////// /// /// protected override CreateParams CreateParams { [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] get { CreateParams cp = base.CreateParams; cp.Style &= (~NativeMethods.WS_BORDER); if (!Application.RenderWithVisualStyles) { switch (borderStyle) { case BorderStyle.Fixed3D: cp.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE; break; case BorderStyle.FixedSingle: cp.Style |= NativeMethods.WS_BORDER; break; } } return cp; } } ////// Returns the parameters needed to create the handle. Inheriting classes /// can override this to provide extra functionality. They should not, /// however, forget to call base.getCreateParams() first to get the struct /// filled up with the basic info. /// ////// /// Deriving classes can override this to configure a default size for their control. /// This is more efficient than setting the size in the control's constructor. /// protected override Size DefaultSize { get { return new Size(DefaultControlWidth, PreferredHeight); } } // DockPadding is not relevant to UpDownBase ////// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] new public DockPaddingEdges DockPadding { get { return base.DockPadding; } } ////// /// Returns true if this control has focus. /// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.ControlFocusedDescr) ] public override bool Focused { get { return upDownEdit.Focused; } } ////// /// /// public override Color ForeColor { get { return upDownEdit.ForeColor; } set { base.ForeColor = value; upDownEdit.ForeColor = value; } } ////// Indicates the foreground color for the control. /// ////// /// [ SRCategory(SR.CatBehavior), DefaultValue(true), SRDescription(SR.UpDownBaseInterceptArrowKeysDescr) ] public bool InterceptArrowKeys { get { return interceptArrowKeys; } set { interceptArrowKeys = value; } } ////// Gets or sets a value indicating whether /// the user can use the UP /// ARROW and DOWN ARROW keys to select values. /// ///public override Size MaximumSize { get { return base.MaximumSize; } set { base.MaximumSize = new Size(value.Width, 0); } } /// public override Size MinimumSize { get { return base.MinimumSize; } set { base.MinimumSize = new Size(value.Width, 0); } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler MouseEnter { add { base.MouseEnter += value; } remove { base.MouseEnter -= value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler MouseLeave { add { base.MouseLeave += value; } remove { base.MouseLeave -= value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler MouseHover { add { base.MouseHover += value; } remove { base.MouseHover -= value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event MouseEventHandler MouseMove { add { base.MouseMove += value; } remove { base.MouseMove -= value; } } /// /// /// [ SRCategory(SR.CatLayout), Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.UpDownBasePreferredHeightDescr) ] public int PreferredHeight { get { int height = FontHeight; // Adjust for the border style if (borderStyle != BorderStyle.None) { height += SystemInformation.BorderSize.Height * 4 + 3; } else { height += 3; } return height; } } ////// Gets the height of /// the up-down control. /// ////// /// [ SRCategory(SR.CatBehavior), DefaultValue(false), SRDescription(SR.UpDownBaseReadOnlyDescr) ] public bool ReadOnly { get { return upDownEdit.ReadOnly; } set { upDownEdit.ReadOnly = value; } } ////// Gets or sets /// a /// value /// indicating whether the text may only be changed by the /// use /// of the up or down buttons. /// ////// /// [ Localizable(true) ] public override string Text { get { return upDownEdit.Text; } set { upDownEdit.Text = value; // The text changed event will at this point be triggered. // After returning, the value of UserEdit will reflect // whether or not the current upDownEditbox text is in [....] // with any internally stored values. If UserEdit is true, // we must validate the text the user typed or set. ChangingText = false; // Details: Usually, the code in the Text changed event handler // sets ChangingText back to false. // If the text hasn't actually changed though, the event handler // never fires. ChangingText should always be false on exit from // this property. if (UserEdit) { ValidateEditText(); } } } ////// Gets or sets the text /// displayed in the up-down control. /// ////// /// [ Localizable(true), SRCategory(SR.CatAppearance), DefaultValue(HorizontalAlignment.Left), SRDescription(SR.UpDownBaseTextAlignDescr) ] public HorizontalAlignment TextAlign { get { return upDownEdit.TextAlign; } set { //valid values are 0x0 to 0x2 if (!ClientUtils.IsEnumValid(value, (int)value, (int)HorizontalAlignment.Left, (int)HorizontalAlignment.Center)) { throw new InvalidEnumArgumentException("value", (int)value, typeof(HorizontalAlignment)); } upDownEdit.TextAlign = value; } } internal TextBox TextBox { get { return upDownEdit; } } ////// Gets or /// sets the alignment of the text in the up-down /// control. /// ////// /// [ Localizable(true), SRCategory(SR.CatAppearance), DefaultValue(LeftRightAlignment.Right), SRDescription(SR.UpDownBaseAlignmentDescr) ] public LeftRightAlignment UpDownAlign { get { return upDownAlign; } set { //valid values are 0x0 to 0x1 if (!ClientUtils.IsEnumValid(value, (int)value, (int)LeftRightAlignment.Left, (int)LeftRightAlignment.Right)) { throw new InvalidEnumArgumentException("value", (int)value, typeof(LeftRightAlignment)); } if (upDownAlign != value) { upDownAlign = value; PositionControls(); Invalidate(); } } } internal UpDownButtons UpDownButtonsInternal { get { return upDownButtons; } } ////// Gets /// or sets the /// alignment /// of the up and down buttons on the up-down control. /// ////// /// protected bool UserEdit { get { return userEdit; } set { userEdit = value; } } //////////////////////////////////////////////////////////////////////// // Methods // //////////////////////////////////////////////////////////////////////// ////// Gets /// or sets a value indicating whether a value has been entered by the /// user. /// ////// /// public abstract void DownButton(); // GetPreferredSize and SetBoundsCore call this method to allow controls to self impose // constraints on their size. internal override Rectangle ApplyBoundsConstraints(int suggestedX, int suggestedY, int proposedWidth, int proposedHeight) { return base.ApplyBoundsConstraints(suggestedX,suggestedY, proposedWidth, PreferredHeight); } ////// When overridden in a derived class, handles the pressing of the down button /// on the up-down control. /// ////// /// /// protected virtual void OnChanged(object source, EventArgs e) { } ///When overridden in a derived class, raises the Changed event. /// event. ////// /// /// protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); PositionControls(); SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(this.UserPreferenceChanged); } ////// Initialize the updown. Adds the upDownEdit and updown buttons. /// ////// /// /// protected override void OnHandleDestroyed(EventArgs e) { SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(this.UserPreferenceChanged); base.OnHandleDestroyed(e); } ////// Tear down the updown. /// ////// /// Handles painting the buttons on the control. /// /// protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Rectangle editBounds = upDownEdit.Bounds; if (Application.RenderWithVisualStyles) { if (borderStyle != BorderStyle.None) { Rectangle bounds = ClientRectangle; Rectangle clipBounds = e.ClipRectangle; //Draw a themed textbox-like border, which is what the spin control does VisualStyleRenderer vsr = new VisualStyleRenderer(VisualStyleElement.TextBox.TextEdit.Normal); int border = ThemedBorderWidth; Rectangle clipLeft = new Rectangle(bounds.Left, bounds.Top, border, bounds.Height); Rectangle clipTop = new Rectangle(bounds.Left, bounds.Top, bounds.Width, border); Rectangle clipRight = new Rectangle(bounds.Right - border, bounds.Top, border, bounds.Height); Rectangle clipBottom = new Rectangle(bounds.Left, bounds.Bottom - border, bounds.Width, border); clipLeft.Intersect(clipBounds); clipTop.Intersect(clipBounds); clipRight.Intersect(clipBounds); clipBottom.Intersect(clipBounds); vsr.DrawBackground(e.Graphics, bounds, clipLeft); vsr.DrawBackground(e.Graphics, bounds, clipTop); vsr.DrawBackground(e.Graphics, bounds, clipRight); vsr.DrawBackground(e.Graphics, bounds, clipBottom); // Draw rectangle around edit control with background color using (Pen pen = new Pen(BackColor)) { Rectangle backRect = editBounds; backRect.X--; backRect.Y--; backRect.Width++; backRect.Height++; e.Graphics.DrawRectangle(pen, backRect); } } } else { // Draw rectangle around edit control with background color using (Pen pen = new Pen(BackColor, Enabled ? 2 : 1)) { Rectangle backRect = editBounds; backRect.Inflate(1, 1); if (!Enabled) { backRect.X--; backRect.Y--; backRect.Width++; backRect.Height++; } e.Graphics.DrawRectangle(pen, backRect); } } if (!Enabled && BorderStyle != BorderStyle.None && !upDownEdit.ShouldSerializeBackColor()) { //draws a grayed rectangled around the upDownEdit, since otherwise we will have a white //border around the upDownEdit, which is inconsistent with Windows' behavior //we only want to do this when BackColor is not serialized, since otherwise //we should display the backcolor instead of the usual grayed textbox. editBounds.Inflate(1, 1); ControlPaint.DrawBorder(e.Graphics, editBounds, SystemColors.Control, ButtonBorderStyle.Solid); } } ////// /// protected virtual void OnTextBoxKeyDown(object source, KeyEventArgs e) { this.OnKeyDown(e); if (interceptArrowKeys) { // Intercept up arrow if (e.KeyData == Keys.Up) { UpButton(); e.Handled = true; } // Intercept down arrow else if (e.KeyData == Keys.Down) { DownButton(); e.Handled = true; } } // Perform text validation if ENTER is pressed // if (e.KeyCode == Keys.Return && UserEdit) { ValidateEditText(); } } ///Raises the ////// event. /// /// protected virtual void OnTextBoxKeyPress(object source, KeyPressEventArgs e) { this.OnKeyPress(e); } ///Raises the ////// event. /// /// protected virtual void OnTextBoxLostFocus(object source, EventArgs e) { if (UserEdit) { ValidateEditText(); } } ///Raises the ///event. /// /// protected virtual void OnTextBoxResize(object source, EventArgs e) { this.Height = PreferredHeight; PositionControls(); } ///Raises the ///event. /// /// protected virtual void OnTextBoxTextChanged(object source, EventArgs e) { if (changingText) { Debug.Assert(UserEdit == false, "OnTextBoxTextChanged() - UserEdit == true"); ChangingText = false; } else { UserEdit = true; } this.OnTextChanged(e); OnChanged(source, new EventArgs()); } ///Raises the TextBoxTextChanged event. /// event. ////// Called from the UpDownButtons member. Provided for derived controls to have a finer way to handle the event. /// internal virtual void OnStartTimer() { } internal virtual void OnStopTimer() { } ////// Raises the protected override void OnMouseDown(MouseEventArgs e) { if (e.Clicks == 2 && e.Button == MouseButtons.Left) { doubleClickFired = true; } base.OnMouseDown(e); } ///event. /// /// /// protected override void OnMouseUp(MouseEventArgs mevent) { if (mevent.Button == MouseButtons.Left) { Point pt = PointToScreen(new Point(mevent.X, mevent.Y)); if (UnsafeNativeMethods.WindowFromPoint(pt.X, pt.Y) == Handle && !ValidationCancelled) { if (!doubleClickFired) { OnClick(mevent); OnMouseClick(mevent); } else { doubleClickFired = false; OnDoubleClick(mevent); OnMouseDoubleClick(mevent); } } doubleClickFired = false; } base.OnMouseUp(mevent); } ////// Raises the ///event. /// /// /// /// protected override void OnMouseWheel(MouseEventArgs e) { base.OnMouseWheel(e); HandledMouseEventArgs hme = e as HandledMouseEventArgs; if (hme != null) { if (hme.Handled) { return; } hme.Handled = true; } if ((ModifierKeys & (Keys.Shift | Keys.Alt)) != 0 || MouseButtons != MouseButtons.None) { return; // Do not scroll when Shift or Alt key is down, or when a mouse button is down. } int wheelScrollLines = SystemInformation.MouseWheelScrollLines; if (wheelScrollLines == 0) { return; // Do not scroll when the user system setting is 0 lines per notch } Debug.Assert(this.wheelDelta > -NativeMethods.WHEEL_DELTA, "wheelDelta is too smal"); Debug.Assert(this.wheelDelta < NativeMethods.WHEEL_DELTA, "wheelDelta is too big"); this.wheelDelta += e.Delta; float partialNotches; partialNotches = (float)this.wheelDelta / (float)NativeMethods.WHEEL_DELTA; if (wheelScrollLines == -1) { wheelScrollLines = DefaultWheelScrollLinesPerPage; } // Evaluate number of bands to scroll int scrollBands = (int)((float)wheelScrollLines * partialNotches); if (scrollBands != 0) { int absScrollBands; if (scrollBands > 0) { absScrollBands = scrollBands; while (absScrollBands > 0) { UpButton(); absScrollBands--; } this.wheelDelta -= (int)((float)scrollBands * ((float)NativeMethods.WHEEL_DELTA / (float)wheelScrollLines)); } else { absScrollBands = -scrollBands; while (absScrollBands > 0) { DownButton(); absScrollBands--; } this.wheelDelta -= (int)((float)scrollBands * ((float)NativeMethods.WHEEL_DELTA / (float)wheelScrollLines)); } } } ///Raises the ///event. /// /// /// Handle the layout event. The size of the upDownEdit control, and the /// position of the UpDown control must be modified. /// protected override void OnLayout(LayoutEventArgs e) { PositionControls(); base.OnLayout(e); } ////// /// /// protected override void OnFontChanged(EventArgs e) { // Clear the font height cache FontHeight = -1; Height = PreferredHeight; PositionControls(); base.OnFontChanged(e); } ////// Raises the FontChanged event. /// ////// /// /// Handles UpDown events, which are generated by clicking on /// the updown buttons in the child updown control. /// /// private void OnUpDown(object source, UpDownEventArgs e) { // Modify the value if (e.ButtonID == (int)ButtonID.Up) UpButton(); else if (e.ButtonID == (int)ButtonID.Down) DownButton(); } ////// /// Calculates the size and position of the upDownEdit control and /// the updown buttons. /// private void PositionControls() { Rectangle upDownEditBounds = Rectangle.Empty, upDownButtonsBounds = Rectangle.Empty; Rectangle clientArea = new Rectangle(Point.Empty, ClientSize); int totalClientWidth = clientArea.Width; bool themed = Application.RenderWithVisualStyles; BorderStyle borderStyle = BorderStyle; // determine how much to squish in - Fixed3d and FixedSingle have 2PX border int borderWidth = (borderStyle == BorderStyle.None) ? 0 : 2; clientArea.Inflate(-borderWidth, -borderWidth); // Reposition and resize the upDownEdit control // if (upDownEdit != null) { upDownEditBounds = clientArea; upDownEditBounds.Size = new Size(clientArea.Width - DefaultButtonsWidth, clientArea.Height); } // Reposition and resize the updown buttons // if (upDownButtons != null) { int borderFixup = (themed) ? 1: 2; if (borderStyle == BorderStyle.None) { borderFixup = 0; } upDownButtonsBounds = new Rectangle(/*x*/clientArea.Right - DefaultButtonsWidth+borderFixup, /*y*/clientArea.Top-borderFixup, /*w*/DefaultButtonsWidth, /*h*/clientArea.Height+(borderFixup*2)); } // Right to left translation LeftRightAlignment updownAlign = UpDownAlign; updownAlign = RtlTranslateLeftRight(updownAlign); // left/right updown align translation if (updownAlign == LeftRightAlignment.Left) { // if the buttons are aligned to the left, swap position of text box/buttons upDownButtonsBounds.X = totalClientWidth - upDownButtonsBounds.Right; upDownEditBounds.X = totalClientWidth - upDownEditBounds.Right; } // apply locations if (upDownEdit != null) { upDownEdit.Bounds = upDownEditBounds; } if (upDownButtons != null) { upDownButtons.Bounds = upDownButtonsBounds; upDownButtons.Invalidate(); } } ////// /// public void Select(int start, int length) { upDownEdit.Select(start, length); } ////// Selects a range of /// text in the up-down control. /// ////// Child controls run their /// private MouseEventArgs TranslateMouseEvent(Control child, MouseEventArgs e) { if (child != null && IsHandleCreated) { // same control as PointToClient or PointToScreen, just // with two specific controls in mind. NativeMethods.POINT point = new NativeMethods.POINT(e.X, e.Y); UnsafeNativeMethods.MapWindowPoints(new HandleRef(child, child.Handle), new HandleRef(this, Handle), point, 1); return new MouseEventArgs(e.Button, e.Clicks, point.x, point.y , e.Delta); } return e; } ////// /// public abstract void UpButton(); ////// When overridden in a derived class, handles the pressing of the up button on the up-down control. /// ////// /// protected abstract void UpdateEditText(); private void UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs pref) { if (pref.Category == UserPreferenceCategory.Locale) { UpdateEditText(); } } ////// When overridden /// in a derived class, updates the text displayed in the up-down control. /// ////// /// protected virtual void ValidateEditText() { } ////// When overridden in a /// derived class, validates the text displayed in the up-down control. /// ////// /// /// [EditorBrowsable(EditorBrowsableState.Advanced)] [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { switch (m.Msg) { case NativeMethods.WM_SETFOCUS: if (!HostedInWin32DialogManager) { if (ActiveControl == null) { SetActiveControlInternal(TextBox); } else { FocusActiveControlInternal(); } } else { if (TextBox.CanFocus){ UnsafeNativeMethods.SetFocus(new HandleRef(TextBox, TextBox.Handle)); } base.WndProc(ref m); } break; case NativeMethods.WM_KILLFOCUS: DefWndProc(ref m); break; default: base.WndProc(ref m); break; } } ////// /// /// This Function sets the ToolTip for this composite control. /// internal void SetToolTip(ToolTip toolTip, string caption) { toolTip.SetToolTip(this.upDownEdit , caption); toolTip.SetToolTip(this.upDownButtons , caption); } internal class UpDownEdit : TextBox{ ///////////////////////////////////////////////////////////////////// // Member variables // ///////////////////////////////////////////////////////////////////// // Parent control private UpDownBase parent; private bool doubleClickFired = false; ///////////////////////////////////////////////////////////////////// // Constructors // ///////////////////////////////////////////////////////////////////// internal UpDownEdit(UpDownBase parent) : base() { SetStyle(ControlStyles.FixedHeight | ControlStyles.FixedWidth, true); SetStyle(ControlStyles.Selectable, false); this.parent = parent; } protected override AccessibleObject CreateAccessibilityInstance() { return new UpDownEditAccessibleObject(this, parent); } protected override void OnMouseDown(MouseEventArgs e) { if (e.Clicks == 2 && e.Button == MouseButtons.Left) { doubleClickFired = true; } parent.OnMouseDown(parent.TranslateMouseEvent(this, e)); } ////// /// /// Handles detecting when the mouse button is released. /// /// protected override void OnMouseUp(MouseEventArgs e) { Point pt = new Point(e.X,e.Y); pt = PointToScreen(pt); MouseEventArgs me = parent.TranslateMouseEvent(this, e); if (e.Button == MouseButtons.Left) { if (!parent.ValidationCancelled && UnsafeNativeMethods.WindowFromPoint(pt.X, pt.Y) == Handle) { if (!doubleClickFired) { parent.OnClick(me); parent.OnMouseClick(me); } else { doubleClickFired = false; parent.OnDoubleClick(me); parent.OnMouseDoubleClick(me); } } doubleClickFired = false; } parent.OnMouseUp(me); } internal override void WmContextMenu(ref Message m) { // VSWhidbey 521337: want to make the SourceControl to be the UpDownBase, not the Edit. if (ContextMenu == null && ContextMenuStrip != null) { WmContextMenu(ref m, parent); } else { WmContextMenu(ref m, this); } } ////// /// protected override void OnKeyUp(KeyEventArgs e) { parent.OnKeyUp(e); } protected override void OnGotFocus(EventArgs e) { parent.SetActiveControlInternal(this); parent.OnGotFocus(e); } protected override void OnLostFocus(EventArgs e) { parent.OnLostFocus(e); } // [....]: Focus fixes. The XXXUpDown control will // also fire a Leave event. We don't want // to fire two of them. // protected override void OnLeave(EventArgs e) { // parent.OnLeave(e); // } // Create our own accessibility object to map the accessible name // back to our parent. They should track. internal class UpDownEditAccessibleObject : ControlAccessibleObject { UpDownBase parent; public UpDownEditAccessibleObject(UpDownEdit owner, UpDownBase parent) : base(owner) { this.parent = parent; } public override string Name { get { return parent.AccessibilityObject.Name; } set { parent.AccessibilityObject.Name = value; } } public override string KeyboardShortcut { get { return parent.AccessibilityObject.KeyboardShortcut; } } } } ///Raises the ////// event. /// /// /// Nested class UpDownButtons /// /// A control representing the pair of buttons on the end of the upDownEdit control. /// This class handles drawing the updown buttons, and detecting mouse actions /// on these buttons. Acceleration on the buttons is handled. The control /// sends UpDownEventArgss to the parent UpDownBase class when a button is pressed, /// or when the acceleration determines that another event should be generated. /// internal class UpDownButtons : Control { // ///////////////////////////////////////////////////////////////////// // Member variables // ///////////////////////////////////////////////////////////////////// // Parent control private UpDownBase parent; // Button state private ButtonID pushed = ButtonID.None; private ButtonID captured = ButtonID.None; private ButtonID mouseOver = ButtonID.None; // UpDown event handler private UpDownEventHandler upDownEventHandler; // Timer private Timer timer; // generates UpDown events private int timerInterval; // milliseconds between events private bool doubleClickFired = false; ///////////////////////////////////////////////////////////////////// // Constructors // ///////////////////////////////////////////////////////////////////// internal UpDownButtons(UpDownBase parent) : base() { SetStyle(ControlStyles.Opaque | ControlStyles.FixedHeight | ControlStyles.FixedWidth, true); SetStyle(ControlStyles.Selectable, false); this.parent = parent; } ///////////////////////////////////////////////////////////////////// // Methods // ///////////////////////////////////////////////////////////////////// ////// /// /// Adds a handler for the updown button event. /// public event UpDownEventHandler UpDown { add { upDownEventHandler += value; } remove { upDownEventHandler -= value; } } // Called when the mouse button is pressed - we need to start // spinning the value of the updown. // private void BeginButtonPress(MouseEventArgs e) { int half_height = Size.Height / 2; if (e.Y < half_height) { // Up button // pushed = captured = ButtonID.Up; Invalidate(); } else { // Down button // pushed = captured = ButtonID.Down; Invalidate(); } // Capture the mouse // CaptureInternal = true; // Generate UpDown event // OnUpDown(new UpDownEventArgs((int)pushed)); // Start the timer for new updown events // StartTimer(); } protected override AccessibleObject CreateAccessibilityInstance() { return new UpDownButtonsAccessibleObject(this); } // Called when the mouse button is released - we need to stop // spinning the value of the updown. // private void EndButtonPress() { pushed = ButtonID.None; captured = ButtonID.None; // Stop the timer StopTimer(); // Release the mouse CaptureInternal = false; // Redraw the buttons Invalidate(); } ////// /// /// Handles detecting mouse hits on the buttons. This method /// detects which button was hit (up or down), fires a /// updown event, captures the mouse, and starts a timer /// for repeated updown events. /// /// protected override void OnMouseDown(MouseEventArgs e) { // Begin spinning the value // // Focus the parent // this.parent.FocusInternal(); if (!parent.ValidationCancelled && e.Button == MouseButtons.Left) { BeginButtonPress(e); } if (e.Clicks == 2 && e.Button == MouseButtons.Left) { doubleClickFired = true; } // At no stage should a button be pushed, and the mouse // not captured. // Debug.Assert(!(pushed != ButtonID.None && captured == ButtonID.None), "Invalid button pushed/captured combination"); parent.OnMouseDown(parent.TranslateMouseEvent(this, e)); } ////// /// /// Handles detecting mouse movement. /// /// protected override void OnMouseMove(MouseEventArgs e) { // If the mouse is captured by the buttons (i.e. an updown button // was pushed, and the mouse button has not yet been released), // determine the new state of the buttons depending on where // the mouse pointer has moved. if (Capture) { // Determine button area Rectangle rect = ClientRectangle; rect.Height /= 2; if (captured == ButtonID.Down) { rect.Y += rect.Height; } // Test if the mouse has moved outside the button area if (rect.Contains(e.X, e.Y)) { // Inside button // Repush the button if necessary if (pushed != captured) { // Restart the timer StartTimer(); pushed = captured; Invalidate(); } } else { // Outside button // Retain the capture, but pop the button up whilst // the mouse remains outside the button and the // mouse button remains pressed. if (pushed != ButtonID.None) { // Stop the timer for updown events StopTimer(); pushed = ButtonID.None; Invalidate(); } } } //Logic for seeing which button is Hot if any Rectangle rectUp = ClientRectangle, rectDown = ClientRectangle; rectUp.Height /= 2; rectDown.Y += rectDown.Height / 2; //Check if the mouse is on the upper or lower button. Note that it could be in neither. if (rectUp.Contains(e.X, e.Y)) { mouseOver = ButtonID.Up; Invalidate(); } else if (rectDown.Contains(e.X, e.Y)) { mouseOver = ButtonID.Down; Invalidate(); } // At no stage should a button be pushed, and the mouse // not captured. Debug.Assert(!(pushed != ButtonID.None && captured == ButtonID.None), "Invalid button pushed/captured combination"); parent.OnMouseMove(parent.TranslateMouseEvent(this, e)); } ////// /// /// Handles detecting when the mouse button is released. /// /// protected override void OnMouseUp(MouseEventArgs e) { if (!parent.ValidationCancelled && e.Button == MouseButtons.Left) { EndButtonPress(); } // At no stage should a button be pushed, and the mouse // not captured. Debug.Assert(!(pushed != ButtonID.None && captured == ButtonID.None), "Invalid button pushed/captured combination"); Point pt = new Point(e.X,e.Y); pt = PointToScreen(pt); MouseEventArgs me = parent.TranslateMouseEvent(this, e); if (e.Button == MouseButtons.Left) { if (!parent.ValidationCancelled && UnsafeNativeMethods.WindowFromPoint(pt.X, pt.Y) == Handle) { if (!doubleClickFired) { this.parent.OnClick(me); } else { doubleClickFired = false; this.parent.OnDoubleClick(me); this.parent.OnMouseDoubleClick(me); } } doubleClickFired = false; } parent.OnMouseUp(me); } ////// /// /// Handles detecting when the mouse leaves. /// /// protected override void OnMouseLeave(EventArgs e) { mouseOver = ButtonID.None; Invalidate(); parent.OnMouseLeave(e); } ////// /// Handles painting the buttons on the control. /// /// protected override void OnPaint(PaintEventArgs e) { int half_height = ClientSize.Height / 2; /* Draw the up and down buttons */ if (Application.RenderWithVisualStyles) { VisualStyleRenderer vsr = new VisualStyleRenderer(mouseOver == ButtonID.Up ? VisualStyleElement.Spin.Up.Hot : VisualStyleElement.Spin.Up.Normal); if (!Enabled) { vsr.SetParameters(VisualStyleElement.Spin.Up.Disabled); } else if (pushed == ButtonID.Up) { vsr.SetParameters(VisualStyleElement.Spin.Up.Pressed); } vsr.DrawBackground(e.Graphics, new Rectangle(0, 0, DefaultButtonsWidth, half_height)); if (!Enabled) { vsr.SetParameters(VisualStyleElement.Spin.Down.Disabled); } else if (pushed == ButtonID.Down) { vsr.SetParameters(VisualStyleElement.Spin.Down.Pressed); } else { vsr.SetParameters(mouseOver == ButtonID.Up ? VisualStyleElement.Spin.Down.Hot : VisualStyleElement.Spin.Down.Normal); } vsr.DrawBackground(e.Graphics, new Rectangle(0, half_height, DefaultButtonsWidth, half_height)); } else { ControlPaint.DrawScrollButton(e.Graphics, new Rectangle(0, 0, DefaultButtonsWidth, half_height), ScrollButton.Up, pushed == ButtonID.Up ? ButtonState.Pushed : (Enabled ? ButtonState.Normal : ButtonState.Inactive)); ControlPaint.DrawScrollButton(e.Graphics, new Rectangle(0, half_height, DefaultButtonsWidth, half_height), ScrollButton.Down, pushed == ButtonID.Down ? ButtonState.Pushed : (Enabled ? ButtonState.Normal : ButtonState.Inactive)); } if (half_height != (ClientSize.Height + 1) / 2) { // When control has odd height, a line needs to be drawn below the buttons with the backcolor. using (Pen pen = new Pen(this.parent.BackColor)) { Rectangle clientRect = ClientRectangle; e.Graphics.DrawLine(pen, clientRect.Left, clientRect.Bottom - 1, clientRect.Right - 1, clientRect.Bottom - 1); } } base.OnPaint(e); // raise paint event, just in case this inner class goes public some day } ////// /// Occurs when the UpDown buttons are pressed and when the acceleration timer tick event is raised. /// protected virtual void OnUpDown(UpDownEventArgs upevent) { if (upDownEventHandler != null) upDownEventHandler(this, upevent); } ////// /// Starts the timer for generating updown events /// protected void StartTimer() { parent.OnStartTimer(); if (timer == null) { timer = new Timer(); // generates UpDown events // Add the timer handler timer.Tick += new EventHandler(TimerHandler); } this.timerInterval = DefaultTimerInterval; timer.Interval = this.timerInterval; timer.Start(); } ////// /// Stops the timer for generating updown events /// protected void StopTimer() { if (timer != null) { timer.Stop(); timer.Dispose(); timer = null; } parent.OnStopTimer(); } ////// /// Generates updown events when the timer calls this function. /// private void TimerHandler(object source, EventArgs args) { // Make sure we've got mouse capture if (!Capture) { EndButtonPress(); return; } OnUpDown(new UpDownEventArgs((int)pushed)); // Accelerate timer. this.timerInterval *= 7; this.timerInterval /= 10; if (this.timerInterval < 1) { this.timerInterval = 1; } timer.Interval = this.timerInterval; } internal class UpDownButtonsAccessibleObject : ControlAccessibleObject { private DirectionButtonAccessibleObject upButton; private DirectionButtonAccessibleObject downButton; public UpDownButtonsAccessibleObject(UpDownButtons owner) : base(owner) { } public override string Name { get { string baseName = base.Name; if (baseName == null || baseName.Length == 0) { return "Spinner"; } return baseName; } set { base.Name = value; } } ////// /// public override AccessibleRole Role { get { AccessibleRole role = Owner.AccessibleRole; if (role != AccessibleRole.Default) { return role; } return AccessibleRole.SpinButton; } } private DirectionButtonAccessibleObject UpButton { get { if (upButton == null) { upButton = new DirectionButtonAccessibleObject(this, true); } return upButton; } } private DirectionButtonAccessibleObject DownButton { get { if (downButton == null) { downButton = new DirectionButtonAccessibleObject(this, false); } return downButton; } } ///[To be supplied.] ////// /// public override AccessibleObject GetChild(int index) { // Up button // if (index == 0) { return UpButton; } // Down button // if (index == 1) { return DownButton; } return null; } ////// /// public override int GetChildCount() { return 2; } internal class DirectionButtonAccessibleObject : AccessibleObject { private bool up; private UpDownButtonsAccessibleObject parent; public DirectionButtonAccessibleObject(UpDownButtonsAccessibleObject parent, bool up) { this.parent = parent; this.up = up; } public override Rectangle Bounds { get { // Get button bounds // Rectangle bounds = ((UpDownButtons)parent.Owner).Bounds; bounds.Height /= 2; if (!up) { bounds.Y += bounds.Height; } // Convert to screen co-ords // return (((UpDownButtons)parent.Owner).ParentInternal).RectangleToScreen(bounds); } } public override string Name { get { if (up) { return SR.GetString(SR.UpDownBaseUpButtonAccName); } return SR.GetString(SR.UpDownBaseDownButtonAccName); } set { } } public override AccessibleObject Parent { [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] get { return parent; } } public override AccessibleRole Role { get { return AccessibleRole.PushButton; } } } } } // end class UpDownButtons // Button identifiers internal enum ButtonID { None = 0, Up = 1, Down = 2, } } // end class UpDownBase } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- RectangleGeometry.cs
- OleDbWrapper.cs
- BeginStoryboard.cs
- ComNativeDescriptor.cs
- IsolatedStorageFile.cs
- RegexGroupCollection.cs
- SyndicationDeserializer.cs
- AnchoredBlock.cs
- TableDesigner.cs
- SocketAddress.cs
- DropDownButton.cs
- ParallelTimeline.cs
- TextServicesHost.cs
- SettingsProperty.cs
- ProcessHostMapPath.cs
- WindowsSlider.cs
- XmlSiteMapProvider.cs
- Select.cs
- WizardForm.cs
- CodeThrowExceptionStatement.cs
- JavaScriptString.cs
- DodSequenceMerge.cs
- WebPartCollection.cs
- ConnectivityStatus.cs
- MinimizableAttributeTypeConverter.cs
- log.cs
- HtmlShimManager.cs
- NetworkInterface.cs
- WebPartHelpVerb.cs
- OptionalColumn.cs
- SmtpAuthenticationManager.cs
- FormsAuthenticationConfiguration.cs
- MenuItem.cs
- SemanticResultKey.cs
- ItemDragEvent.cs
- PeerNearMe.cs
- TranslateTransform3D.cs
- RegexTree.cs
- PerfCounterSection.cs
- SchemaNamespaceManager.cs
- ArgumentOutOfRangeException.cs
- ArgIterator.cs
- BindingContext.cs
- DrawingGroupDrawingContext.cs
- FixedPage.cs
- CodeTypeDeclarationCollection.cs
- BindingExpressionBase.cs
- XXXOnTypeBuilderInstantiation.cs
- DelayedRegex.cs
- DetailsViewRowCollection.cs
- Keywords.cs
- PropertyEmitterBase.cs
- DataGridDetailsPresenterAutomationPeer.cs
- ping.cs
- RegexStringValidator.cs
- BezierSegment.cs
- OracleBinary.cs
- RepeatBehaviorConverter.cs
- EdmTypeAttribute.cs
- ValidatorCollection.cs
- ContentPlaceHolder.cs
- ParallelTimeline.cs
- RegistryDataKey.cs
- FormatException.cs
- AudioSignalProblemOccurredEventArgs.cs
- PrintDialogException.cs
- PropertyManager.cs
- Cursor.cs
- XmlQueryTypeFactory.cs
- MenuAutomationPeer.cs
- ObjectAnimationUsingKeyFrames.cs
- DirectoryGroupQuery.cs
- StsCommunicationException.cs
- ArraySegment.cs
- ZipQueryOperator.cs
- ObjectReaderCompiler.cs
- OpenCollectionAsyncResult.cs
- PostBackOptions.cs
- PathData.cs
- NullableDoubleMinMaxAggregationOperator.cs
- FormViewDeleteEventArgs.cs
- HtmlInputPassword.cs
- FixedTextView.cs
- TextEndOfLine.cs
- CollectionViewSource.cs
- DynamicMetaObject.cs
- CompiledRegexRunner.cs
- WorkingDirectoryEditor.cs
- TableColumn.cs
- OneOfElement.cs
- NativeMethodsCLR.cs
- HtmlElementCollection.cs
- GraphicsContext.cs
- Content.cs
- ProfileSection.cs
- ProcessRequestArgs.cs
- ProgressChangedEventArgs.cs
- MessageDispatch.cs
- MaskedTextBoxTextEditor.cs
- RowCache.cs