Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / CompMod / System / ComponentModel / Design / MultilineStringEditor.cs / 1 / MultilineStringEditor.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.ComponentModel.Design { using System; using System.Collections; using System.ComponentModel; using System.Design; using System.Diagnostics; using System.Drawing; using System.Drawing.Design; using System.Reflection; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Windows.Forms.ComponentModel; using System.Windows.Forms.Design; using System.Security; using System.Security.Permissions; using Microsoft.Win32; using System.Globalization; using System.IO; using System.Runtime.Remoting; using System.Runtime.Serialization.Formatters; using System.Text; using IComDataObject = System.Runtime.InteropServices.ComTypes.IDataObject; ////// /// An editor for editing strings that supports multiple lines of text and is resizable. /// public sealed class MultilineStringEditor : UITypeEditor { private MultilineStringEditorUI _editorUI = null; ////// /// Edits the given value, returning the editing results. /// public override object EditValue (ITypeDescriptorContext context, IServiceProvider provider, object value) { if (provider != null) { IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); if (edSvc != null) { if (_editorUI == null) { _editorUI = new MultilineStringEditorUI(); } _editorUI.BeginEdit(edSvc, value); edSvc.DropDownControl(_editorUI); object newValue = _editorUI.Value; if(_editorUI.EndEdit()) { value = newValue; } } } return value; } ////// /// The MultilineStringEditor is a drop down editor, so this returns UITypeEditorEditStyle.DropDown. /// public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.DropDown; } ////// /// Returns false; no extra painting is performed. /// public override bool GetPaintValueSupported (ITypeDescriptorContext context) { return false; } private class MultilineStringEditorUI : RichTextBox { private IWindowsFormsEditorService _editorService; private bool _editing = false; private bool _escapePressed; // Initialized in BeginEdit private bool _ctrlEnterPressed; SolidBrush _watermarkBrush; private Hashtable _fallbackFonts; private readonly StringFormat _watermarkFormat; // TextBox needs a little space greater than that actualy text content // to display the carent. private const int _caretPadding = 3; // Keep textbox from expanding too close to the edge of the working // area. private const int _workAreaPadding = 16; internal MultilineStringEditorUI() { InitializeComponent(); _watermarkFormat = new StringFormat(); _watermarkFormat.Alignment = StringAlignment.Center; _watermarkFormat.LineAlignment = StringAlignment.Center; _fallbackFonts = new Hashtable(2); } private void InitializeComponent() { this.RichTextShortcutsEnabled = false; this.WordWrap = false; this.BorderStyle = BorderStyle.None; this.Multiline = true; this.ScrollBars = RichTextBoxScrollBars.Both; this.DetectUrls = false; } protected override void Dispose(bool disposing) { if(disposing) { if(_watermarkBrush != null) { _watermarkBrush.Dispose(); _watermarkBrush = null; } } base.Dispose(disposing); } [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] protected override object CreateRichEditOleCallback() { return new OleCallback(this); } protected override bool IsInputKey(Keys keyData) { if ((keyData & Keys.KeyCode) == Keys.Return) { if (Multiline && (keyData & Keys.Alt) == 0) { return true; } } return base.IsInputKey(keyData); } protected override bool ProcessDialogKey(Keys keyData) { if ((keyData & (Keys.Shift | Keys.Alt)) == 0) { switch (keyData & Keys.KeyCode) { case Keys.Escape: if((keyData & Keys.Control) == 0) { // Returned by EndEdit to signal that we should disregard changes. _escapePressed = true; } break; } } return base.ProcessDialogKey(keyData); } protected override void OnKeyDown(KeyEventArgs e) { // NDPWhidbey 32414 - The RichTextBox does not always invalidate the entire client area // unless there is a resize, so if you do a newline before you type enough text to resize the // editor the watermark will be ScrollWindowEx'ed down the screen. To prevent this, we do // a full Invalidate if the watermark is showing when a key is pressed. if(ShouldShowWatermark) { Invalidate(); } // Ask the editor service to ask my parent to close when the user types "Ctrl+Enter". if (e.Control && e.KeyCode == Keys.Return && e.Modifiers == Keys.Control) { _editorService.CloseDropDown(); _ctrlEnterPressed = true; } } internal object Value { get { Debug.Assert(_editing, "Value is only valid between Begin and EndEdit. (Do not want to keep a reference to a large text buffer.)"); return this.Text; } } internal void BeginEdit(IWindowsFormsEditorService editorService, object value) { _editing = true; _editorService = editorService; _minimumSize = Size.Empty; _watermarkSize = Size.Empty; _escapePressed = false; _ctrlEnterPressed = false; this.Text = (string) value; } internal bool EndEdit() { _editing = false; _editorService = null; _ctrlEnterPressed = false; this.Text = null; return !_escapePressed; // If user pressed Esc, return false so we disregard changes. } private void ResizeToContent() { if (!Visible) { return; } Size requestedSize = ContentSize; // AdjustWindowRectEx() does not take the WS_VSCROLL or WS_HSCROLL styles into account. // (See NDPWhidbey #11498). We can not tell when ScrollBars should or shouldn't be visible, // so we always add space for them. requestedSize.Width += SystemInformation.VerticalScrollBarWidth; // NOT USED: requestedSize.Height += SystemInformation.HorizontalScrollBarHeight; // Ensure we do not shrink smaller than our minimum size requestedSize.Width = Math.Max(requestedSize.Width, MinimumSize.Width); Rectangle workingArea = Screen.GetWorkingArea(this); Point location = PointToScreen(this.Location); // DANGER: This assumes we will grow to the left. This is true for propertygrid // (DropDownHolder::OnCurrentControlResize) int maxDelta = location.X - workingArea.Left; // NOTE: If we are shrinking, requestedWidth will be negative, so the Min will not // bound shrinking by maxDelta. This is intentional. int requestedDelta = Math.Min((requestedSize.Width - ClientSize.Width), maxDelta); ClientSize = new Size(ClientSize.Width + requestedDelta, MinimumSize.Height); Debug.Assert(workingArea.Contains(RectangleToScreen(ClientRectangle)), "Failed to keep MultilineStringEditor on screen."); } private Size ContentSize { get { NativeMethods.RECT rect = new NativeMethods.RECT(); HandleRef hdc = new HandleRef(null, UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef)); HandleRef hRtbFont = new HandleRef(null, this.Font.ToHfont()); HandleRef hOldFont = new HandleRef(null, SafeNativeMethods.SelectObject(hdc, hRtbFont)); try { SafeNativeMethods.DrawText(hdc, this.Text, this.Text.Length, ref rect, NativeMethods.DT_CALCRECT); } finally { NativeMethods.ExternalDeleteObject(hRtbFont); SafeNativeMethods.SelectObject(hdc, hOldFont); UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, hdc); } return new Size(rect.right - rect.left + _caretPadding, rect.bottom - rect.top); } } private bool _contentsResizedRaised = false; protected override void OnContentsResized(ContentsResizedEventArgs e) { _contentsResizedRaised = true; ResizeToContent(); base.OnContentsResized(e); } protected override void OnTextChanged(EventArgs e) { // OnContentsResized does not get raised for trailing whitespace. To work // around this, we listen for an OnTextChanged that was not preceeded by // an OnContentsResized. Changing the box size here is more expensive, // however, so we only want to do it when we have to. if(!_contentsResizedRaised) { ResizeToContent(); } _contentsResizedRaised = false; base.OnTextChanged(e); } protected override void OnVisibleChanged(EventArgs e) { if (this.Visible) { ProcessSurrogateFonts(0, this.Text.Length); Select(this.Text.Length, 0); // move caret to the end } ResizeToContent(); base.OnVisibleChanged(e); } private Size _minimumSize = Size.Empty; public override Size MinimumSize { get { if(_minimumSize == Size.Empty) { Rectangle workingArea = Screen.GetWorkingArea(this); _minimumSize = new Size( (int) Math.Min( Math.Ceiling(WatermarkSize.Width * 1.75), workingArea.Width / 4 ), (int) Math.Min( Font.Height * 10, workingArea.Height / 4 ) ); } return _minimumSize; } } public override Font Font { get { return base.Font; } set { return; } } public void ProcessSurrogateFonts(int start, int length){ string value = this.Text; if(value == null) return; int[] surrogates = StringInfo.ParseCombiningCharacters(value); if(surrogates.Length != value.Length) { for(int i=0;i= start && surrogates[i] < start+length) { // only process text in the specified area string fallBackFontName = null; char high = value[surrogates[i]]; char low = (char)0x0000; if(surrogates[i]+1 = 0xD800 && high <= 0xDBFF) { if(low >=0xDC00 && low <= 0xDFFF) { int planeNumber = (high / 0x40) - (0xD800 / 0x40) +1; //plane 0 is the default plane Font replaceFont = _fallbackFonts[planeNumber] as Font; if(replaceFont == null ) { using(RegistryKey regkey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\LanguagePack\SurrogateFallback")) { if(regkey != null) { fallBackFontName = (string)regkey.GetValue("Plane"+planeNumber); if(!string.IsNullOrEmpty(fallBackFontName)) { replaceFont = new Font(fallBackFontName, base.Font.Size, base.Font.Style); } _fallbackFonts[planeNumber] = replaceFont; } } } if(replaceFont != null) { int selectionLength = (i==surrogates.Length-1) ? value.Length-surrogates[i] : surrogates[i+1]-surrogates[i]; base.Select(surrogates[i], selectionLength); this.SelectionFont = replaceFont; } } } } } } } // VSWhidbey 187367: Override the Text property from RichTextBox so that we can get // the window text from this control without doing a StreamOut operation on the control // since StreamOut will cause an IME Composition Window to close unexpectedly. public override string Text { get { if (IsHandleCreated) { int textLen = SafeNativeMethods.GetWindowTextLength(new HandleRef(this, Handle)); StringBuilder sb = new StringBuilder(textLen+1); UnsafeNativeMethods.GetWindowText(new HandleRef(this, Handle), sb, sb.Capacity); if (!_ctrlEnterPressed) { return sb.ToString(); } else { String str = sb.ToString(); int index = str.LastIndexOf("\r\n"); Debug.Assert(index != -1, "We should have found a Ctrl+Enter in the string"); return str.Remove(index, 2); } } else return ""; } set { base.Text = value; } } #region Watermark private Size _watermarkSize = Size.Empty; private Size WatermarkSize { get { if(_watermarkSize == Size.Empty) { SizeF size; // See how much space we should reserve for watermark using(Graphics g = CreateGraphics()) { size = g.MeasureString( SR.GetString(SR.MultilineStringEditorWatermark), this.Font ); } _watermarkSize = new Size((int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height)); } return _watermarkSize; } } private bool ShouldShowWatermark { get { // Do not show watermark if we already have text if (this.Text.Length != 0) { return false; } return WatermarkSize.Width < this.ClientSize.Width; } } private Brush WatermarkBrush { get { if(_watermarkBrush == null) { Color cw = SystemColors.Window; Color ct = SystemColors.WindowText; Color c = Color.FromArgb((Int16)(ct.R * 0.3 + cw.R * 0.7), (Int16)(ct.G * 0.3 + cw.G * 0.7), (Int16)(ct.B * 0.3 + cw.B * 0.7)); _watermarkBrush = new SolidBrush(c); } return _watermarkBrush; } } protected override void WndProc(ref Message m) { base.WndProc(ref m); switch (m.Msg) { case NativeMethods.WM_PAINT: { if(ShouldShowWatermark) { using(Graphics g = CreateGraphics()) { g.DrawString( SR.GetString(SR.MultilineStringEditorWatermark), this.Font, WatermarkBrush, new RectangleF(0.0f, 0.0f, this.ClientSize.Width, this.ClientSize.Height), _watermarkFormat ); } } break; } } } #endregion } // I used the visual basic 6 RichText (REOleCB.CPP) as a guide for this private class OleCallback : UnsafeNativeMethods.IRichTextBoxOleCallback { private RichTextBox owner; bool unrestricted = false; static TraceSwitch richTextDbg; static TraceSwitch RichTextDbg { get { if (richTextDbg == null) { richTextDbg = new TraceSwitch("RichTextDbg", "Debug info about RichTextBox"); } return richTextDbg; } } internal OleCallback(RichTextBox owner) { this.owner = owner; } public int GetNewStorage(out UnsafeNativeMethods.IStorage storage) { Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichTextBoxOleCallback::GetNewStorage"); // Debug.WriteLine("get new storage"); UnsafeNativeMethods.ILockBytes pLockBytes = UnsafeNativeMethods.CreateILockBytesOnHGlobal(NativeMethods.NullHandleRef, true); Debug.Assert(pLockBytes != null, "pLockBytes is NULL!"); storage = UnsafeNativeMethods.StgCreateDocfileOnILockBytes(pLockBytes, NativeMethods.STGM_SHARE_EXCLUSIVE | NativeMethods.STGM_CREATE | NativeMethods.STGM_READWRITE, 0); Debug.Assert(storage != null, "storage is NULL!"); return NativeMethods.S_OK; } public int GetInPlaceContext(IntPtr lplpFrame, IntPtr lplpDoc, IntPtr lpFrameInfo) { Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichTextBoxOleCallback::GetInPlaceContext"); return NativeMethods.E_NOTIMPL; } public int ShowContainerUI(int fShow) { Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichTextBoxOleCallback::ShowContainerUI"); // Do nothing return NativeMethods.S_OK; } public int QueryInsertObject(ref Guid lpclsid, IntPtr lpstg, int cp) { Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichTextBoxOleCallback::QueryInsertObject(" + lpclsid.ToString() + ")"); if (unrestricted) { return NativeMethods.S_OK; } else { Guid realClsid = new Guid(); int hr = UnsafeNativeMethods.ReadClassStg(new HandleRef(null, lpstg), ref realClsid); Debug.WriteLineIf(RichTextDbg.TraceVerbose, "real clsid:" + realClsid.ToString() + " (hr=" + hr.ToString("X", CultureInfo.InvariantCulture) + ")"); if (!NativeMethods.Succeeded(hr)) { return NativeMethods.S_FALSE; } if (realClsid == Guid.Empty) { realClsid = lpclsid; } switch (realClsid.ToString().ToUpper(CultureInfo.InvariantCulture)) { case "00000315-0000-0000-C000-000000000046": // Metafile case "00000316-0000-0000-C000-000000000046": // DIB case "00000319-0000-0000-C000-000000000046": // EMF case "0003000A-0000-0000-C000-000000000046": //BMP return NativeMethods.S_OK; default: Debug.WriteLineIf(RichTextDbg.TraceVerbose, " denying '" + lpclsid.ToString() + "' from being inserted due to security restrictions"); return NativeMethods.S_FALSE; } } } public int DeleteObject(IntPtr lpoleobj) { Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichTextBoxOleCallback::DeleteObject"); // Do nothing return NativeMethods.S_OK; } public int QueryAcceptData(IComDataObject lpdataobj, /* CLIPFORMAT* */ IntPtr lpcfFormat, int reco, int fReally, IntPtr hMetaPict) { Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichTextBoxOleCallback::QueryAcceptData(reco=" + reco + ")"); if (reco == NativeMethods.RECO_PASTE){ DataObject dataObj = new DataObject(lpdataobj); if (dataObj != null && (dataObj.GetDataPresent(DataFormats.Text) || dataObj.GetDataPresent(DataFormats.UnicodeText))) { return NativeMethods.S_OK; } return NativeMethods.E_FAIL; } else { return NativeMethods.E_NOTIMPL; } } public int ContextSensitiveHelp(int fEnterMode) { Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichTextBoxOleCallback::ContextSensitiveHelp"); return NativeMethods.E_NOTIMPL; } public int GetClipboardData(NativeMethods.CHARRANGE lpchrg, int reco, IntPtr lplpdataobj) { Debug.WriteLineIf(RichTextDbg.TraceVerbose, "IRichTextBoxOleCallback::GetClipboardData"); return NativeMethods.E_NOTIMPL; } public int GetDragDropEffect(bool fDrag, int grfKeyState, ref int pdwEffect) { pdwEffect = (int)DragDropEffects.None; return NativeMethods.S_OK; } public int GetContextMenu(short seltype, IntPtr lpoleobj, NativeMethods.CHARRANGE lpchrg, out IntPtr hmenu) { TextBox tb = new TextBox(); tb.Visible = true; ContextMenu cm = tb.ContextMenu; if (cm == null || owner.ShortcutsEnabled == false) hmenu = IntPtr.Zero; else { /*cm.sourceControl = owner; cm.OnPopup(EventArgs.Empty); // RichEd calls DestroyMenu after displaying the context menu IntPtr handle = cm.Handle; // if another control shares the same context menu // then we have to mark the context menu's handles empty because // RichTextBox will delete the menu handles once the popup menu is dismissed. Menu menu = cm; while (true) { int i = 0; int count = menu.ItemCount; for (; i< count; i++) { if (menu.items[i].handle != IntPtr.Zero) { menu = menu.items[i]; break; } } if (i == count) { menu.handle = IntPtr.Zero; menu.created = false; if (menu == cm) break; else menu = ((MenuItem) menu).Menu; } }*/ hmenu = cm.Handle; } return NativeMethods.S_OK; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ListSortDescription.cs
- ExpressionBindings.cs
- ObjectListItemCollection.cs
- TextDocumentView.cs
- DataViewManagerListItemTypeDescriptor.cs
- Help.cs
- entitydatasourceentitysetnameconverter.cs
- RowCache.cs
- CodeObject.cs
- ConcatQueryOperator.cs
- DbTransaction.cs
- KeyboardEventArgs.cs
- StringPropertyBuilder.cs
- AnimationLayer.cs
- RuntimeArgumentHandle.cs
- TimeoutException.cs
- MailAddressCollection.cs
- TableCellCollection.cs
- ViewValidator.cs
- XPathScanner.cs
- MessageBox.cs
- NameValueSectionHandler.cs
- InkCanvasInnerCanvas.cs
- HttpSocketManager.cs
- shaperfactory.cs
- DataSvcMapFile.cs
- BlobPersonalizationState.cs
- TcpTransportManager.cs
- DataGridViewRowHeightInfoPushedEventArgs.cs
- BeginEvent.cs
- CryptoApi.cs
- SiteMapNodeCollection.cs
- ModelUIElement3D.cs
- HtmlElementEventArgs.cs
- PageAsyncTaskManager.cs
- WebPartCatalogCloseVerb.cs
- DefaultValidator.cs
- DataGridViewHeaderCell.cs
- BufferedMessageWriter.cs
- TransformCollection.cs
- TileBrush.cs
- DynamicResourceExtensionConverter.cs
- OracleSqlParser.cs
- ResumeStoryboard.cs
- DataGridViewCellStyle.cs
- MetadataCollection.cs
- Rule.cs
- TextRangeEdit.cs
- DataGridViewAutoSizeModeEventArgs.cs
- HiddenFieldPageStatePersister.cs
- TextChange.cs
- TabletCollection.cs
- InlineCollection.cs
- GuidTagList.cs
- SqlError.cs
- EdmItemError.cs
- OutputCacheProfile.cs
- JsonReaderWriterFactory.cs
- ViewPort3D.cs
- Part.cs
- TabControl.cs
- TemplateField.cs
- HttpWebResponse.cs
- AbstractExpressions.cs
- EmbeddedMailObject.cs
- SchemaObjectWriter.cs
- RepeaterCommandEventArgs.cs
- CombinedTcpChannel.cs
- ColorAnimationBase.cs
- ProxyAttribute.cs
- _ReceiveMessageOverlappedAsyncResult.cs
- ClientScriptManagerWrapper.cs
- IgnoreFileBuildProvider.cs
- TraceContext.cs
- GestureRecognitionResult.cs
- Queue.cs
- ClientUtils.cs
- EdgeModeValidation.cs
- EntitySqlQueryState.cs
- URLAttribute.cs
- TransportOutputChannel.cs
- SchemaComplexType.cs
- DelayDesigner.cs
- ChannelServices.cs
- PointF.cs
- SourceSwitch.cs
- OleDbRowUpdatedEvent.cs
- XmlSchemaImport.cs
- ConcurrencyBehavior.cs
- DocumentApplicationJournalEntry.cs
- Timer.cs
- PolyBezierSegment.cs
- SaveFileDialog.cs
- Double.cs
- GroupStyle.cs
- TrackingStringDictionary.cs
- ACL.cs
- SqlTransaction.cs
- _ProxyChain.cs
- DataListItemEventArgs.cs