Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / WinForms / Managed / System / WinForms / ToolStripSplitButton.cs / 1 / ToolStripSplitButton.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
namespace System.Windows.Forms {
using System;
using System.Security;
using System.Security.Permissions;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.ComponentModel;
using System.Windows.Forms.Design;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Diagnostics;
using System.Windows.Forms.Layout;
///
///
[
ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip),
DefaultEvent("ButtonClick")
]
public class ToolStripSplitButton : ToolStripDropDownItem {
private ToolStripItem defaultItem = null;
private ToolStripSplitButtonButton splitButtonButton = null;
private Rectangle dropDownButtonBounds = Rectangle.Empty;
private ToolStripSplitButtonButtonLayout splitButtonButtonLayout = null;
private int dropDownButtonWidth = 0;
private int splitterWidth = 1;
private Rectangle splitterBounds = Rectangle.Empty;
private byte openMouseId = 0;
private long lastClickTime = 0;
private const int DEFAULT_DROPDOWN_WIDTH = 11;
private static readonly object EventDefaultItemChanged = new object();
private static readonly object EventButtonClick = new object();
private static readonly object EventButtonDoubleClick = new object();
private static readonly object EventDropDownOpened = new object();
private static readonly object EventDropDownClosed = new object();
///
///
/// Summary of ToolStripSplitButton.
///
public ToolStripSplitButton() {
Initialize(); // all additional work should be done in Initialize
}
public ToolStripSplitButton(string text):base(text,null,(EventHandler)null) {
Initialize();
}
public ToolStripSplitButton(Image image):base(null,image,(EventHandler)null) {
Initialize();
}
public ToolStripSplitButton(string text, Image image):base(text,image,(EventHandler)null) {
Initialize();
}
public ToolStripSplitButton(string text, Image image, EventHandler onClick):base(text,image,onClick) {
Initialize();
}
public ToolStripSplitButton(string text, Image image, EventHandler onClick, string name) :base(text,image,onClick,name){
Initialize();
}
public ToolStripSplitButton(string text, Image image, params ToolStripItem[] dropDownItems):base(text,image,dropDownItems) {
Initialize();
}
[DefaultValue(true)]
public new bool AutoToolTip {
get {
return base.AutoToolTip;
}
set {
base.AutoToolTip = value;
}
}
///
///
/// Summary of ToolStripSplitButton.
///
[Browsable(false)]
public Rectangle ButtonBounds {
get {
//Rectangle bounds = SplitButtonButton.Bounds;
//bounds.Offset(this.Bounds.Location);
return SplitButtonButton.Bounds;
}
}
///
///
/// Summary of ButtonPressed.
///
[Browsable(false)]
public bool ButtonPressed {
get {
return SplitButtonButton.Pressed;
}
}
///
///
/// Summary of ButtonPressed.
///
[Browsable(false)]
public bool ButtonSelected {
get {
return SplitButtonButton.Selected || DropDownButtonPressed;
}
}
///
///
/// Occurs when the button portion of a split button is clicked.
///
[
SRCategory(SR.CatAction),
SRDescription(SR.ToolStripSplitButtonOnButtonClickDescr)
]
public event EventHandler ButtonClick {
add {
Events.AddHandler(EventButtonClick, value);
}
remove {
Events.RemoveHandler(EventButtonClick, value);
}
}
///
///
/// Occurs when the utton portion of a split button is double clicked.
///
[
SRCategory(SR.CatAction),
SRDescription(SR.ToolStripSplitButtonOnButtonDoubleClickDescr)
]
public event EventHandler ButtonDoubleClick {
add {
Events.AddHandler(EventButtonDoubleClick, value);
}
remove {
Events.RemoveHandler(EventButtonDoubleClick, value);
}
}
protected override bool DefaultAutoToolTip {
get {
return true;
}
}
///
///
/// Summary of DefaultItem.
///
[DefaultValue(null), Browsable(false)]
public ToolStripItem DefaultItem {
get {
return defaultItem;
}
set {
if (defaultItem != value) {
OnDefaultItemChanged(new EventArgs());
defaultItem = value;
}
}
}
///
///
/// Occurs when the default item has changed
///
[
SRCategory(SR.CatAction),
SRDescription(SR.ToolStripSplitButtonOnDefaultItemChangedDescr)
]
public event EventHandler DefaultItemChanged {
add {
Events.AddHandler(EventDefaultItemChanged, value);
}
remove {
Events.RemoveHandler(EventDefaultItemChanged, value);
}
}
///
///
/// specifies the default behavior of these items on ToolStripDropDowns when clicked.
///
internal protected override bool DismissWhenClicked {
get {
return DropDown.Visible != true;
}
}
internal override Rectangle DropDownButtonArea {
get { return this.DropDownButtonBounds; }
}
///
///
/// The bounds of the DropDown in ToolStrip coordinates.
///
[Browsable(false)]
public Rectangle DropDownButtonBounds {
get {
return dropDownButtonBounds;
}
}
///
///
/// Summary of DropDownButtonBounds.
///
[Browsable(false)]
public bool DropDownButtonPressed {
get {
//
return DropDown.Visible;
}
}
///
///
/// Summary of DropDownButtonSelected.
///
[Browsable(false)]
public bool DropDownButtonSelected{
get {
return this.Selected;
}
}
///
///
/// Summary of DropDownButtonWidth.
///
[
SRCategory(SR.CatLayout),
SRDescription(SR.ToolStripSplitButtonDropDownButtonWidthDescr)
]
public int DropDownButtonWidth {
get{
return dropDownButtonWidth;
}
set {
if (value < 0) {
// throw if less than 0.
throw new ArgumentOutOfRangeException("DropDownButtonWidth", SR.GetString(SR.InvalidLowBoundArgumentEx, "DropDownButtonWidth", value.ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture)));
}
if (dropDownButtonWidth != value) {
dropDownButtonWidth = value;
InvalidateSplitButtonLayout();
InvalidateItemLayout(PropertyNames.DropDownButtonWidth, true);
}
}
}
///
/// This is here for serialization purposes.
///
private int DefaultDropDownButtonWidth {
get {
// lets start off with a size roughly equivilant to a combobox dropdown
return DEFAULT_DROPDOWN_WIDTH;
}
}
///
/// Just used as a convenience to help manage layout
///
private ToolStripSplitButtonButton SplitButtonButton {
get {
if (splitButtonButton == null) {
splitButtonButton = new ToolStripSplitButtonButton(this);
}
splitButtonButton.Image = this.Image;
splitButtonButton.Text = this.Text;
splitButtonButton.BackColor = this.BackColor;
splitButtonButton.ForeColor = this.ForeColor;
splitButtonButton.Font = this.Font;
splitButtonButton.ImageAlign = this.ImageAlign;
splitButtonButton.TextAlign = this.TextAlign;
splitButtonButton.TextImageRelation = this.TextImageRelation;
return splitButtonButton;
}
}
///
/// Summary of SplitButtonButtonLayout.
///
internal ToolStripItemInternalLayout SplitButtonButtonLayout {
get {
// For preferred size caching reasons, we need to keep our two
// internal layouts (button, dropdown button) in [....].
if (InternalLayout != null /*if layout is invalid - calls CreateInternalLayout - which resets splitButtonButtonLayout to null*/
&& splitButtonButtonLayout == null) {
splitButtonButtonLayout = new ToolStripSplitButtonButtonLayout(this);
}
return splitButtonButtonLayout;
}
}
///
///
/// the width of the separator between the default and drop down button
///
[
SRDescription(SR.ToolStripSplitButtonSplitterWidthDescr),
SRCategory(SR.CatLayout),
Browsable(false),
EditorBrowsable(EditorBrowsableState.Advanced)
]
internal int SplitterWidth {
get {
return splitterWidth;
}
set {
if (value < 0) {
splitterWidth = 0;
}
else {
splitterWidth = value;
}
InvalidateSplitButtonLayout();
}
}
///
///
/// the boundaries of the separator between the default and drop down button, exposed for custom
/// painting purposes.
///
[Browsable(false)]
public Rectangle SplitterBounds {
get {
return splitterBounds;
}
}
///
/// Summary of CalculateLayout.
///
private void CalculateLayout() {
// Figure out where the DropDown image goes.
Rectangle dropDownButtonBounds = new Rectangle(Point.Empty, this.Size);
Rectangle splitButtonButtonBounds = Rectangle.Empty;
dropDownButtonBounds = new Rectangle(Point.Empty, new Size(Math.Min(this.Width, DropDownButtonWidth), this.Height));
// Figure out the height and width of the selected item.
int splitButtonButtonWidth = Math.Max(0, this.Width - dropDownButtonBounds.Width);
int splitButtonButtonHeight = Math.Max(0, this.Height);
splitButtonButtonBounds = new Rectangle(Point.Empty, new Size(splitButtonButtonWidth, splitButtonButtonHeight));
// grow the selected item by one since we're overlapping the borders.
splitButtonButtonBounds.Width -= splitterWidth;
if (this.RightToLeft == RightToLeft.No) {
// the dropdown button goes on the right
dropDownButtonBounds.Offset(splitButtonButtonBounds.Right+splitterWidth, 0);
splitterBounds = new Rectangle(splitButtonButtonBounds.Right, splitButtonButtonBounds.Top, splitterWidth, splitButtonButtonBounds.Height);
}
else {
// the split button goes on the right.
splitButtonButtonBounds.Offset(DropDownButtonWidth+splitterWidth, 0);
splitterBounds = new Rectangle(dropDownButtonBounds.Right, dropDownButtonBounds.Top, splitterWidth, dropDownButtonBounds.Height);
}
this.SplitButtonButton.SetBounds(splitButtonButtonBounds);
this.SetDropDownButtonBounds(dropDownButtonBounds);
}
protected override AccessibleObject CreateAccessibilityInstance() {
return new ToolStripSplitButtonAccessibleObject(this);
}
protected override ToolStripDropDown CreateDefaultDropDown() {
// AutoGenerate a Winbar DropDown - set the property so we hook events
return new ToolStripDropDownMenu(this, /*isAutoGenerated=*/true);
}
internal override ToolStripItemInternalLayout CreateInternalLayout() {
// whenever the master layout is invalidated - invalidate the splitbuttonbutton layout.
this.splitButtonButtonLayout = null;
return new ToolStripItemInternalLayout(this);
}
///
public override Size GetPreferredSize(Size constrainingSize) {
Size preferredSize = SplitButtonButtonLayout.GetPreferredSize(constrainingSize);
preferredSize.Width += DropDownButtonWidth + SplitterWidth + Padding.Horizontal;
return preferredSize;
}
///
/// Summary of InvalidateSplitButtonLayout.
///
private void InvalidateSplitButtonLayout() {
this.splitButtonButtonLayout = null;
CalculateLayout();
}
private void Initialize() {
dropDownButtonWidth = DefaultDropDownButtonWidth;
SupportsSpaceKey = true;
}
[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
protected internal override bool ProcessDialogKey(Keys keyData) {
if (Enabled && (keyData == Keys.Enter || (SupportsSpaceKey && keyData == Keys.Space))) {
PerformButtonClick();
return true;
}
return base.ProcessDialogKey(keyData);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] // 'charCode' matches control.cs
[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
protected internal override bool ProcessMnemonic(char charCode) {
// checking IsMnemonic is not necessary - toolstrip does this for us
PerformButtonClick();
return true;
}
///
///
/// called when the button portion of a split button is clicked
/// if there is a default item, this will route the click to the default item
///
protected virtual void OnButtonClick(System.EventArgs e) {
if (DefaultItem != null) {
DefaultItem.FireEvent(ToolStripItemEventType.Click);
}
EventHandler handler = (EventHandler)Events[EventButtonClick];
if (handler != null) handler(this, e);
}
///
///
/// called when the button portion of a split button is double clicked
/// if there is a default item, this will route the double click to the default item
///
public virtual void OnButtonDoubleClick(System.EventArgs e) {
if (DefaultItem != null) {
DefaultItem.FireEvent(ToolStripItemEventType.DoubleClick);
}
EventHandler handler = (EventHandler)Events[EventButtonDoubleClick];
if (handler != null) handler(this,e);
}
///
///
/// Inheriting classes should override this method to handle this event.
///
protected virtual void OnDefaultItemChanged(EventArgs e) {
InvalidateSplitButtonLayout();
if (CanRaiseEvents) {
EventHandler eh = Events[EventDefaultItemChanged] as EventHandler;
if (eh != null) {
eh(this, e);
}
}
}
///
///
/// Summary of OnMouseDown.
///
protected override void OnMouseDown(MouseEventArgs e) {
if (DropDownButtonBounds.Contains(e.Location)) {
if (e.Button == MouseButtons.Left) {
if (!DropDown.Visible) {
Debug.Assert(ParentInternal != null, "Parent is null here, not going to get accurate ID");
openMouseId = (ParentInternal == null) ? (byte)0: ParentInternal.GetMouseId();
this.ShowDropDown(/*mousePress = */true);
}
}
}
else {
SplitButtonButton.Push(true);
}
}
///
///
/// Summary of OnMouseUp.
///
protected override void OnMouseUp(MouseEventArgs e) {
if (!Enabled) {
return;
}
SplitButtonButton.Push(false);
if (DropDownButtonBounds.Contains(e.Location)) {
if (e.Button == MouseButtons.Left) {
if (DropDown.Visible) {
Debug.Assert(ParentInternal != null, "Parent is null here, not going to get accurate ID");
byte closeMouseId = (ParentInternal == null) ? (byte)0: ParentInternal.GetMouseId();
if (closeMouseId != openMouseId) {
openMouseId = 0; // reset the mouse id, we should never get this value from toolstrip.
ToolStripManager.ModalMenuFilter.CloseActiveDropDown(DropDown, ToolStripDropDownCloseReason.AppClicked);
Select();
}
}
}
}
Point clickPoint = new Point(e.X, e.Y);
if ((e.Button == MouseButtons.Left) && this.SplitButtonButton.Bounds.Contains(clickPoint)) {
bool shouldFireDoubleClick = false;
if (DoubleClickEnabled) {
long newTime = DateTime.Now.Ticks;
long deltaTicks = newTime - lastClickTime;
lastClickTime = newTime;
// use >= for cases where the succession of click events is so fast it's not picked up by
// DateTime resolution.
Debug.Assert(deltaTicks >= 0, "why are deltaticks less than zero? thats some mighty fast clicking");
// if we've seen a mouse up less than the double click time ago, we should fire.
if (deltaTicks >= 0 && deltaTicks < DoubleClickTicks) {
shouldFireDoubleClick = true;
}
}
if (shouldFireDoubleClick) {
OnButtonDoubleClick(new System.EventArgs());
// VSWhidbey 486983: if we actually fired DoubleClick - reset the lastClickTime.
lastClickTime = 0;
}
else {
OnButtonClick(new System.EventArgs());
}
}
}
///
protected override void OnMouseLeave(EventArgs e) {
openMouseId = 0; // reset the mouse id, we should never get this value from toolstrip.
SplitButtonButton.Push(false);
base.OnMouseLeave(e);
}
///
///
/// Summary of OnRightToLeftChanged.
///
protected override void OnRightToLeftChanged(EventArgs e) {
base.OnRightToLeftChanged(e);
InvalidateSplitButtonLayout();
}
///
///
/// Summary of OnPaint.
///
///
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {
ToolStripRenderer renderer = this.Renderer;
if (renderer != null) {
InvalidateSplitButtonLayout();
Graphics g = e.Graphics;
renderer.DrawSplitButton(new ToolStripItemRenderEventArgs(g, this));
if ((DisplayStyle & ToolStripItemDisplayStyle.Image) != ToolStripItemDisplayStyle.None) {
renderer.DrawItemImage(new ToolStripItemImageRenderEventArgs(g, this, SplitButtonButtonLayout.ImageRectangle));
}
if ((DisplayStyle & ToolStripItemDisplayStyle.Text) != ToolStripItemDisplayStyle.None) {
renderer.DrawItemText(new ToolStripItemTextRenderEventArgs(g, this, SplitButtonButton.Text, SplitButtonButtonLayout.TextRectangle, this.ForeColor, this.Font, SplitButtonButtonLayout.TextFormat));
}
}
}
public void PerformButtonClick() {
if (Enabled && Available) {
PerformClick();
OnButtonClick(EventArgs.Empty);
}
}
///
///
/// Resets the RightToLeft to be the default.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual void ResetDropDownButtonWidth() {
DropDownButtonWidth = DefaultDropDownButtonWidth;
}
///
/// Summary of SetDropDownBounds.
///
private void SetDropDownButtonBounds(Rectangle rect) {
dropDownButtonBounds = rect;
}
///
/// Determines if the property needs to be persisted.
///
[EditorBrowsable(EditorBrowsableState.Never)]
internal virtual bool ShouldSerializeDropDownButtonWidth() {
return (DropDownButtonWidth != DefaultDropDownButtonWidth);
}
///
/// This class represents the item to the left of the dropdown [ A |v] (e.g the "A")
/// It exists so that we can use our existing methods for text and image layout
/// and have a place to stick certain state information like pushed and selected
/// Note since this is NOT an actual item hosted on the Winbar - it wont get things
/// like MouseOver, wont be laid out by the ToolStrip, etc etc. This is purely internal
/// convenience.
///
private class ToolStripSplitButtonButton : ToolStripButton {
private ToolStripSplitButton owner = null;
public ToolStripSplitButtonButton(ToolStripSplitButton owner) {
this.owner = owner;
}
public override bool Enabled {
get {
return owner.Enabled;
}
set {
// do nothing
}
}
public override ToolStripItemDisplayStyle DisplayStyle {
get {
return owner.DisplayStyle;
}
set {
// do nothing
}
}
public override Padding Padding {
get {
return this.owner.Padding;
}
set {
// do nothing
}
}
public override ToolStripTextDirection TextDirection {
get {
return owner.TextDirection;
}
}
public override Image Image {
get {
if ((owner.DisplayStyle & ToolStripItemDisplayStyle.Image) == ToolStripItemDisplayStyle.Image) {
return owner.Image;
}
else {
return null;
}
}
set {
// do nothing
}
}
public override bool Selected {
get {
if (owner != null) {
return owner.Selected;
}
return base.Selected;
}
}
public override string Text {
get {
if ((owner.DisplayStyle & ToolStripItemDisplayStyle.Text) == ToolStripItemDisplayStyle.Text) {
return owner.Text;
}
else {
return null;
}
}
set {
// do nothing
}
}
}
///
/// This class performs internal layout for the "split button button" portion of a split button.
/// Its main job is to make sure the inner button has the same parent as the split button, so
/// that layout can be performed using the correct graphics context.
///
private class ToolStripSplitButtonButtonLayout : ToolStripItemInternalLayout {
ToolStripSplitButton owner;
public ToolStripSplitButtonButtonLayout(ToolStripSplitButton owner) : base(owner.SplitButtonButton) {
this.owner = owner;
}
protected override ToolStripItem Owner {
get { return owner; }
}
protected override ToolStrip ParentInternal {
get {
return owner.ParentInternal;
}
}
public override Rectangle ImageRectangle {
get {
Rectangle imageRect = base.ImageRectangle;
// translate to ToolStripItem coordinates
imageRect.Offset(owner.SplitButtonButton.Bounds.Location);
return imageRect;
}
}
public override Rectangle TextRectangle {
get {
Rectangle textRect = base.TextRectangle;
// translate to ToolStripItem coordinates
textRect.Offset(owner.SplitButtonButton.Bounds.Location);
return textRect;
}
}
}
///
[SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
public class ToolStripSplitButtonAccessibleObject : ToolStripItem.ToolStripItemAccessibleObject {
private ToolStripSplitButton owner;
public ToolStripSplitButtonAccessibleObject(ToolStripSplitButton item) : base(item) {
owner = item;
}
///
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override void DoDefaultAction() {
owner.PerformButtonClick();
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
namespace System.Windows.Forms {
using System;
using System.Security;
using System.Security.Permissions;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.ComponentModel;
using System.Windows.Forms.Design;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Diagnostics;
using System.Windows.Forms.Layout;
///
///
[
ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip),
DefaultEvent("ButtonClick")
]
public class ToolStripSplitButton : ToolStripDropDownItem {
private ToolStripItem defaultItem = null;
private ToolStripSplitButtonButton splitButtonButton = null;
private Rectangle dropDownButtonBounds = Rectangle.Empty;
private ToolStripSplitButtonButtonLayout splitButtonButtonLayout = null;
private int dropDownButtonWidth = 0;
private int splitterWidth = 1;
private Rectangle splitterBounds = Rectangle.Empty;
private byte openMouseId = 0;
private long lastClickTime = 0;
private const int DEFAULT_DROPDOWN_WIDTH = 11;
private static readonly object EventDefaultItemChanged = new object();
private static readonly object EventButtonClick = new object();
private static readonly object EventButtonDoubleClick = new object();
private static readonly object EventDropDownOpened = new object();
private static readonly object EventDropDownClosed = new object();
///
///
/// Summary of ToolStripSplitButton.
///
public ToolStripSplitButton() {
Initialize(); // all additional work should be done in Initialize
}
public ToolStripSplitButton(string text):base(text,null,(EventHandler)null) {
Initialize();
}
public ToolStripSplitButton(Image image):base(null,image,(EventHandler)null) {
Initialize();
}
public ToolStripSplitButton(string text, Image image):base(text,image,(EventHandler)null) {
Initialize();
}
public ToolStripSplitButton(string text, Image image, EventHandler onClick):base(text,image,onClick) {
Initialize();
}
public ToolStripSplitButton(string text, Image image, EventHandler onClick, string name) :base(text,image,onClick,name){
Initialize();
}
public ToolStripSplitButton(string text, Image image, params ToolStripItem[] dropDownItems):base(text,image,dropDownItems) {
Initialize();
}
[DefaultValue(true)]
public new bool AutoToolTip {
get {
return base.AutoToolTip;
}
set {
base.AutoToolTip = value;
}
}
///
///
/// Summary of ToolStripSplitButton.
///
[Browsable(false)]
public Rectangle ButtonBounds {
get {
//Rectangle bounds = SplitButtonButton.Bounds;
//bounds.Offset(this.Bounds.Location);
return SplitButtonButton.Bounds;
}
}
///
///
/// Summary of ButtonPressed.
///
[Browsable(false)]
public bool ButtonPressed {
get {
return SplitButtonButton.Pressed;
}
}
///
///
/// Summary of ButtonPressed.
///
[Browsable(false)]
public bool ButtonSelected {
get {
return SplitButtonButton.Selected || DropDownButtonPressed;
}
}
///
///
/// Occurs when the button portion of a split button is clicked.
///
[
SRCategory(SR.CatAction),
SRDescription(SR.ToolStripSplitButtonOnButtonClickDescr)
]
public event EventHandler ButtonClick {
add {
Events.AddHandler(EventButtonClick, value);
}
remove {
Events.RemoveHandler(EventButtonClick, value);
}
}
///
///
/// Occurs when the utton portion of a split button is double clicked.
///
[
SRCategory(SR.CatAction),
SRDescription(SR.ToolStripSplitButtonOnButtonDoubleClickDescr)
]
public event EventHandler ButtonDoubleClick {
add {
Events.AddHandler(EventButtonDoubleClick, value);
}
remove {
Events.RemoveHandler(EventButtonDoubleClick, value);
}
}
protected override bool DefaultAutoToolTip {
get {
return true;
}
}
///
///
/// Summary of DefaultItem.
///
[DefaultValue(null), Browsable(false)]
public ToolStripItem DefaultItem {
get {
return defaultItem;
}
set {
if (defaultItem != value) {
OnDefaultItemChanged(new EventArgs());
defaultItem = value;
}
}
}
///
///
/// Occurs when the default item has changed
///
[
SRCategory(SR.CatAction),
SRDescription(SR.ToolStripSplitButtonOnDefaultItemChangedDescr)
]
public event EventHandler DefaultItemChanged {
add {
Events.AddHandler(EventDefaultItemChanged, value);
}
remove {
Events.RemoveHandler(EventDefaultItemChanged, value);
}
}
///
///
/// specifies the default behavior of these items on ToolStripDropDowns when clicked.
///
internal protected override bool DismissWhenClicked {
get {
return DropDown.Visible != true;
}
}
internal override Rectangle DropDownButtonArea {
get { return this.DropDownButtonBounds; }
}
///
///
/// The bounds of the DropDown in ToolStrip coordinates.
///
[Browsable(false)]
public Rectangle DropDownButtonBounds {
get {
return dropDownButtonBounds;
}
}
///
///
/// Summary of DropDownButtonBounds.
///
[Browsable(false)]
public bool DropDownButtonPressed {
get {
//
return DropDown.Visible;
}
}
///
///
/// Summary of DropDownButtonSelected.
///
[Browsable(false)]
public bool DropDownButtonSelected{
get {
return this.Selected;
}
}
///
///
/// Summary of DropDownButtonWidth.
///
[
SRCategory(SR.CatLayout),
SRDescription(SR.ToolStripSplitButtonDropDownButtonWidthDescr)
]
public int DropDownButtonWidth {
get{
return dropDownButtonWidth;
}
set {
if (value < 0) {
// throw if less than 0.
throw new ArgumentOutOfRangeException("DropDownButtonWidth", SR.GetString(SR.InvalidLowBoundArgumentEx, "DropDownButtonWidth", value.ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture)));
}
if (dropDownButtonWidth != value) {
dropDownButtonWidth = value;
InvalidateSplitButtonLayout();
InvalidateItemLayout(PropertyNames.DropDownButtonWidth, true);
}
}
}
///
/// This is here for serialization purposes.
///
private int DefaultDropDownButtonWidth {
get {
// lets start off with a size roughly equivilant to a combobox dropdown
return DEFAULT_DROPDOWN_WIDTH;
}
}
///
/// Just used as a convenience to help manage layout
///
private ToolStripSplitButtonButton SplitButtonButton {
get {
if (splitButtonButton == null) {
splitButtonButton = new ToolStripSplitButtonButton(this);
}
splitButtonButton.Image = this.Image;
splitButtonButton.Text = this.Text;
splitButtonButton.BackColor = this.BackColor;
splitButtonButton.ForeColor = this.ForeColor;
splitButtonButton.Font = this.Font;
splitButtonButton.ImageAlign = this.ImageAlign;
splitButtonButton.TextAlign = this.TextAlign;
splitButtonButton.TextImageRelation = this.TextImageRelation;
return splitButtonButton;
}
}
///
/// Summary of SplitButtonButtonLayout.
///
internal ToolStripItemInternalLayout SplitButtonButtonLayout {
get {
// For preferred size caching reasons, we need to keep our two
// internal layouts (button, dropdown button) in [....].
if (InternalLayout != null /*if layout is invalid - calls CreateInternalLayout - which resets splitButtonButtonLayout to null*/
&& splitButtonButtonLayout == null) {
splitButtonButtonLayout = new ToolStripSplitButtonButtonLayout(this);
}
return splitButtonButtonLayout;
}
}
///
///
/// the width of the separator between the default and drop down button
///
[
SRDescription(SR.ToolStripSplitButtonSplitterWidthDescr),
SRCategory(SR.CatLayout),
Browsable(false),
EditorBrowsable(EditorBrowsableState.Advanced)
]
internal int SplitterWidth {
get {
return splitterWidth;
}
set {
if (value < 0) {
splitterWidth = 0;
}
else {
splitterWidth = value;
}
InvalidateSplitButtonLayout();
}
}
///
///
/// the boundaries of the separator between the default and drop down button, exposed for custom
/// painting purposes.
///
[Browsable(false)]
public Rectangle SplitterBounds {
get {
return splitterBounds;
}
}
///
/// Summary of CalculateLayout.
///
private void CalculateLayout() {
// Figure out where the DropDown image goes.
Rectangle dropDownButtonBounds = new Rectangle(Point.Empty, this.Size);
Rectangle splitButtonButtonBounds = Rectangle.Empty;
dropDownButtonBounds = new Rectangle(Point.Empty, new Size(Math.Min(this.Width, DropDownButtonWidth), this.Height));
// Figure out the height and width of the selected item.
int splitButtonButtonWidth = Math.Max(0, this.Width - dropDownButtonBounds.Width);
int splitButtonButtonHeight = Math.Max(0, this.Height);
splitButtonButtonBounds = new Rectangle(Point.Empty, new Size(splitButtonButtonWidth, splitButtonButtonHeight));
// grow the selected item by one since we're overlapping the borders.
splitButtonButtonBounds.Width -= splitterWidth;
if (this.RightToLeft == RightToLeft.No) {
// the dropdown button goes on the right
dropDownButtonBounds.Offset(splitButtonButtonBounds.Right+splitterWidth, 0);
splitterBounds = new Rectangle(splitButtonButtonBounds.Right, splitButtonButtonBounds.Top, splitterWidth, splitButtonButtonBounds.Height);
}
else {
// the split button goes on the right.
splitButtonButtonBounds.Offset(DropDownButtonWidth+splitterWidth, 0);
splitterBounds = new Rectangle(dropDownButtonBounds.Right, dropDownButtonBounds.Top, splitterWidth, dropDownButtonBounds.Height);
}
this.SplitButtonButton.SetBounds(splitButtonButtonBounds);
this.SetDropDownButtonBounds(dropDownButtonBounds);
}
protected override AccessibleObject CreateAccessibilityInstance() {
return new ToolStripSplitButtonAccessibleObject(this);
}
protected override ToolStripDropDown CreateDefaultDropDown() {
// AutoGenerate a Winbar DropDown - set the property so we hook events
return new ToolStripDropDownMenu(this, /*isAutoGenerated=*/true);
}
internal override ToolStripItemInternalLayout CreateInternalLayout() {
// whenever the master layout is invalidated - invalidate the splitbuttonbutton layout.
this.splitButtonButtonLayout = null;
return new ToolStripItemInternalLayout(this);
}
///
public override Size GetPreferredSize(Size constrainingSize) {
Size preferredSize = SplitButtonButtonLayout.GetPreferredSize(constrainingSize);
preferredSize.Width += DropDownButtonWidth + SplitterWidth + Padding.Horizontal;
return preferredSize;
}
///
/// Summary of InvalidateSplitButtonLayout.
///
private void InvalidateSplitButtonLayout() {
this.splitButtonButtonLayout = null;
CalculateLayout();
}
private void Initialize() {
dropDownButtonWidth = DefaultDropDownButtonWidth;
SupportsSpaceKey = true;
}
[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
protected internal override bool ProcessDialogKey(Keys keyData) {
if (Enabled && (keyData == Keys.Enter || (SupportsSpaceKey && keyData == Keys.Space))) {
PerformButtonClick();
return true;
}
return base.ProcessDialogKey(keyData);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters")] // 'charCode' matches control.cs
[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
protected internal override bool ProcessMnemonic(char charCode) {
// checking IsMnemonic is not necessary - toolstrip does this for us
PerformButtonClick();
return true;
}
///
///
/// called when the button portion of a split button is clicked
/// if there is a default item, this will route the click to the default item
///
protected virtual void OnButtonClick(System.EventArgs e) {
if (DefaultItem != null) {
DefaultItem.FireEvent(ToolStripItemEventType.Click);
}
EventHandler handler = (EventHandler)Events[EventButtonClick];
if (handler != null) handler(this, e);
}
///
///
/// called when the button portion of a split button is double clicked
/// if there is a default item, this will route the double click to the default item
///
public virtual void OnButtonDoubleClick(System.EventArgs e) {
if (DefaultItem != null) {
DefaultItem.FireEvent(ToolStripItemEventType.DoubleClick);
}
EventHandler handler = (EventHandler)Events[EventButtonDoubleClick];
if (handler != null) handler(this,e);
}
///
///
/// Inheriting classes should override this method to handle this event.
///
protected virtual void OnDefaultItemChanged(EventArgs e) {
InvalidateSplitButtonLayout();
if (CanRaiseEvents) {
EventHandler eh = Events[EventDefaultItemChanged] as EventHandler;
if (eh != null) {
eh(this, e);
}
}
}
///
///
/// Summary of OnMouseDown.
///
protected override void OnMouseDown(MouseEventArgs e) {
if (DropDownButtonBounds.Contains(e.Location)) {
if (e.Button == MouseButtons.Left) {
if (!DropDown.Visible) {
Debug.Assert(ParentInternal != null, "Parent is null here, not going to get accurate ID");
openMouseId = (ParentInternal == null) ? (byte)0: ParentInternal.GetMouseId();
this.ShowDropDown(/*mousePress = */true);
}
}
}
else {
SplitButtonButton.Push(true);
}
}
///
///
/// Summary of OnMouseUp.
///
protected override void OnMouseUp(MouseEventArgs e) {
if (!Enabled) {
return;
}
SplitButtonButton.Push(false);
if (DropDownButtonBounds.Contains(e.Location)) {
if (e.Button == MouseButtons.Left) {
if (DropDown.Visible) {
Debug.Assert(ParentInternal != null, "Parent is null here, not going to get accurate ID");
byte closeMouseId = (ParentInternal == null) ? (byte)0: ParentInternal.GetMouseId();
if (closeMouseId != openMouseId) {
openMouseId = 0; // reset the mouse id, we should never get this value from toolstrip.
ToolStripManager.ModalMenuFilter.CloseActiveDropDown(DropDown, ToolStripDropDownCloseReason.AppClicked);
Select();
}
}
}
}
Point clickPoint = new Point(e.X, e.Y);
if ((e.Button == MouseButtons.Left) && this.SplitButtonButton.Bounds.Contains(clickPoint)) {
bool shouldFireDoubleClick = false;
if (DoubleClickEnabled) {
long newTime = DateTime.Now.Ticks;
long deltaTicks = newTime - lastClickTime;
lastClickTime = newTime;
// use >= for cases where the succession of click events is so fast it's not picked up by
// DateTime resolution.
Debug.Assert(deltaTicks >= 0, "why are deltaticks less than zero? thats some mighty fast clicking");
// if we've seen a mouse up less than the double click time ago, we should fire.
if (deltaTicks >= 0 && deltaTicks < DoubleClickTicks) {
shouldFireDoubleClick = true;
}
}
if (shouldFireDoubleClick) {
OnButtonDoubleClick(new System.EventArgs());
// VSWhidbey 486983: if we actually fired DoubleClick - reset the lastClickTime.
lastClickTime = 0;
}
else {
OnButtonClick(new System.EventArgs());
}
}
}
///
protected override void OnMouseLeave(EventArgs e) {
openMouseId = 0; // reset the mouse id, we should never get this value from toolstrip.
SplitButtonButton.Push(false);
base.OnMouseLeave(e);
}
///
///
/// Summary of OnRightToLeftChanged.
///
protected override void OnRightToLeftChanged(EventArgs e) {
base.OnRightToLeftChanged(e);
InvalidateSplitButtonLayout();
}
///
///
/// Summary of OnPaint.
///
///
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {
ToolStripRenderer renderer = this.Renderer;
if (renderer != null) {
InvalidateSplitButtonLayout();
Graphics g = e.Graphics;
renderer.DrawSplitButton(new ToolStripItemRenderEventArgs(g, this));
if ((DisplayStyle & ToolStripItemDisplayStyle.Image) != ToolStripItemDisplayStyle.None) {
renderer.DrawItemImage(new ToolStripItemImageRenderEventArgs(g, this, SplitButtonButtonLayout.ImageRectangle));
}
if ((DisplayStyle & ToolStripItemDisplayStyle.Text) != ToolStripItemDisplayStyle.None) {
renderer.DrawItemText(new ToolStripItemTextRenderEventArgs(g, this, SplitButtonButton.Text, SplitButtonButtonLayout.TextRectangle, this.ForeColor, this.Font, SplitButtonButtonLayout.TextFormat));
}
}
}
public void PerformButtonClick() {
if (Enabled && Available) {
PerformClick();
OnButtonClick(EventArgs.Empty);
}
}
///
///
/// Resets the RightToLeft to be the default.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual void ResetDropDownButtonWidth() {
DropDownButtonWidth = DefaultDropDownButtonWidth;
}
///
/// Summary of SetDropDownBounds.
///
private void SetDropDownButtonBounds(Rectangle rect) {
dropDownButtonBounds = rect;
}
///
/// Determines if the property needs to be persisted.
///
[EditorBrowsable(EditorBrowsableState.Never)]
internal virtual bool ShouldSerializeDropDownButtonWidth() {
return (DropDownButtonWidth != DefaultDropDownButtonWidth);
}
///
/// This class represents the item to the left of the dropdown [ A |v] (e.g the "A")
/// It exists so that we can use our existing methods for text and image layout
/// and have a place to stick certain state information like pushed and selected
/// Note since this is NOT an actual item hosted on the Winbar - it wont get things
/// like MouseOver, wont be laid out by the ToolStrip, etc etc. This is purely internal
/// convenience.
///
private class ToolStripSplitButtonButton : ToolStripButton {
private ToolStripSplitButton owner = null;
public ToolStripSplitButtonButton(ToolStripSplitButton owner) {
this.owner = owner;
}
public override bool Enabled {
get {
return owner.Enabled;
}
set {
// do nothing
}
}
public override ToolStripItemDisplayStyle DisplayStyle {
get {
return owner.DisplayStyle;
}
set {
// do nothing
}
}
public override Padding Padding {
get {
return this.owner.Padding;
}
set {
// do nothing
}
}
public override ToolStripTextDirection TextDirection {
get {
return owner.TextDirection;
}
}
public override Image Image {
get {
if ((owner.DisplayStyle & ToolStripItemDisplayStyle.Image) == ToolStripItemDisplayStyle.Image) {
return owner.Image;
}
else {
return null;
}
}
set {
// do nothing
}
}
public override bool Selected {
get {
if (owner != null) {
return owner.Selected;
}
return base.Selected;
}
}
public override string Text {
get {
if ((owner.DisplayStyle & ToolStripItemDisplayStyle.Text) == ToolStripItemDisplayStyle.Text) {
return owner.Text;
}
else {
return null;
}
}
set {
// do nothing
}
}
}
///
/// This class performs internal layout for the "split button button" portion of a split button.
/// Its main job is to make sure the inner button has the same parent as the split button, so
/// that layout can be performed using the correct graphics context.
///
private class ToolStripSplitButtonButtonLayout : ToolStripItemInternalLayout {
ToolStripSplitButton owner;
public ToolStripSplitButtonButtonLayout(ToolStripSplitButton owner) : base(owner.SplitButtonButton) {
this.owner = owner;
}
protected override ToolStripItem Owner {
get { return owner; }
}
protected override ToolStrip ParentInternal {
get {
return owner.ParentInternal;
}
}
public override Rectangle ImageRectangle {
get {
Rectangle imageRect = base.ImageRectangle;
// translate to ToolStripItem coordinates
imageRect.Offset(owner.SplitButtonButton.Bounds.Location);
return imageRect;
}
}
public override Rectangle TextRectangle {
get {
Rectangle textRect = base.TextRectangle;
// translate to ToolStripItem coordinates
textRect.Offset(owner.SplitButtonButton.Bounds.Location);
return textRect;
}
}
}
///
[SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
public class ToolStripSplitButtonAccessibleObject : ToolStripItem.ToolStripItemAccessibleObject {
private ToolStripSplitButton owner;
public ToolStripSplitButtonAccessibleObject(ToolStripSplitButton item) : base(item) {
owner = item;
}
///
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public override void DoDefaultAction() {
owner.PerformButtonClick();
}
}
}
}
// 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
- ReflectEventDescriptor.cs
- KeyConstraint.cs
- PathSegmentCollection.cs
- FullTrustAssemblyCollection.cs
- DataReaderContainer.cs
- AuthenticationService.cs
- BreakRecordTable.cs
- ProxyGenerator.cs
- login.cs
- ObjectHelper.cs
- FontStretchConverter.cs
- CompilationPass2TaskInternal.cs
- _UriTypeConverter.cs
- VirtualPath.cs
- ScriptControlManager.cs
- RightNameExpirationInfoPair.cs
- OracleParameterBinding.cs
- HtmlWindow.cs
- CharAnimationBase.cs
- ButtonBase.cs
- ServiceManagerHandle.cs
- ContractReference.cs
- DataSourceCollectionBase.cs
- SeverityFilter.cs
- Enum.cs
- Crypto.cs
- MembershipSection.cs
- ModelItemDictionary.cs
- DetailsViewDeleteEventArgs.cs
- IResourceProvider.cs
- InkPresenter.cs
- ClientOptions.cs
- CRYPTPROTECT_PROMPTSTRUCT.cs
- Random.cs
- CustomErrorCollection.cs
- ProxyGenerator.cs
- FormsAuthenticationUser.cs
- InvalidateEvent.cs
- LinqDataSourceSelectEventArgs.cs
- Connector.cs
- PageAsyncTask.cs
- XmlDomTextWriter.cs
- ListArgumentProvider.cs
- BulletedList.cs
- TextContainerChangeEventArgs.cs
- DisposableCollectionWrapper.cs
- OleDbErrorCollection.cs
- IHttpResponseInternal.cs
- Win32.cs
- TableDesigner.cs
- IOThreadScheduler.cs
- ManagedIStream.cs
- EncoderReplacementFallback.cs
- FixedLineResult.cs
- TransactionBridge.cs
- TraceFilter.cs
- EdmProperty.cs
- DataTable.cs
- AutomationElementIdentifiers.cs
- WorkflowApplicationCompletedException.cs
- selecteditemcollection.cs
- RelationshipEndMember.cs
- FilePresentation.cs
- SQLDateTimeStorage.cs
- HttpListenerResponse.cs
- UInt64Storage.cs
- FunctionNode.cs
- FacetValueContainer.cs
- MsmqReceiveParameters.cs
- XamlPoint3DCollectionSerializer.cs
- WebControlAdapter.cs
- ImpersonationContext.cs
- UnmanagedBitmapWrapper.cs
- ByteStack.cs
- Vector.cs
- InputProcessorProfilesLoader.cs
- MostlySingletonList.cs
- UnaryOperationBinder.cs
- ProxySimple.cs
- DesignTimeResourceProviderFactoryAttribute.cs
- SaveFileDialog.cs
- ConfigDefinitionUpdates.cs
- DataObjectSettingDataEventArgs.cs
- ExtenderProvidedPropertyAttribute.cs
- SvcMapFileLoader.cs
- TickBar.cs
- ViewStateException.cs
- IssuanceLicense.cs
- ByteAnimationBase.cs
- InArgument.cs
- StateDesigner.Layouts.cs
- ProgressBar.cs
- ReadingWritingEntityEventArgs.cs
- TableLayoutSettings.cs
- ActiveXHost.cs
- SystemEvents.cs
- translator.cs
- GeometryDrawing.cs
- DescendentsWalkerBase.cs
- DataViewSettingCollection.cs