|
//------------------------------------------------------------------------------
// <copyright file="TextBoxBase.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
*/
namespace System.Windows.Forms {
using System.Text;
using System.Runtime.Serialization.Formatters;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Security.Permissions;
using System.Windows.Forms.Design;
using System.Windows.Forms.Layout;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms.Internal;
using System.Drawing.Design;
using Microsoft.Win32;
using System.Reflection;
using System.Globalization;
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase"]/*' />
/// <devdoc>
/// <para>
/// Implements the basic functionality required by text
/// controls.
/// </para>
/// </devdoc>
[
ComVisible(true),
ClassInterface(ClassInterfaceType.AutoDispatch),
DefaultEvent("TextChanged"),
DefaultBindingProperty("Text"),
Designer("System.Windows.Forms.Design.TextBoxBaseDesigner, " + AssemblyRef.SystemDesign)
]
public abstract class TextBoxBase : Control {
// The boolean properties for this control are contained in the textBoxFlags bit
// vector. We can store up to 32 boolean values in this one vector. Here we
// create the bitmasks for each bit in the vector.
//
private static readonly int autoSize = BitVector32.CreateMask();
private static readonly int hideSelection = BitVector32.CreateMask(autoSize);
private static readonly int multiline = BitVector32.CreateMask(hideSelection);
private static readonly int modified = BitVector32.CreateMask(multiline);
private static readonly int readOnly = BitVector32.CreateMask(modified);
private static readonly int acceptsTab = BitVector32.CreateMask(readOnly);
private static readonly int wordWrap = BitVector32.CreateMask(acceptsTab);
private static readonly int creatingHandle = BitVector32.CreateMask(wordWrap);
private static readonly int codeUpdateText = BitVector32.CreateMask(creatingHandle);
private static readonly int shortcutsEnabled = BitVector32.CreateMask(codeUpdateText);
private static readonly int scrollToCaretOnHandleCreated = BitVector32.CreateMask(shortcutsEnabled);
private static readonly int setSelectionOnHandleCreated = BitVector32.CreateMask(scrollToCaretOnHandleCreated);
private static readonly object EVENT_ACCEPTSTABCHANGED = new object();
private static readonly object EVENT_BORDERSTYLECHANGED = new object();
private static readonly object EVENT_HIDESELECTIONCHANGED = new object();
private static readonly object EVENT_MODIFIEDCHANGED = new object();
private static readonly object EVENT_MULTILINECHANGED = new object();
private static readonly object EVENT_READONLYCHANGED = new object();
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.borderStyle"]/*' />
/// <devdoc>
/// The current border for this edit control.
/// </devdoc>
private BorderStyle borderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.maxLength"]/*' />
/// <devdoc>
/// Controls the maximum length of text in the edit control.
/// </devdoc>
private int maxLength = 32767; // Win9X default, used for consistency
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.requestedHeight"]/*' />
/// <devdoc>
/// Used by the autoSizing code to help figure out the desired height of
/// the edit box.
/// </devdoc>
private int requestedHeight;
bool integralHeightAdjust = false;
//these indices are used to cache the values of the selection, by doing this
//if the handle isn't created yet, we don't force a creation.
private int selectionStart = 0;
private int selectionLength = 0;
/// <devdoc>
/// Controls firing of click event (Left click).
/// This is used by TextBox, RichTextBox and MaskedTextBox, code was moved down from TextBox/RichTextBox
/// but cannot make it as default behavior to avoid introducing breaking changes.
/// </devdoc>
private bool doubleClickFired = false;
private static int[] shortcutsToDisable;
// We store all boolean properties in here.
//
private BitVector32 textBoxFlags = new BitVector32();
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.TextBoxBase"]/*' />
/// <devdoc>
/// Creates a new TextBox control. Uses the parent's current font and color
/// set.
/// </devdoc>
internal TextBoxBase() : base() {
// this class overrides GetPreferredSizeCore, let Control automatically cache the result
SetState2(STATE2_USEPREFERREDSIZECACHE, true);
textBoxFlags[autoSize | hideSelection | wordWrap | shortcutsEnabled] = true;
SetStyle(ControlStyles.FixedHeight, textBoxFlags[autoSize]);
SetStyle(ControlStyles.StandardClick
| ControlStyles.StandardDoubleClick
| ControlStyles.UseTextForAccessibility
| ControlStyles.UserPaint, false);
// cache requestedHeight. Note: Control calls DefaultSize (overridable) in the constructor
// to set the control's cached height that is returned when calling Height, so we just
// need to get the cached height here.
requestedHeight = Height;
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.AcceptsTab"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets
/// a value indicating whether pressing the TAB key
/// in a multiline text box control types
/// a TAB character in the control instead of moving the focus to the next control
/// in the tab order.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatBehavior),
DefaultValue(false),
SRDescription(SR.TextBoxAcceptsTabDescr)
]
public bool AcceptsTab {
get {
return textBoxFlags[acceptsTab];
}
set {
if (textBoxFlags[acceptsTab] != value) {
textBoxFlags[acceptsTab] = value;
OnAcceptsTabChanged(EventArgs.Empty);
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.AcceptsTabChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRCategory(SR.CatPropertyChanged), SRDescription(SR.TextBoxBaseOnAcceptsTabChangedDescr)]
public event EventHandler AcceptsTabChanged {
add {
Events.AddHandler(EVENT_ACCEPTSTABCHANGED, value);
}
remove {
Events.RemoveHandler(EVENT_ACCEPTSTABCHANGED, value);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.ShortcutsEnabled"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether the following shortcuts should be enabled or not:
/// Ctrl-Z, Ctrl-C, Ctrl-X, Ctrl-V, Ctrl-A, Ctrl-L, Ctrl-R, Ctrl-E, Ctrl-I, Ctrl-Y,
/// Ctrl-BackSpace, Ctrl-Del, Shift-Del, Shift-Ins.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatBehavior),
DefaultValue(true),
SRDescription(SR.TextBoxShortcutsEnabledDescr)
]
public virtual bool ShortcutsEnabled {
get {
return textBoxFlags[shortcutsEnabled];
}
set {
if (shortcutsToDisable == null) {
shortcutsToDisable = new int[] {(int)Shortcut.CtrlZ, (int)Shortcut.CtrlC, (int)Shortcut.CtrlX,
(int)Shortcut.CtrlV, (int)Shortcut.CtrlA, (int)Shortcut.CtrlL, (int)Shortcut.CtrlR,
(int)Shortcut.CtrlE, (int)Shortcut.CtrlY, (int)Keys.Control + (int)Keys.Back,
(int)Shortcut.CtrlDel, (int)Shortcut.ShiftDel, (int)Shortcut.ShiftIns, (int)Shortcut.CtrlJ};
}
textBoxFlags[shortcutsEnabled] = value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for=TextBoxBase.ProcessCmdKey]/*'/ />
/// <devdoc>
/// Implements the <see cref='System.Windows.Forms.TextBoxBase.ShortcutsEnabled'/> property.
/// </devdoc>
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
// First call parent's ProcessCmdKey, since we don't to eat up
// the shortcut key we are not supported in TextBox.
bool returnedValue = base.ProcessCmdKey(ref msg, keyData);
if (this.ShortcutsEnabled == false) {
foreach (int shortcutValue in shortcutsToDisable) {
if ((int)keyData == shortcutValue ||
(int)keyData == (shortcutValue | (int)Keys.Shift)) {
return true;
}
}
}
//
// There are a few keys that change the alignment of the text, but that
// are not ignored by the native control when the ReadOnly property is set.
// We need to workaround that.
if (textBoxFlags[readOnly]) {
int k = (int)keyData;
if (k == (int)Shortcut.CtrlL // align left
|| k == (int)Shortcut.CtrlR // align right
|| k == (int)Shortcut.CtrlE // align centre
|| k == (int)Shortcut.CtrlJ) { // align justified
return true;
}
}
return returnedValue;
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.AutoSize"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether the size
/// of the control automatically adjusts when the font assigned to the control
/// is changed.
///
/// Note: this works differently than other Controls' AutoSize, so we're hiding
/// it to avoid confusion.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatBehavior),
DefaultValue(true),
Localizable(true),
SRDescription(SR.TextBoxAutoSizeDescr),
RefreshProperties(RefreshProperties.Repaint),
Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public override bool AutoSize {
get {
return textBoxFlags[autoSize];
}
set {
// Note that we intentionally do not call base. TextBoxes size themselves by
// overriding SetBoundsCore (old RTM code). We let CommonProperties.GetAutoSize
// continue to return false to keep our LayoutEngines from messing with TextBoxes.
// This is done for backwards compatibility since the new AutoSize behavior differs.
if (textBoxFlags[autoSize] != value) {
textBoxFlags[autoSize] = value;
// AutoSize's effects are ignored for a multi-line textbox
//
if (!Multiline) {
SetStyle(ControlStyles.FixedHeight, value);
AdjustHeight(false);
}
OnAutoSizeChanged(EventArgs.Empty);
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.BackColor"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets
/// the background color of the control.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatAppearance),
DispId(NativeMethods.ActiveX.DISPID_BACKCOLOR),
SRDescription(SR.ControlBackColorDescr)
]
public override Color BackColor {
get {
if (ShouldSerializeBackColor()) {
return base.BackColor;
}
else if (this.ReadOnly) {
return SystemColors.Control;
} else {
return SystemColors.Window;
}
}
set {
base.BackColor = value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.BackgroundImage"]/*' />
/// <internalonly/>
/// <devdoc>
/// </devdoc>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public override Image BackgroundImage {
get {
return base.BackgroundImage;
}
set {
base.BackgroundImage = value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.AutoSizeChanged"]/*' />
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler AutoSizeChanged {
add {
base.AutoSizeChanged += value;
}
remove {
base.AutoSizeChanged -= value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.BackgroundImageChanged"]/*' />
/// <internalonly/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler BackgroundImageChanged {
add {
base.BackgroundImageChanged += value;
}
remove {
base.BackgroundImageChanged -= value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.BackgroundImageLayout"]/*' />
/// <internalonly/>
/// <devdoc>
/// </devdoc>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public override ImageLayout BackgroundImageLayout {
get {
return base.BackgroundImageLayout;
}
set {
base.BackgroundImageLayout = value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.BackgroundImageLayoutChanged"]/*' />
/// <internalonly/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler BackgroundImageLayoutChanged {
add {
base.BackgroundImageLayoutChanged += value;
}
remove {
base.BackgroundImageLayoutChanged -= value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.BorderStyle"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the border type
/// of the text box control.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatAppearance),
DefaultValue(BorderStyle.Fixed3D),
DispId(NativeMethods.ActiveX.DISPID_BORDERSTYLE),
SRDescription(SR.TextBoxBorderDescr)
]
public BorderStyle BorderStyle {
get {
return borderStyle;
}
set {
if (borderStyle != value) {
//verify that 'value' is a valid enum type...
//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));
}
borderStyle = value;
UpdateStyles();
RecreateHandle();
// PreferredSize depends on BorderStyle : thru CreateParams.ExStyle in User32!AdjustRectEx.
// So when the BorderStyle changes let the parent of this control know about it.
using(LayoutTransaction.CreateTransactionIf(AutoSize, ParentInternal, this, PropertyNames.BorderStyle)) {
OnBorderStyleChanged(EventArgs.Empty);
}
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.BorderStyleChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRCategory(SR.CatPropertyChanged), SRDescription(SR.TextBoxBaseOnBorderStyleChangedDescr)]
public event EventHandler BorderStyleChanged {
add {
Events.AddHandler(EVENT_BORDERSTYLECHANGED, value);
}
remove {
Events.RemoveHandler(EVENT_BORDERSTYLECHANGED, value);
}
}
internal virtual bool CanRaiseTextChangedEvent {
get {
return true;
}
}
/// <devdoc>
/// Specifies whether the ImeMode can be enabled - See also ImeModeBase.
/// </devdoc>
protected override bool CanEnableIme {
get {
Debug.WriteLineIf( CompModSwitches.ImeMode.Level >= TraceLevel.Info, "Inside get_CanEnableIme(), this = " + this );
Debug.Indent();
bool canEnable = !( this.ReadOnly || this.PasswordProtect ) && base.CanEnableIme;
Debug.WriteLineIf( CompModSwitches.ImeMode.Level >= TraceLevel.Info, "Value = " + canEnable );
Debug.Unindent();
return canEnable;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.CanUndo"]/*' />
/// <devdoc>
/// <para>
/// Gets a value
/// indicating whether the user can undo the previous operation in a text box control.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatBehavior),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.TextBoxCanUndoDescr)
]
public bool CanUndo {
get {
if (IsHandleCreated) {
bool b;
b = unchecked( (int) (long)SendMessage(NativeMethods.EM_CANUNDO, 0, 0)) != 0;
return b;
}
return false;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.CreateParams"]/*' />
/// <internalonly/>
/// <devdoc>
/// <para>
/// 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.
/// </para>
/// </devdoc>
protected override CreateParams CreateParams {
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
get {
CreateParams cp = base.CreateParams;
cp.ClassName = "EDIT";
cp.Style |= NativeMethods.ES_AUTOHSCROLL | NativeMethods.ES_AUTOVSCROLL;
if (!textBoxFlags[hideSelection]) cp.Style |= NativeMethods.ES_NOHIDESEL;
if (textBoxFlags[readOnly]) cp.Style |= NativeMethods.ES_READONLY;
cp.ExStyle &= (~NativeMethods.WS_EX_CLIENTEDGE);
cp.Style &= (~NativeMethods.WS_BORDER);
switch (borderStyle) {
case BorderStyle.Fixed3D:
cp.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE;
break;
case BorderStyle.FixedSingle:
cp.Style |= NativeMethods.WS_BORDER;
break;
}
if (textBoxFlags[multiline]) {
cp.Style |= NativeMethods.ES_MULTILINE;
if (textBoxFlags[wordWrap]) cp.Style &= ~NativeMethods.ES_AUTOHSCROLL;
}
return cp;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.DoubleBuffered"]/*' />
/// <devdoc>
/// This property is overridden and hidden from statement completion
/// on controls that are based on Win32 Native Controls.
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Never)]
protected override bool DoubleBuffered {
get {
return base.DoubleBuffered;
}
set {
base.DoubleBuffered = value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Click"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
public new event EventHandler Click {
add {
base.Click += value;
}
remove {
base.Click -= value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.MouseClick"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
public new event MouseEventHandler MouseClick {
add {
base.MouseClick += value;
}
remove {
base.MouseClick -= value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.DefaultCursor"]/*' />
protected override Cursor DefaultCursor {
get {
return Cursors.IBeam;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.DefaultSize"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
protected override Size DefaultSize {
get {
return new Size(100, PreferredHeight);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.ForeColor"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the foreground color of the control.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatAppearance),
DispId(NativeMethods.ActiveX.DISPID_FORECOLOR),
SRDescription(SR.ControlForeColorDescr)
]
public override Color ForeColor {
get {
if (ShouldSerializeForeColor()) {
return base.ForeColor;
}
else {
return SystemColors.WindowText;
}
}
set {
base.ForeColor = value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.HideSelection"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether the selected
/// text in the text box control remains highlighted when the control loses focus.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatBehavior),
DefaultValue(true),
SRDescription(SR.TextBoxHideSelectionDescr)
]
public bool HideSelection {
get {
return textBoxFlags[hideSelection];
}
set {
if (textBoxFlags[hideSelection] != value) {
textBoxFlags[hideSelection] = value;
RecreateHandle();
OnHideSelectionChanged(EventArgs.Empty);
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.HideSelectionChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRCategory(SR.CatPropertyChanged), SRDescription(SR.TextBoxBaseOnHideSelectionChangedDescr)]
public event EventHandler HideSelectionChanged {
add {
Events.AddHandler(EVENT_HIDESELECTIONCHANGED, value);
}
remove {
Events.RemoveHandler(EVENT_HIDESELECTIONCHANGED, value);
}
}
/// <devdoc>
/// Internal version of ImeMode property. The ImeMode of TextBoxBase controls depend on its IME restricted
/// mode which is determined by the CanEnableIme property which checks whether the control is in Password or
/// ReadOnly mode.
/// </devdoc>
protected override ImeMode ImeModeBase {
get {
if( DesignMode ) {
return base.ImeModeBase;
}
Debug.WriteLineIf( CompModSwitches.ImeMode.Level >= TraceLevel.Info, "Inside get_ImeModeInternal(), this = " + this );
Debug.Indent();
ImeMode imeMode = CanEnableIme ? base.ImeModeBase : ImeMode.Disable;
Debug.WriteLineIf( CompModSwitches.ImeMode.Level >= TraceLevel.Info, "Value = " + imeMode );
Debug.Unindent();
return imeMode;
}
set {
base.ImeModeBase = value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Lines"]/*' />
/// <devdoc>
/// <para>
/// Gets or
/// sets the lines of text in an text box control.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatAppearance),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
MergableProperty(false),
Localizable(true),
SRDescription(SR.TextBoxLinesDescr),
Editor("System.Windows.Forms.Design.StringArrayEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))
]
public string[] Lines {
get {
string text = Text;
ArrayList list = new ArrayList();
int lineStart = 0;
while (lineStart < text.Length) {
int lineEnd = lineStart;
for (; lineEnd < text.Length; lineEnd++) {
char c = text[lineEnd];
if (c == '\r' || c == '\n')
break;
}
string line = text.Substring(lineStart, lineEnd - lineStart);
list.Add(line);
// Treat "\r", "\r\n", and "\n" as new lines
if (lineEnd < text.Length && text[lineEnd] == '\r')
lineEnd++;
if (lineEnd < text.Length && text[lineEnd] == '\n')
lineEnd++;
lineStart = lineEnd;
}
// Corner case -- last character in Text is a new line; need to add blank line to list
if (text.Length > 0 && (text[text.Length - 1] == '\r' || text[text.Length - 1] == '\n'))
list.Add("");
return(string[]) list.ToArray(typeof(string));
}
[
SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters") // We append a new line to the Text property.
// Don't localize the new line character.
]
set {
//unparse this string list...
if (value != null && value.Length > 0) {
// Work Item #40689:
// Using a StringBuilder instead of a String
// speeds things up approx 150 times
StringBuilder text = new StringBuilder(value[0]);
for (int i=1; i < value.Length; ++i) {
text.Append("\r\n");
text.Append(value[i]);
}
Text = text.ToString();
}
else {
Text = "";
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.MaxLength"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the maximum number of
/// characters the user can type into the text box control.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatBehavior),
DefaultValue(32767),
Localizable(true),
SRDescription(SR.TextBoxMaxLengthDescr)
]
public virtual int MaxLength {
get {
return maxLength;
}
set {
if (value < 0) {
throw new ArgumentOutOfRangeException("MaxLength", SR.GetString(SR.InvalidLowBoundArgumentEx, "MaxLength", (value).ToString(CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture)));
}
if (maxLength != value) {
maxLength = value;
UpdateMaxLength();
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Modified"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value that indicates that the text box control has been modified by the user since
/// the control was created or its contents were last set.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatBehavior),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.TextBoxModifiedDescr)
]
public bool Modified {
get {
if (IsHandleCreated) {
bool curState = (0 != unchecked( (int) (long)SendMessage(NativeMethods.EM_GETMODIFY, 0, 0)));
if (textBoxFlags[modified] != curState) {
// VSWhidbey 94719 - raise ModifiedChanged event. See WmReflectCommand for more info.
textBoxFlags[modified] = curState;
OnModifiedChanged(EventArgs.Empty);
}
return curState;
}
else{
return textBoxFlags[modified];
}
}
set {
if (Modified != value) {
if (IsHandleCreated) {
SendMessage(NativeMethods.EM_SETMODIFY, value ? 1 : 0, 0);
// VSWhidbey 94719 - must maintain this state always in order for the
// test in the Get method to work properly.
}
textBoxFlags[modified] = value;
OnModifiedChanged(EventArgs.Empty);
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.ModifiedChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRCategory(SR.CatPropertyChanged), SRDescription(SR.TextBoxBaseOnModifiedChangedDescr)]
public event EventHandler ModifiedChanged {
add {
Events.AddHandler(EVENT_MODIFIEDCHANGED, value);
}
remove {
Events.RemoveHandler(EVENT_MODIFIEDCHANGED, value);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Multiline"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether this
/// is a multiline text box control.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatBehavior),
DefaultValue(false),
Localizable(true),
SRDescription(SR.TextBoxMultilineDescr),
RefreshProperties(RefreshProperties.All)
]
public virtual bool Multiline {
get {
return textBoxFlags[multiline];
}
set {
if (textBoxFlags[multiline] != value) {
using (LayoutTransaction.CreateTransactionIf(AutoSize, ParentInternal, this, PropertyNames.Multiline)) {
textBoxFlags[multiline] = value;
if (value) {
// Multi-line textboxes do not have fixed height
//
SetStyle(ControlStyles.FixedHeight, false);
}
else {
// Single-line textboxes may have fixed height, depending on AutoSize
SetStyle(ControlStyles.FixedHeight, AutoSize);
}
RecreateHandle();
AdjustHeight(false);
OnMultilineChanged(EventArgs.Empty);
}
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.MultilineChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRCategory(SR.CatPropertyChanged), SRDescription(SR.TextBoxBaseOnMultilineChangedDescr)]
public event EventHandler MultilineChanged {
add {
Events.AddHandler(EVENT_MULTILINECHANGED, value);
}
remove {
Events.RemoveHandler(EVENT_MULTILINECHANGED, value);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Padding"]/*' />
/// <devdoc>
/// <para>
/// <para>[To be supplied.]</para>
/// </para>
/// </devdoc>
[
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public new Padding Padding {
get { return base.Padding; }
set { base.Padding = value;}
}
/// <include file='doc\Control.uex' path='docs/doc[@for="Control.PaddingChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRCategory(SR.CatLayout), SRDescription(SR.ControlOnPaddingChangedDescr)
]
public new event EventHandler PaddingChanged {
add {
base.PaddingChanged += value;
}
remove {
base.PaddingChanged -= value;
}
}
/// <devdoc>
/// Determines if the control is in password protect mode. This is overridden in TextBox and
/// MaskedTextBox and is false by default so RichTextBox that doesn't support Password doesn't
/// have to care about this.
/// </devdoc>
virtual internal bool PasswordProtect
{
get {
return false;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.PreferredHeight"]/*' />
/// <devdoc>
/// <para>
/// Returns the preferred
/// height for a single-line text box.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatLayout),
Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.TextBoxPreferredHeightDescr)
]
public int PreferredHeight {
get {
// VSWhidbey 523205: COMPAT we must return the same busted height we did in Everett, even
// if it doesnt take multiline and word wrap into account. For better accuracy and/or wrapping use
// GetPreferredSize instead.
int height = FontHeight;
if (borderStyle != BorderStyle.None) {
height += SystemInformation.GetBorderSizeForDpi(deviceDpi).Height * 4 + 3;
}
return height;
}
}
// GetPreferredSizeCore
// VSWhidbey 523205: This method can return a different value than PreferredHeight! It properly handles
// border style + multiline and wordwrap.
internal override Size GetPreferredSizeCore(Size proposedConstraints)
{
// 3px vertical space is required between the text and the border to keep the last
// line from being clipped.
// This 3 pixel size was added in everett and we do this to maintain compat.
// old everett behavior was FontHeight + [SystemInformation.BorderSize.Height * 4 + 3]
// however the [ ] was only added if borderstyle was not none.
Size bordersAndPadding = SizeFromClientSize(Size.Empty) + Padding.Size;
if (BorderStyle != BorderStyle.None) {
bordersAndPadding += new Size(0, 3);
}
if (BorderStyle == BorderStyle.FixedSingle) {
// VSWhidbey 321520: bump these by 2px to match BorderStyle.Fixed3D - they'll be omitted from the SizeFromClientSize call.
bordersAndPadding.Width +=2;
bordersAndPadding.Height +=2;
}
// Reduce constraints by border/padding size
proposedConstraints -= bordersAndPadding;
// Fit the text to the remaining space
// Fix for Dev10 bug 590621:
// in text box, we don't interpret ampersand (&) as a directive to underscore the character that follows.
TextFormatFlags format = TextFormatFlags.NoPrefix;
if(!Multiline) {
format |= TextFormatFlags.SingleLine;
} else if(WordWrap) {
format |= TextFormatFlags.WordBreak;
}
Size textSize = TextRenderer.MeasureText(this.Text, this.Font, proposedConstraints, format);
// We use this old computation as a lower bound to ensure backwards compatibility.
textSize.Height = Math.Max(textSize.Height, FontHeight);
Size preferredSize = textSize + bordersAndPadding;
return preferredSize;
}
/// <devdoc>
/// Get the currently selected text start position and length. Use this method internally
/// to avoid calling SelectionStart + SelectionLength each of which does essentially the
/// same (save one message round trip).
/// </devdoc>
internal void GetSelectionStartAndLength( out int start, out int length ){
int end = 0;
if( !IsHandleCreated ) {
// It is possible that the cached values are no longer valid if the Text has been changed
// while the control does not have a handle. We need to return valid values. We also need
// to keep the old cached values in case the Text is changed again making the cached values
// valid again. See VSW#495181.
AdjustSelectionStartAndEnd( this.selectionStart, this.selectionLength, out start, out end, -1 );
length = end - start;
}
else {
start = 0;
UnsafeNativeMethods.SendMessage( new HandleRef( this, Handle ), NativeMethods.EM_GETSEL, ref start, ref end );
//Here, we return the max of either 0 or the # returned by
//the windows call. This eliminates a problem on nt4 where
// a huge negative # is being returned.
//
start = Math.Max( 0, start );
// ditto for end
end = Math.Max( 0, end );
if( this.SelectionUsesDbcsOffsetsInWin9x && Marshal.SystemDefaultCharSize == 1 ) {
// When processing EM_GETSEL, EDIT control returns byte offsets instead of character offsets, this
// makes a difference in unicode code pages like Japanese. We need to adjust the offsets.
ToUnicodeOffsets( WindowText, ref start, ref end );
}
length = end - start;
}
#if DEBUG
{
string t = WindowText;
int len;
end = start + length - 1;
if (t == null) {
len = 0;
}
else {
len = t.Length;
}
Debug.Assert(end <= len, "SelectionEnd is outside the set of valid caret positions for the current WindowText (end ="
+ end + ", WindowText.Length =" + len +")");
}
#endif
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.ReadOnly"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether text in the text box is read-only.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatBehavior),
DefaultValue(false),
RefreshProperties(RefreshProperties.Repaint),
SRDescription(SR.TextBoxReadOnlyDescr)
]
public bool ReadOnly {
get {
return textBoxFlags[readOnly];
}
set {
if (textBoxFlags[readOnly] != value) {
textBoxFlags[readOnly] = value;
if (IsHandleCreated) {
SendMessage(NativeMethods.EM_SETREADONLY, value? -1: 0, 0);
}
OnReadOnlyChanged(EventArgs.Empty);
VerifyImeRestrictedModeChanged();
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.ReadOnlyChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRCategory(SR.CatPropertyChanged), SRDescription(SR.TextBoxBaseOnReadOnlyChangedDescr)]
public event EventHandler ReadOnlyChanged {
add {
Events.AddHandler(EVENT_READONLYCHANGED, value);
}
remove {
Events.RemoveHandler(EVENT_READONLYCHANGED, value);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.SelectedText"]/*' />
/// <devdoc>
/// <para>
/// The currently selected text in the control.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatAppearance),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.TextBoxSelectedTextDescr)
]
public virtual string SelectedText {
get {
int selStart, selLength;
GetSelectionStartAndLength( out selStart, out selLength );
return Text.Substring(selStart, selLength);
}
set {
SetSelectedTextInternal(value, true);
}
}
/// <devdoc>
/// Replaces the selected text with the one passed in.
/// </devdoc>
internal virtual void SetSelectedTextInternal(string text, bool clearUndo){
if (!IsHandleCreated) {
CreateHandle();
}
if( text == null ){
text = "";
}
// The EM_LIMITTEXT message limits only the text the user can enter. It does not affect any text
// already in the edit control when the message is sent, nor does it affect the length of the text
// copied to the edit control by the WM_SETTEXT message.
SendMessage(NativeMethods.EM_LIMITTEXT, 0, 0);
if( clearUndo ){
SendMessage(NativeMethods.EM_REPLACESEL, 0, text);
// For consistency with Text, we clear the modified flag
SendMessage(NativeMethods.EM_SETMODIFY, 0, 0);
ClearUndo();
}
else{
SendMessage(NativeMethods.EM_REPLACESEL, /*undoable*/ -1, text);
}
// Re-enable user input.
SendMessage(NativeMethods.EM_LIMITTEXT, maxLength, 0);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.SelectionLength"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the number of characters selected in the text
/// box.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatAppearance),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.TextBoxSelectionLengthDescr)
]
public virtual int SelectionLength {
get {
int start, length;
GetSelectionStartAndLength( out start, out length );
return length;
}
set {
if (value < 0){
throw new ArgumentOutOfRangeException("SelectionLength", SR.GetString(SR.InvalidArgument, "SelectionLength", value.ToString(CultureInfo.CurrentCulture)));
}
int selStart, selLength;
GetSelectionStartAndLength( out selStart, out selLength );
if (value != selLength) {
Select(selStart, value);
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.SelectionStart"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the starting
/// point of text selected in the text
/// box.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatAppearance),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.TextBoxSelectionStartDescr)
]
public int SelectionStart {
get {
int selStart, selLength;
GetSelectionStartAndLength( out selStart, out selLength );
return selStart;
}
set {
if (value < 0){
throw new ArgumentOutOfRangeException("SelectionStart", SR.GetString(SR.InvalidArgument, "SelectionStart", value.ToString(CultureInfo.CurrentCulture)));
}
Select(value, SelectionLength);
}
}
// Call SetSelectionOnHandle inside CreateHandle()
internal virtual bool SetSelectionInCreateHandle {
get {
return true;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Text"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets
/// the current text in the text box.
/// </para>
/// </devdoc>
[
Localizable(true),
Editor("System.ComponentModel.Design.MultilineStringEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))
]
public override string Text {
get {
return base.Text;
}
set {
if (value != base.Text) {
base.Text = value;
if (IsHandleCreated) {
// clear the modified flag
SendMessage(NativeMethods.EM_SETMODIFY, 0, 0);
}
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.TextLength"]/*' />
[Browsable(false)]
public virtual int TextLength {
get {
// Note: Currently Microsoft does not fully support surrogates - VSW#327396. If
// the text contains surrogate characters this property may return incorrect values.
if (IsHandleCreated && Marshal.SystemDefaultCharSize == 2) {
return SafeNativeMethods.GetWindowTextLength(new HandleRef(this, Handle));
}
else {
return Text.Length;
}
}
}
/// <devdoc>
/// Specifies whether the control uses unicode to set/get text selection information (WM_GESEL/WM_SETSEL)
/// in Win9x.
/// </devdoc>
internal virtual bool SelectionUsesDbcsOffsetsInWin9x {
get {
return true;
}
}
// Since setting the WindowText while the handle is created
// generates a WM_COMMAND message, we must trap that case
// and prevent the event from getting fired, or we get
// double "TextChanged" events.
//
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.WindowText"]/*' />
/// <internalonly/>
/// <devdoc>
/// </devdoc>
internal override string WindowText {
get {
return base.WindowText;
}
set {
if (value == null) value = "";
if (!WindowText.Equals(value)) {
textBoxFlags[codeUpdateText] = true;
try {
base.WindowText = value;
}
finally {
textBoxFlags[codeUpdateText] = false;
}
}
}
}
/// <devdoc>
/// For VSWhidbey 325345. In certain circumstances we might have to force
/// text into the window whether or not the text is the same.
/// Make this a method on TextBoxBase rather than RichTextBox (which is the only
/// control that needs this at this point), since we need to set codeUpdateText.
/// </devdoc>
internal void ForceWindowText(string value) {
if (value == null) {
value = "";
}
textBoxFlags[codeUpdateText] = true;
try {
if (IsHandleCreated) {
UnsafeNativeMethods.SetWindowText(new HandleRef(this, Handle), value);
}
else {
if (value.Length == 0) {
Text = null;
}
else {
Text = value;
}
}
}
finally {
textBoxFlags[codeUpdateText] = false;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.WordWrap"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether a
/// multiline text box control automatically wraps words to the beginning of the next
/// line when necessary.
/// </para>
/// </devdoc>
[
SRCategory(SR.CatBehavior),
Localizable(true),
DefaultValue(true),
SRDescription(SR.TextBoxWordWrapDescr)
]
public bool WordWrap {
get {
return textBoxFlags[wordWrap];
}
set {
using (LayoutTransaction.CreateTransactionIf(AutoSize, ParentInternal, this, PropertyNames.WordWrap)) {
if (textBoxFlags[wordWrap] != value) {
textBoxFlags[wordWrap] = value;
RecreateHandle();
}
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.AdjustHeight"]/*' />
/// <devdoc>
/// Adjusts the height of a single-line edit control to match the height of
/// the control's font.
/// </devdoc>
/// <internalonly/>
private void AdjustHeight(bool returnIfAnchored) {
// If we're anchored to two opposite sides of the form, don't adjust the size because
// we'll lose our anchored size by resetting to the requested width.
//
if (returnIfAnchored && (this.Anchor & (AnchorStyles.Top | AnchorStyles.Bottom)) == (AnchorStyles.Top | AnchorStyles.Bottom)) {
return;
}
int saveHeight = requestedHeight;
try {
if (textBoxFlags[autoSize] && !textBoxFlags[multiline]) {
Height = PreferredHeight;
}
else {
int curHeight = Height;
// Changing the font of a multi-line textbox can sometimes cause a painting problem
// The only workaround I can find is to size the textbox big enough for the font, and
// then restore its correct size.
//
if (textBoxFlags[multiline]) {
Height = Math.Max(saveHeight, PreferredHeight + 2); // 2 = fudge factor
}
integralHeightAdjust = true;
try {
Height = saveHeight;
}
finally {
integralHeightAdjust = false;
}
}
}
finally {
requestedHeight = saveHeight;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.AppendText"]/*' />
/// <devdoc>
/// <para>
/// Append text to the current text of text box.
/// </para>
/// </devdoc>
public void AppendText( string text ) {
if (text.Length > 0) {
int selStart, selLength;
GetSelectionStartAndLength( out selStart, out selLength );
try {
// This enables you to use SelectionColor to AppendText in color.
int endOfText = GetEndPosition();
SelectInternal(endOfText, endOfText, endOfText);
SelectedText = text;
}
finally {
// If AppendText is called when the control is docked and the form is minimized,
// all the text will scroll to the top and the control will look empty when the
// form is restored. We work around this by selecting back whatever was originally
// selected when AppendText was called.
if (this.Width == 0 || this.Height == 0) {
this.Select(selStart, selLength);
}
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Clear"]/*' />
/// <devdoc>
/// <para>
/// Clears all text from the text box control.
/// </para>
/// </devdoc>
public void Clear() {
Text = null;
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.ClearUndo"]/*' />
/// <devdoc>
/// <para>
/// Clears information about the most recent operation
/// from the undo buffer of the text box.
/// </para>
/// </devdoc>
public void ClearUndo() {
if (IsHandleCreated) {
SendMessage(NativeMethods.EM_EMPTYUNDOBUFFER, 0, 0);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Copy"]/*' />
/// <devdoc>
/// <para>
/// Copies the current selection in the text box to the Clipboard.
/// </para>
/// </devdoc>
[UIPermission(SecurityAction.Demand, Clipboard=UIPermissionClipboard.OwnClipboard)]
public void Copy() {
SendMessage(NativeMethods.WM_COPY, 0, 0);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.CreateHandle"]/*' />
/// <devdoc>
/// </devdoc>
/// <internalonly/>
protected override void CreateHandle() {
// This "creatingHandle" stuff is to avoid property change events
// when we set the Text property.
textBoxFlags[creatingHandle] = true;
try {
base.CreateHandle();
if (SetSelectionInCreateHandle) {
// send EM_SETSEL message
SetSelectionOnHandle();
}
}
finally {
textBoxFlags[creatingHandle] = false;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Cut"]/*' />
/// <devdoc>
/// <para>
/// Moves the current selection in the text box to the Clipboard.
/// </para>
/// </devdoc>
public void Cut() {
SendMessage(NativeMethods.WM_CUT, 0, 0);
}
/// <devdoc>
/// Returns the text end position (one past the last input character). This property is virtual to allow MaskedTextBox
/// to set the last input char position as opposed to the last char position which may be a mask character.
/// </devdoc>
internal virtual int GetEndPosition(){
// +1 because RichTextBox has this funny EOF pseudo-character after all the text.
return IsHandleCreated ? TextLength + 1 : TextLength;
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.IsInputKey"]/*' />
/// <internalonly/>
/// <devdoc>
/// Overridden to handle TAB key.
/// </devdoc>
protected override bool IsInputKey(Keys keyData) {
if ((keyData & Keys.Alt) != Keys.Alt) {
switch (keyData & Keys.KeyCode) {
case Keys.Tab:
// Single-line RichEd's want tab characters (see WM_GETDLGCODE),
// so we don't ask it
return Multiline && textBoxFlags[acceptsTab] && ((keyData & Keys.Control) == 0);
case Keys.Escape:
if (Multiline)
return false;
break;
case Keys.Back:
if (!this.ReadOnly)
return true;
break;
case Keys.PageUp:
case Keys.PageDown:
case Keys.Home:
case Keys.End:
return true;
// else fall through to base
}
}
return base.IsInputKey(keyData);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.OnHandleCreated"]/*' />
/// <internalonly/>
/// <devdoc>
/// Overridden to update the newly created handle with the settings of the
/// MaxLength and PasswordChar properties.
/// </devdoc>
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
// it's likely here that the create params could have changed
// the border size/etc.
CommonProperties.xClearPreferredSizeCache(this);
AdjustHeight(true);
UpdateMaxLength();
if (textBoxFlags[modified]){
SendMessage(NativeMethods.EM_SETMODIFY, 1, 0);
}
if (textBoxFlags[scrollToCaretOnHandleCreated]) {
ScrollToCaret();
textBoxFlags[scrollToCaretOnHandleCreated] = false;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.OnHandleDestroyed"]/*' />
/// <devdoc>
/// </devdoc>
/// <internalonly/>
protected override void OnHandleDestroyed(EventArgs e) {
textBoxFlags[modified] = Modified;
textBoxFlags[setSelectionOnHandleCreated] = true;
// Update text selection cached values to be restored when recreating the handle.
GetSelectionStartAndLength( out this.selectionStart, out this.selectionLength );
base.OnHandleDestroyed(e);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Paste"]/*' />
/// <devdoc>
/// <para>
/// Replaces the current selection in the text box with the contents of the Clipboard.
/// </para>
/// </devdoc>
[UIPermission(SecurityAction.Demand, Clipboard=UIPermissionClipboard.OwnClipboard)]
public void Paste() {
Debug.WriteLineIf(IntSecurity.SecurityDemand.TraceVerbose, "ClipboardRead Demanded");
IntSecurity.ClipboardRead.Demand();
SendMessage(NativeMethods.WM_PASTE, 0, 0);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.ProcessDialogKey"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.AllWindows)]
protected override bool ProcessDialogKey(Keys keyData) {
Debug.WriteLineIf(ControlKeyboardRouting.TraceVerbose, "TextBoxBase.ProcessDialogKey [" + keyData.ToString() + "]");
Keys keyCode = (Keys)keyData & Keys.KeyCode;
if (keyCode == Keys.Tab && this.AcceptsTab && (keyData & Keys.Control) != 0) {
// When this control accepts Tabs, Ctrl-Tab is treated exactly like Tab.
keyData &= ~Keys.Control;
}
return base.ProcessDialogKey(keyData);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.OnPaint"]/*' />
/// <devdoc>
/// TextBox / RichTextBox Onpaint.
/// </devdoc>
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new event PaintEventHandler Paint {
add {
base.Paint += value;
}
remove {
base.Paint -= value;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.OnAcceptsTabChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected virtual void OnAcceptsTabChanged(EventArgs e) {
EventHandler eh = Events[EVENT_ACCEPTSTABCHANGED] as EventHandler;
if (eh != null) {
eh(this, e);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.OnBorderStyleChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected virtual void OnBorderStyleChanged(EventArgs e) {
EventHandler eh = Events[EVENT_BORDERSTYLECHANGED] as EventHandler;
if (eh != null) {
eh(this, e);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.OnFontChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected override void OnFontChanged(EventArgs e) {
base.OnFontChanged(e);
AdjustHeight(false);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.OnHideSelectionChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected virtual void OnHideSelectionChanged(EventArgs e) {
EventHandler eh = Events[EVENT_HIDESELECTIONCHANGED] as EventHandler;
if (eh != null) {
eh(this, e);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.OnModifiedChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected virtual void OnModifiedChanged(EventArgs e) {
EventHandler eh = Events[EVENT_MODIFIEDCHANGED] as EventHandler;
if (eh != null) {
eh(this, e);
}
}
/// <devdoc>
/// Raises the MouseUp event.
/// </devdoc>
protected override void OnMouseUp(MouseEventArgs mevent) {
Point pt = PointToScreen(mevent.Location);
if (mevent.Button == MouseButtons.Left) {
if (!ValidationCancelled && UnsafeNativeMethods.WindowFromPoint(pt.X, pt.Y) == Handle) {
if (!this.doubleClickFired) {
OnClick(mevent);
OnMouseClick(mevent);
}
else {
this.doubleClickFired = false;
OnDoubleClick(mevent);
OnMouseDoubleClick(mevent);
}
}
this.doubleClickFired = false;
}
base.OnMouseUp(mevent);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.OnMultilineChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected virtual void OnMultilineChanged(EventArgs e) {
EventHandler eh = Events[EVENT_MULTILINECHANGED] as EventHandler;
if (eh != null) {
eh(this, e);
}
}
protected override void OnPaddingChanged(EventArgs e) {
base.OnPaddingChanged(e);
AdjustHeight(false);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.OnReadOnlyChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected virtual void OnReadOnlyChanged(EventArgs e) {
EventHandler eh = Events[EVENT_READONLYCHANGED] as EventHandler;
if (eh != null) {
eh(this, e);
}
}
protected override void OnTextChanged(EventArgs e) {
// since AutoSize existed in Everett, (and is the default) we can't
// relayout the parent when the "preferredsize" of the control changes.
// this means a multiline = true textbox wont natrually grow in height when
// the text changes.
CommonProperties.xClearPreferredSizeCache(this);
base.OnTextChanged(e);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.GetCharFromPosition"]/*' />
/// <devdoc>
/// Returns the character nearest to the given point.
/// </devdoc>
public virtual char GetCharFromPosition(Point pt) {
string t = this.Text;
int index = GetCharIndexFromPosition(pt);
return (index < 0 || index >= t.Length) ? (char)0 : t[index];
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.GetCharIndexFromPosition"]/*' />
/// <devdoc>
/// Returns the index of the character nearest to the given point.
/// </devdoc>
public virtual int GetCharIndexFromPosition(Point pt) {
int longPoint = NativeMethods.Util.MAKELONG(pt.X, pt.Y);
int index = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.EM_CHARFROMPOS, 0, longPoint);
index = NativeMethods.Util.LOWORD(index);
if (index < 0) {
index = 0;
}
else {
string t = this.Text;
// EM_CHARFROMPOS will return an invalid number if the last character in the RichEdit
// is a newline.
//
if (index >= t.Length) {
index = Math.Max(t.Length - 1, 0);
}
}
return index;
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.GetLineFromCharIndex"]/*' />
/// <devdoc>
/// Returns the number of the line containing a specified character position
/// in a textbox. Note that this returns the physical line number
/// and not the conceptual line number. For example, if the first conceptual
/// line (line number 0) word-wraps and extends to the second line, and if
/// you pass the index of a overflowed character, GetLineFromCharIndex would
/// return 1 and not 0.
/// </devdoc>
public virtual int GetLineFromCharIndex(int index) {
return unchecked( (int) (long)SendMessage(NativeMethods.EM_LINEFROMCHAR, index, 0));
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.GetPositionFromCharIndex"]/*' />
/// <devdoc>
/// Returns the location of the character at the given index.
/// </devdoc>
public virtual Point GetPositionFromCharIndex(int index) {
if (index < 0 || index >= Text.Length)
return Point.Empty;
int i = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.EM_POSFROMCHAR, index, 0);
return new Point(NativeMethods.Util.SignedLOWORD(i), NativeMethods.Util.SignedHIWORD(i));
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.GetFirstCharIndexFromLine"]/*' />
/// <devdoc>
/// Returns the index of the first character of a given line. Returns -1 of lineNumber is invalid.
/// </devdoc>
public int GetFirstCharIndexFromLine(int lineNumber) {
if (lineNumber < 0) {
throw new ArgumentOutOfRangeException("lineNumber", SR.GetString(SR.InvalidArgument, "lineNumber", lineNumber.ToString(CultureInfo.CurrentCulture)));
}
return unchecked( (int) (long)SendMessage(NativeMethods.EM_LINEINDEX, lineNumber, 0));
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.GetFirstCharIndexofCurrentLine"]/*' />
/// <devdoc>
/// Returns the index of the first character of the line where the caret is.
/// </devdoc>
public int GetFirstCharIndexOfCurrentLine() {
return unchecked( (int) (long)SendMessage(NativeMethods.EM_LINEINDEX, -1, 0));
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.ScrollToCaret"]/*' />
/// <devdoc>
/// Ensures that the caret is visible in the TextBox window, by scrolling the
/// TextBox control surface if necessary.
/// </devdoc>
public void ScrollToCaret() {
if (IsHandleCreated) {
if (String.IsNullOrEmpty(this.WindowText)) {
// If there is no text, then there is no place to go.
return;
}
bool scrolled = false;
object editOle = null;
IntPtr editOlePtr = IntPtr.Zero;
try {
if (UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_GETOLEINTERFACE, 0, out editOle) != 0) {
editOlePtr = Marshal.GetIUnknownForObject(editOle);
if (editOlePtr != IntPtr.Zero) {
IntPtr iTextDocument = IntPtr.Zero;
Guid iiTextDocumentGuid = typeof(UnsafeNativeMethods.ITextDocument).GUID;
try {
Marshal.QueryInterface(editOlePtr, ref iiTextDocumentGuid, out iTextDocument);
UnsafeNativeMethods.ITextDocument textDocument = Marshal.GetObjectForIUnknown(iTextDocument) as UnsafeNativeMethods.ITextDocument;
if (textDocument != null) {
int selStart, selLength;
// vsWhidbey 372764: when the user calls RichTextBox::ScrollToCaret we want the RichTextBox to show as
// much text as possible.
// Here is how we do that:
// 1. We scroll the RichTextBox all the way to the bottom so the last line of text is the last visible line.
// 2. We get the first visible line.
// 3. If the first visible line is smaller than the start of the selection, then we are done:
// The selection fits inside the RichTextBox display rectangle.
// 4. Otherwise, scroll the selection to the top of the RichTextBox.
GetSelectionStartAndLength( out selStart, out selLength );
int selStartLine = GetLineFromCharIndex(selStart);
// 1. Scroll the RichTextBox all the way to the bottom
UnsafeNativeMethods.ITextRange textRange = textDocument.Range(this.WindowText.Length - 1, this.WindowText.Length - 1);
textRange.ScrollIntoView(0); // 0 ==> tomEnd
// 2. Get the first visible line.
int firstVisibleLine = unchecked( (int) (long)SendMessage(NativeMethods.EM_GETFIRSTVISIBLELINE, 0, 0));
// 3. If the first visible line is smaller than the start of the selection, we are done;
if (firstVisibleLine <= selStartLine) {
// we are done
} else {
// 4. Scroll the selection to the top of the RichTextBox
textRange = textDocument.Range(selStart, selStart + selLength);
textRange.ScrollIntoView(32); // 32 ==> tomStart
}
scrolled = true;
}
} finally {
if (iTextDocument != IntPtr.Zero) {
Marshal.Release(iTextDocument);
}
}
}
}
} finally {
if (editOlePtr != IntPtr.Zero) {
Marshal.Release(editOlePtr);
}
}
if (!scrolled) {
SendMessage(NativeMethods.EM_SCROLLCARET, 0, 0);
}
}
else {
textBoxFlags[scrollToCaretOnHandleCreated] = true;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.DeselectAll"]/*' />
/// <devdoc>
/// <para>
/// Sets the SelectionLength to 0.
/// </para>
/// </devdoc>
public void DeselectAll() {
this.SelectionLength = 0;
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Select"]/*' />
/// <devdoc>
/// <para>
/// Selects a range of text in the text box.
/// </para>
/// </devdoc>
public void Select(int start, int length) {
if (start < 0){
throw new ArgumentOutOfRangeException("start", SR.GetString(SR.InvalidArgument, "start", start.ToString(CultureInfo.CurrentCulture)));
}
int textLen = TextLength;
if (start > textLen) {
//We shouldn't allow positive length if you're starting at the end, but
//should allow negative length.
long longLength = Math.Min(0, (long)length + start - textLen);
if (longLength < int.MinValue) {
length = int.MinValue;
}
else {
length = (int)longLength;
}
start = textLen;
}
SelectInternal(start, length, textLen);
}
/// <devdoc>
/// Performs the actual select without doing arg checking.
///
/// Send in -1 for the textLen parameter if you don't have the text
/// length cached when calling this method. It will be computed.
/// But if you do have it cached, please pass it in. This will avoid
/// the expensive call to the TextLength property.
/// </devdoc>
internal virtual void SelectInternal(int start, int length, int textLen) {
//if our handle is created - send message...
if (IsHandleCreated) {
int s, e;
AdjustSelectionStartAndEnd(start, length, out s, out e, textLen);
SendMessage(NativeMethods.EM_SETSEL, s, e);
//
}
else {
//otherwise, wait until handle is created to send this message.
//Store the indices until then...
this.selectionStart = start;
this.selectionLength = length;
textBoxFlags[setSelectionOnHandleCreated] = true;
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.SelectAll"]/*' />
/// <devdoc>
/// <para>
/// Selects all text in the text box.
/// </para>
/// </devdoc>
public void SelectAll() {
int textLen = TextLength;
SelectInternal(0, textLen, textLen);
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.SetBoundsCore"]/*' />
/// <devdoc>
/// Overrides Control.setBoundsCore to enforce autoSize.
/// </devdoc>
/// <internalonly/>
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
if (!integralHeightAdjust && height != Height)
requestedHeight = height;
if (textBoxFlags[autoSize] && !textBoxFlags[multiline])
height = PreferredHeight;
base.SetBoundsCore(x, y, width, height, specified);
}
private static void Swap(ref int n1, ref int n2) {
int temp = n2;
n2 = n1;
n1 = temp;
}
//
// Send in -1 if you don't have the text length cached
// when calling this method. It will be computed. If not,
// please pass in the text length as the last parameter.
// This will avoid the expensive call to the TextLength
// property.
internal void AdjustSelectionStartAndEnd(int selStart, int selLength, out int start, out int end, int textLen) {
start = selStart;
end = 0;
if (start <= -1) {
start = -1;
}
else {
int textLength;
if (textLen >= 0) {
textLength = textLen;
}
else {
textLength = this.TextLength;
}
if (start > textLength) {
start = textLength;
}
checked {
try {
end = start + selLength;
}
catch (OverflowException) {
//Since we overflowed, cap at the max/min value: we'll correct the value below
end = start > 0 ? int.MaxValue : int.MinValue;
}
}
// Make sure end is in range
if (end < 0) {
end = 0;
}
else if (end > textLength) {
end = textLength;
}
if (this.SelectionUsesDbcsOffsetsInWin9x && Marshal.SystemDefaultCharSize == 1) {
// EDIT control expects selection values to be byte offsets instead of character offsets,
// this makes a difference in unicode code pages like Japanese.
// We need to adjust the offsets.
ToDbcsOffsets(WindowText, ref start, ref end);
}
}
}
// Called by CreateHandle or OnHandleCreated
internal void SetSelectionOnHandle() {
Debug.Assert(IsHandleCreated, "Don't call this method until the handle is created.");
if (textBoxFlags[setSelectionOnHandleCreated]) {
textBoxFlags[setSelectionOnHandleCreated] = false;
int start, end;
AdjustSelectionStartAndEnd(this.selectionStart, this.selectionLength, out start, out end, -1);
SendMessage(NativeMethods.EM_SETSEL, start, end);
}
}
/// <devdoc>
/// Converts byte offsset to unicode offsets.
/// When procssing WM_GETSEL/WM_SETSEL, EDIT control works with byte offsets instead of character positions
/// as opposed to RICHEDIT which does it always as character positions.
/// This method is used when handling the WM_GETSEL message.
/// </devdoc>
static void ToUnicodeOffsets(string str, ref int start, ref int end) {
Encoding e = Encoding.Default;
// Acutally, we may get away with this call if we can get the bytes from Win9x. Dont know if it is possible.
// This can be expensive since start/end could be small, but str.Length can be quite big.
byte[] bytes = e.GetBytes(str);
bool swap = start > end;
if (swap) {
Swap(ref start, ref end);
}
// Make sure start and end are within the string
//
if (start < 0){
start = 0;
}
if (start > bytes.Length){
start = bytes.Length;
}
if (end > bytes.Length){
end = bytes.Length;
}
// IMPORTANT: Avoid off-by-1 errors!
// The end value passed in is the character immediately after the last character selected.
int newStart = start == 0 ? 0 : e.GetCharCount(bytes, 0, start);
end = newStart + e.GetCharCount(bytes, start, end - start);
start = newStart;
if (swap){
Swap(ref start, ref end);
}
}
/// <devdoc>
/// Converts unicode offsset to byte offsets.
/// When procssing WM_GETSEL/WM_SETSEL, EDIT control works with byte offsets instead of character positions
/// as opposed to RICHEDIT which does it always as character positions.
/// This method is used when handling the WM_SETSEL message.
/// </devdoc>
static internal void ToDbcsOffsets(string str, ref int start, ref int end) {
Encoding e = Encoding.Default;
bool swap = start > end;
if (swap) {
Swap(ref start, ref end);
}
// Make sure start and end are within the string
//
if (start < 0) {
start = 0;
}
if (start > str.Length) {
start = str.Length;
}
if (end < start) {
end = start;
}
if (end > str.Length) {
end = str.Length;
}
// IMPORTANT: Avoid off-by-1 errors!
// The end value passed in is the character immediately after the last character selected.
int newStart = start == 0 ? 0 : e.GetByteCount(str.Substring(0, start));
end = newStart + e.GetByteCount(str.Substring(start, end - start));
start = newStart;
if (swap) {
Swap(ref start, ref end);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.ToString"]/*' />
/// <devdoc>
/// Provides some interesting information for the TextBox control in
/// String form.
/// </devdoc>
/// <internalonly/>
public override string ToString() {
string s = base.ToString();
string txt = Text;
if (txt.Length > 40) txt = txt.Substring(0, 40) + "...";
return s + ", Text: " + txt.ToString();
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.Undo"]/*' />
/// <devdoc>
/// <para>
/// Undoes the last edit operation in the text box.
/// </para>
/// </devdoc>
public void Undo() {
SendMessage(NativeMethods.EM_UNDO, 0, 0);
}
internal virtual void UpdateMaxLength() {
if (IsHandleCreated) {
SendMessage(NativeMethods.EM_LIMITTEXT, maxLength, 0);
}
}
internal override IntPtr InitializeDCForWmCtlColor (IntPtr dc, int msg)
{
if ((msg == NativeMethods.WM_CTLCOLORSTATIC) && !ShouldSerializeBackColor()) {
// Let the Win32 Edit control handle background colors itself.
// This is necessary because a disabled edit control will display a different
// BackColor than when enabled.
return IntPtr.Zero;
}
else {
return base.InitializeDCForWmCtlColor(dc, msg);
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.WmReflectCommand"]/*' />
/// <devdoc>
/// </devdoc>
/// <internalonly/>
private void WmReflectCommand(ref Message m) {
if (!textBoxFlags[codeUpdateText] && !textBoxFlags[creatingHandle]) {
if (NativeMethods.Util.HIWORD(m.WParam) == NativeMethods.EN_CHANGE && CanRaiseTextChangedEvent) {
OnTextChanged(EventArgs.Empty);
}
else if (NativeMethods.Util.HIWORD(m.WParam) == NativeMethods.EN_UPDATE) {
// VSWhidbey 94719: force update to the Modified property, which will trigger
// ModifiedChanged event handlers
bool force = this.Modified;
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.WmSetFont"]/*' />
/// <devdoc>
/// </devdoc>
/// <internalonly/>
void WmSetFont(ref Message m) {
base.WndProc(ref m);
if (!textBoxFlags[multiline]) {
SendMessage(NativeMethods.EM_SETMARGINS, NativeMethods.EC_LEFTMARGIN | NativeMethods.EC_RIGHTMARGIN, 0);
}
}
void WmGetDlgCode(ref Message m) {
base.WndProc(ref m);
if (AcceptsTab) {
Debug.WriteLineIf(Control.ControlKeyboardRouting.TraceVerbose, "TextBox wants tabs");
m.Result = (IntPtr)(unchecked( (int) (long)m.Result) | NativeMethods.DLGC_WANTTAB);
}
else {
Debug.WriteLineIf(Control.ControlKeyboardRouting.TraceVerbose, "TextBox doesn't want tabs");
m.Result = (IntPtr)(unchecked( (int) (long)m.Result) & ~(NativeMethods.DLGC_WANTTAB | NativeMethods.DLGC_WANTALLKEYS));
}
}
/// <devdoc>
/// Handles the WM_CONTEXTMENU message based on this
/// table:
/// ShortcutsEnabled #1 #2 #3
/// Yes strip context system
/// No strip context N/A
/// </devdoc>
/// <internalonly/>
private void WmTextBoxContextMenu(ref Message m) {
if (ContextMenu != null || ContextMenuStrip != null) {
int x = NativeMethods.Util.SignedLOWORD(m.LParam);
int y = NativeMethods.Util.SignedHIWORD(m.LParam);
Point client;
bool keyboardActivated = false;
// lparam will be exactly -1 when the user invokes the context menu
// with the keyboard.
//
if (unchecked((int)(long)m.LParam) == -1) {
keyboardActivated = true;
client = new Point(Width/2, Height/2);
}
else {
client = PointToClientInternal(new Point(x, y));
}
//
// VisualStudio7 # 156, only show the context menu when clicked in the client area
if (ClientRectangle.Contains( client )) {
if (ContextMenu != null) {
ContextMenu.Show(this, client);
}
else if (ContextMenuStrip != null) {
ContextMenuStrip.ShowInternal(this, client, keyboardActivated);
}
else {
Debug.Fail("contextmenu and contextmenustrip are both null... hmm how did we get here?");
DefWndProc( ref m );
}
}
}
}
/// <include file='doc\TextBoxBase.uex' path='docs/doc[@for="TextBoxBase.WndProc"]/*' />
/// <internalonly/>
/// <devdoc>
/// The control's window procedure. Inheriting classes can override this
/// to add extra functionality, but should not forget to call
/// base.wndProc(m); to ensure the control continues to function properly.
/// </devdoc>
[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case NativeMethods.WM_LBUTTONDBLCLK:
this.doubleClickFired = true;
base.WndProc(ref m);
break;
case NativeMethods.WM_REFLECT + NativeMethods.WM_COMMAND:
WmReflectCommand(ref m);
break;
case NativeMethods.WM_GETDLGCODE:
WmGetDlgCode(ref m);
break;
case NativeMethods.WM_SETFONT:
WmSetFont(ref m);
break;
case NativeMethods.WM_CONTEXTMENU:
if (ShortcutsEnabled) {
//calling base will find ContextMenus in this order:
// 1) ContextMenu 2) ContextMenuStrip 3) SystemMenu
base.WndProc(ref m);
}
else {
// we'll handle this message so we can hide the
// SystemMenu if Context and Strip menus are null
WmTextBoxContextMenu(ref m);
}
break;
default:
base.WndProc(ref m);
break;
}
}
}
}
|