public void CreateHtml() { Debug.Assert(this.document == null, "Must call CloseHtml before recreating."); bool created = false; try { // create the trident instance this.document = (NativeMethods.IHTMLDocument2) new NativeMethods.HTMLDocument(); this.oleObject = (NativeMethods.IOleObject) this.document; // hand it our NativeMethods.IOleClientSite implementation this.oleObject.SetClientSite((NativeMethods.IOleClientSite) this); created = true; this.propertyNotifySinkCookie = new NativeMethods.ConnectionPointCookie(this.document, this, typeof(NativeMethods.IPropertyNotifySink), false); this.oleObject.Advise((NativeMethods.IAdviseSink) this, out adviseSinkCookie); Debug.Assert(adviseSinkCookie != 0); this.commandTarget = (NativeMethods.IOleCommandTarget) this.document; } finally { if (created == false) { this.document = null; this.oleObject = null; this.commandTarget = null; } } }
public void CloseHtml() { this.hostControl.Resize -= new EventHandler(this.HostControl_Resize); try { if (this.propertyNotifySinkCookie != null) { this.propertyNotifySinkCookie.Disconnect(); this.propertyNotifySinkCookie = null; } if (this.document != null) { this.documentView = null; this.document = null; this.commandTarget = null; this.activeObject = null; if (adviseSinkCookie != 0) { this.oleObject.Unadvise(adviseSinkCookie); this.adviseSinkCookie = 0; } this.oleObject.Close(NativeMethods.OLECLOSE_NOSAVE); this.oleObject.SetClientSite(null); this.oleObject = null; } } catch (Exception exception) { Debug.Fail(exception.ToString()); } }
private static void CreateControl() { if (null != _tridentControl && null != _htmlBody) { return; } _tridentControl = new MSHTMLHost(); _tridentControl.Size = new Size(CONTROL_WIDTH, CONTROL_HEIGHT); _tridentControl.CreateTrident(); _tridentControl.ActivateTrident(); NativeMethods.IHTMLDocument2 htmlDoc2 = _tridentControl.GetDocument(); _htmlBody = htmlDoc2.GetBody(); }
/// <include file='doc\MSHTMLHost.uex' path='docs/doc[@for="TridentSite.CloseDocument"]/*' /> /// <devdoc> /// Closes the mshtml instance by deactivating and releasing it. /// </devdoc> protected void CloseDocument() { try { if (tridentDocument != null) { tridentView = null; tridentDocument = null; tridentOleObject.Close(NativeMethods.OLECLOSE_NOSAVE); tridentOleObject.SetClientSite(null); tridentOleObject = null; } } catch (Exception e) { Debug.Fail(e.ToString()); } }
/////////////////////////////////////////////////////////////////////////// // Implementation /// <include file='doc\MSHTMLHost.uex' path='docs/doc[@for="TridentSite.CreateDocument"]/*' /> /// <devdoc> /// Creates a new instance of mshtml and initializes it as a new document /// using its IPersistStreamInit. /// </devdoc> protected void CreateDocument() { try { // Create an instance of Trident tridentDocument = (NativeMethods.IHTMLDocument2) new NativeMethods.HTMLDocument(); tridentOleObject = (NativeMethods.IOleObject)tridentDocument; // Initialize its client site tridentOleObject.SetClientSite((NativeMethods.IOleClientSite) this); // Initialize it NativeMethods.IPersistStreamInit psi = (NativeMethods.IPersistStreamInit)tridentDocument; psi.InitNew(); } catch (Exception e) { Debug.Fail(e.ToString()); throw e; } }
/// <include file='doc\CalendarAutoFormatDialog.uex' path='docs/doc[@for="CalendarAutoFormatDialog.UpdateSchemePreview"]/*' /> /// <devdoc> /// Update scheme preview /// </devdoc> /// <internalonly/> private void UpdateSchemePreview() { // create a new calendar and apply the scheme to it Calendar wc = GetPreviewCalendar(); // CONSIDER: Its not safe to create a designer and associate it to // a control that is not site'd... // This should use the runtime control directly and call RenderControl instead. // get the design time HTML IDesigner designer = TypeDescriptor.CreateDesigner(wc, typeof(IDesigner)); designer.Initialize(wc); CalendarDesigner wcd = (CalendarDesigner)designer; string designHTML = wcd.GetDesignTimeHtml(); // and show it! NativeMethods.IHTMLDocument2 tridentDocument = schemePreview.GetDocument(); NativeMethods.IHTMLElement documentElement = tridentDocument.GetBody(); documentElement.SetInnerHTML(designHTML); }
protected override void OnTemplateModeChanged() { base.OnTemplateModeChanged(); if (InTemplateMode) { // Set xmlns in view linked document to show HTML intrinsic // controls in property grid with same schema used by // Intellisense for current choice tag in HTML view. NativeMethods.IHTMLElement htmlElement = (NativeMethods.IHTMLElement)((IControlDesignerBehavior)Behavior).DesignTimeElementView; Debug.Assert(htmlElement != null, "Invalid HTML element in MobileTemplateControlDesigner.OnTemplateModeChanged"); NativeMethods.IHTMLDocument2 htmlDocument2 = (NativeMethods.IHTMLDocument2)htmlElement.GetDocument(); Debug.Assert(htmlDocument2 != null, "Invalid HTML Document2 in MobileTemplateControlDesigner.OnTemplateModeChanged"); NativeMethods.IHTMLElement htmlBody = (NativeMethods.IHTMLElement)htmlDocument2.GetBody(); Debug.Assert(htmlBody != null, "Invalid HTML Body in MobileTemplateControlDesigner.OnTemplateModeChanged"); htmlBody.SetAttribute("xmlns", (Object)CurrentChoice.Xmlns, 0); } }
/// <include file='doc\TemplateEditingFrame.uex' path='docs/doc[@for="TemplateEditingFrame.Initialize"]/*' /> /// <devdoc> /// Initialize from content by creating the necessary HTML element tree structure, etc. /// </devdoc> private void Initialize() { if (this.htmlElemFrame != null) { return; } try { NativeMethods.IHTMLDocument2 htmlDocument = (NativeMethods.IHTMLDocument2)htmlElemParent.GetDocument(); // Create an HTML element that would represent the entire template frame. this.htmlElemFrame = htmlDocument.CreateElement("SPAN"); // Place the provided content within the frame htmlElemFrame.SetInnerHTML(this.Content); // Hold on to the top-level HTML element of the template frame content. NativeMethods.IHTMLDOMNode domNodeFrame = (NativeMethods.IHTMLDOMNode)htmlElemFrame; if (domNodeFrame != null) { this.htmlElemContent = (NativeMethods.IHTMLElement)domNodeFrame.GetFirstChild(); } // Mark the frame as not editable! NativeMethods.IHTMLElement3 htmlElement3 = (NativeMethods.IHTMLElement3)htmlElemFrame; if (htmlElement3 != null) { htmlElement3.SetContentEditable("false"); } // Create an array to hold the HTML elements representing the individual templates. templateElements = new object[templateNames.Length]; Object varName; Object varIndex = (int)0; NativeMethods.IHTMLElementCollection allCollection = (NativeMethods.IHTMLElementCollection)htmlElemFrame.GetAll(); // Obtain all the children of the frame and hold on to the ones representing the templates. for (int i = 0; i < templateNames.Length; i++) { try { varName = templateNames[i]; NativeMethods.IHTMLElement htmlElemTemplate = (NativeMethods.IHTMLElement)allCollection.Item(varName, varIndex); // Set an expando attribute (on the above HTML element) called "TemplateName" // which contains the name of the template it corresponds to. htmlElemTemplate.SetAttribute("templatename", varName, /*lFlags*/ 0); // Place an editable DIV within the individual templates. // This is needed in order for, say, TABLEs, TRs, TDs, etc., to be editable in a // view-linked markup. string editableDIV = "<DIV contentEditable=\"true\" style=\"padding:1;height:100%;width:100%\"></DIV>"; htmlElemTemplate.SetInnerHTML(editableDIV); // The first child of the template element will be the above editable SPAN. NativeMethods.IHTMLDOMNode domNodeTemplate = (NativeMethods.IHTMLDOMNode)htmlElemTemplate; if (domNodeTemplate != null) { templateElements[i] = domNodeTemplate.GetFirstChild(); } } catch (Exception ex) { Debug.Fail(ex.ToString()); templateElements[i] = null; } } // Hold on to the HTML element within which the control name should get displayed. // The presence of this element is optional. varName = "idControlName"; this.htmlElemControlName = (NativeMethods.IHTMLElement)allCollection.Item(varName, varIndex); // Retrieve the HTML element within which the template frame name should be displayed. // The presence of this element is optional. // We also don't hold on to it, since the name of the template frame can't be changed. varName = "idFrameName"; object objFrameName = allCollection.Item(varName, varIndex); if (objFrameName != null) { NativeMethods.IHTMLElement htmlElemFrameName = (NativeMethods.IHTMLElement)objFrameName; htmlElemFrameName.SetInnerText(frameName); } NativeMethods.IHTMLDOMNode domNodeParent = (NativeMethods.IHTMLDOMNode)htmlElemParent; if (domNodeParent == null) { return; } domNodeParent.AppendChild(domNodeFrame); } catch (Exception ex) { Debug.Fail(ex.ToString()); } }
/// <summary> /// Update scheme preview /// </summary> /// <internalonly/> private void UpdateSamplePreview() { if (_firstActivate) { return; } NativeMethods.IHTMLDocument2 tridentDocument = _samplePreview.GetDocument(); NativeMethods.IHTMLElement documentElement = tridentDocument.GetBody(); NativeMethods.IHTMLBodyElement bodyElement; bodyElement = (NativeMethods.IHTMLBodyElement)documentElement; bodyElement.SetScroll("no"); if (SelectedStyle == null) { documentElement.SetInnerHTML(String.Empty); tridentDocument.SetBgColor("buttonface"); return; } else { tridentDocument.SetBgColor(String.Empty); } bool cycle = ReferencesContainCycle(SelectedStyle); if (cycle) { documentElement.SetInnerHTML(String.Empty); return; } // apply the current Style to label ApplyStyle(); DesignerTextWriter tw = new DesignerTextWriter(); //ToolTip tw.AddAttribute("title", ((StyleNode)SelectedStyle).RuntimeStyle.Name); // ForeColor Color c = _previewStyle.ForeColor; if (!c.Equals(Color.Empty)) { tw.AddStyleAttribute("color", ColorTranslator.ToHtml(c)); } // BackColor c = _previewStyle.BackColor; if (!c.Equals(Color.Empty)) { tw.AddStyleAttribute("background-color", ColorTranslator.ToHtml(c)); } // Font Name String name = _previewStyle.Font.Name; if (!name.Equals(String.Empty)) { tw.AddStyleAttribute("font-family", name); } // Font Size switch (_previewStyle.Font.Size) { case FontSize.Large: tw.AddStyleAttribute("font-size", "Medium"); break; case FontSize.Small: tw.AddStyleAttribute("font-size", "X-Small"); break; default: tw.AddStyleAttribute("font-size", "Small"); break; } // Font Style if (_previewStyle.Font.Bold == BooleanOption.True) { tw.AddStyleAttribute("font-weight", "bold"); } if (_previewStyle.Font.Italic == BooleanOption.True) { tw.AddStyleAttribute("font-style", "italic"); } tw.RenderBeginTag("span"); tw.Write(SR.GetString(SR.StylesEditorDialog_PreviewText)); tw.RenderEndTag(); // and show it! String finalHTML = "<div align='center'><table width='100%' height='100%'><tr><td><p align='center'>" + tw.ToString() + "</p></td></tr></table></div>"; documentElement.SetInnerHTML(finalHTML); }
/////////////////////////////////////////////////////////////////////////// // Implementation /// <include file='doc\MSHTMLHost.uex' path='docs/doc[@for="TridentSite.CreateDocument"]/*' /> /// <devdoc> /// Creates a new instance of mshtml and initializes it as a new document /// using its IPersistStreamInit. /// </devdoc> protected void CreateDocument() { try { // Create an instance of Trident tridentDocument = (NativeMethods.IHTMLDocument2)new NativeMethods.HTMLDocument(); tridentOleObject = (NativeMethods.IOleObject)tridentDocument; // Initialize its client site tridentOleObject.SetClientSite((NativeMethods.IOleClientSite)this); // Initialize it NativeMethods.IPersistStreamInit psi = (NativeMethods.IPersistStreamInit)tridentDocument; psi.InitNew(); } catch (Exception e) { Debug.Fail(e.ToString()); throw e; } }
/// <summary>Saves the HTML contained in control to a string and return it.</summary> /// <returns>string - The HTML in the control</returns> public string SaveHtml() { if (!this.IsCreated) { throw new Exception("HtmlControl.SaveHtml : No HTML to save!"); } string content = String.Empty; try { NativeMethods.IHTMLDocument2 document = this.site.Document; // First save the document to a stream NativeMethods.IPersistStreamInit psi = (NativeMethods.IPersistStreamInit)document; Debug.Assert(psi != null, "Expected IPersistStreamInit"); NativeMethods.IStream stream = null; NativeMethods.CreateStreamOnHGlobal(NativeMethods.NullIntPtr, true, out stream); psi.Save(stream, 1); // Now copy the stream to the string NativeMethods.STATSTG stat = new NativeMethods.STATSTG(); stream.Stat(stat, 1); int length = (int)stat.cbSize; byte[] bytes = new byte[length]; IntPtr hglobal; NativeMethods.GetHGlobalFromStream(stream, out hglobal); Debug.Assert(hglobal != NativeMethods.NullIntPtr, "Failed in GetHGlobalFromStream"); // First copy the stream to a byte array IntPtr pointer = NativeMethods.GlobalLock(hglobal); if (pointer != NativeMethods.NullIntPtr) { Marshal.Copy(pointer, bytes, 0, length); NativeMethods.GlobalUnlock(hglobal); // Then create the string from the byte array (use a StreamReader to eat the preamble in the UTF8 encoding case) StreamReader streamReader = null; try { streamReader = new StreamReader(new MemoryStream(bytes), Encoding.Default); content = streamReader.ReadToEnd(); } finally { if (streamReader != null) { streamReader.Close(); } } } } catch (Exception exception) { Debug.Fail("HtmlControl.SaveHtml" + exception.ToString()); content = String.Empty; } finally { } if (content == null) { content = String.Empty; } return(content); /* * HtmlFormatter formatter = new HtmlFormatter(); * StringWriter writer = new StringWriter(); * formatter.Format(content, writer); * return writer.ToString(); */ }
/* * public void LoadHtml(string content, string url) * { * this.LoadHtml(content, url, null); * } */ // REVIEW: Add a load method for stream and url /// <summary> /// Loads HTML content from a string into this control identified by the specified URL. /// If MSHTML has not yet been created, the loading is postponed until MSHTML has been created. /// </summary> /// <param name="content"></param> /// <param name="url"></param> public void LoadHtml(string content, string url) { if (content == null) { content = ""; } if (!this.isCreated) { this.desiredContent = content; this.desiredUrl = url; this.desiredLoad = true; return; } NativeMethods.IStream stream = null; //First we create a COM stream IntPtr hglobal = Marshal.StringToHGlobalUni(content); NativeMethods.CreateStreamOnHGlobal(hglobal, true, out stream); // Initialize a new document if there is nothing to load if (stream == null) { NativeMethods.IPersistStreamInit psi = (NativeMethods.IPersistStreamInit) this.site.Document; Debug.Assert(psi != null, "Expected IPersistStreamInit"); psi.InitNew(); psi = null; } else { NativeMethods.IHTMLDocument2 document = this.site.Document; if (url == null) { // If there is no specified URL load the document from the stream. NativeMethods.IPersistStreamInit psi = (NativeMethods.IPersistStreamInit)document; Debug.Assert(psi != null, "Expected IPersistStreamInit"); psi.Load(stream); psi = null; } else { // Otherwise we create a moniker and load the stream to that moniker. NativeMethods.IPersistMoniker persistMoniker = (NativeMethods.IPersistMoniker)document; NativeMethods.IMoniker moniker = null; NativeMethods.CreateURLMoniker(null, url, out moniker); NativeMethods.IBindCtx bindContext = null; NativeMethods.CreateBindCtx(0, out bindContext); persistMoniker.Load(1, moniker, bindContext, 0); persistMoniker = null; moniker = null; bindContext = null; } } this.url = url; }
/* * public void LoadHtml(string content, string url) * { * this.LoadHtml(content, url, null); * } */ // REVIEW: Add a load method for stream and url /// <summary> /// Loads HTML content from a string into this control identified by the specified URL. /// If MSHTML has not yet been created, the loading is postponed until MSHTML has been created. /// </summary> /// <param name="content"></param> /// <param name="url"></param> public void LoadHtml(string content, string url) { if (content == null) { content = ""; } if (!this.isCreated) { this.desiredContent = content; this.desiredUrl = url; this.desiredLoad = true; return; } NativeMethods.IStream stream = null; // added by Erik Frey - UTF preamble byte[] preamble = UnicodeEncoding.Unicode.GetPreamble(); string byteOrderMark = UnicodeEncoding.Unicode.GetString(preamble, 0, preamble.Length); // i guess .NET 2.0 fixed up unicode string handling if (System.Environment.Version.Major > 1 || !content.StartsWith(byteOrderMark)) { content = byteOrderMark + content; } //First we create a COM stream IntPtr hglobal = Marshal.StringToHGlobalUni(content); NativeMethods.CreateStreamOnHGlobal(hglobal, true, out stream); // Initialize a new document if there is nothing to load if (stream == null) { NativeMethods.IPersistStreamInit psi = (NativeMethods.IPersistStreamInit) this.site.Document; Debug.Assert(psi != null, "Expected IPersistStreamInit"); psi.InitNew(); psi = null; } else { NativeMethods.IHTMLDocument2 document = this.site.Document; if (url == null) { // If there is no specified URL load the document from the stream. NativeMethods.IPersistStreamInit psi = (NativeMethods.IPersistStreamInit)document; Debug.Assert(psi != null, "Expected IPersistStreamInit"); psi.Load(stream); psi = null; } else { // Otherwise we create a moniker and load the stream to that moniker. NativeMethods.IPersistMoniker persistMoniker = (NativeMethods.IPersistMoniker)document; NativeMethods.IMoniker moniker = null; NativeMethods.CreateURLMoniker(null, url, out moniker); NativeMethods.IBindCtx bindContext = null; NativeMethods.CreateBindCtx(0, out bindContext); persistMoniker.Load(1, moniker, bindContext, 0); persistMoniker = null; moniker = null; bindContext = null; } } this.url = url; }
/// <summary>Synchronizes the selection state held in this object with the selection state in MSHTML.</summary> /// <returns>true if the selection has changed</returns> public bool SynchronizeSelection() { if (this.document == null) { this.document = this.control.HtmlDocument; } NativeMethods.IHTMLSelectionObject selection = this.document.GetSelection(); object currentSelection = null; try { currentSelection = selection.CreateRange(); } catch { } ArrayList oldItems = this.items; HtmlSelectionType oldType = this.type; int oldLength = this.selectionLength; // Default to an empty selection this.type = HtmlSelectionType.Empty; this.selectionLength = 0; if (currentSelection != null) { this.selection = currentSelection; this.items = new ArrayList(); //If it's a text selection if (currentSelection is NativeMethods.IHTMLTxtRange) { NativeMethods.IHTMLTxtRange textRange = (NativeMethods.IHTMLTxtRange) currentSelection; NativeMethods.IHTMLElement parentElement = textRange.ParentElement(); // If the document is in full document mode or we're selecting a non-body tag, allow it to select // otherwise, leave the selection as empty (since we don't want the body tag to be selectable on an ASP.NET User Control) if (this.IsSelectableElement(new HtmlElement(parentElement, this.control))) { // Add the parent of the text selection if (parentElement != null) { this.text = textRange.GetText(); if (this.text != null) { this.selectionLength = this.text.Length; } else { this.selectionLength = 0; } this.type = HtmlSelectionType.TextSelection; this.items.Add(parentElement); } } } // If it is a control selection else if (currentSelection is NativeMethods.IHtmlControlRange) { NativeMethods.IHtmlControlRange controlRange = (NativeMethods.IHtmlControlRange) currentSelection; int selectedCount = controlRange.GetLength(); // Add all elements selected if (selectedCount > 0) { this.type = HtmlSelectionType.ElementSelection; for (int i = 0; i < selectedCount; i++) { NativeMethods.IHTMLElement currentElement = controlRange.Item(i); this.items.Add(currentElement); } this.selectionLength = selectedCount; } } } this.sameParentValid = false; bool selectionChanged = false; //Now check if there was a change of selection //If the two selections have different lengths, then the selection has changed if (this.type != oldType) { selectionChanged = true; } else if (this.selectionLength != oldLength) { selectionChanged = true; } else { if (this.items != null) { //If the two selections have a different element, then the selection has changed for (int i = 0; i < this.items.Count; i++) { if (this.items[i] != oldItems[i]) { selectionChanged = true; break; } } } } if (selectionChanged) { //Set this.elements to null so no one can retrieve a dirty copy of the selection element wrappers this.elements = null; OnSelectionChanged(EventArgs.Empty); return true; } return false; }
public void CloseHtml() { this.hostControl.Resize -= new EventHandler(this.HostControl_Resize); try { if (this.propertyNotifySinkCookie != null) { this.propertyNotifySinkCookie.Disconnect(); this.propertyNotifySinkCookie = null; } if (this.document != null) { this.documentView = null; this.document = null; this.commandTarget = null; this.activeObject = null; if (adviseSinkCookie != 0) { this.oleObject.Unadvise(adviseSinkCookie); this.adviseSinkCookie = 0; } this.oleObject.Close(NativeMethods.OLECLOSE_NOSAVE); this.oleObject.SetClientSite(null); this.oleObject = null; } } catch (Exception exception) { Debug.Fail(exception.ToString()); } }
public void CreateHtml() { Debug.Assert(this.document == null, "Must call CloseHtml before recreating."); bool created = false; try { // create the trident instance this.document = (NativeMethods.IHTMLDocument2) new NativeMethods.HTMLDocument(); this.oleObject = (NativeMethods.IOleObject) this.document; // hand it our NativeMethods.IOleClientSite implementation this.oleObject.SetClientSite((NativeMethods.IOleClientSite)this); created = true; this.propertyNotifySinkCookie = new NativeMethods.ConnectionPointCookie(this.document, this, typeof(NativeMethods.IPropertyNotifySink), false); this.oleObject.Advise((NativeMethods.IAdviseSink)this, out adviseSinkCookie); Debug.Assert(adviseSinkCookie != 0); this.commandTarget = (NativeMethods.IOleCommandTarget) this.document; } finally { if (created == false) { this.document = null; this.oleObject = null; this.commandTarget = null; } } }
/// <summary>Synchronizes the selection state held in this object with the selection state in MSHTML.</summary> /// <returns>true if the selection has changed</returns> public bool SynchronizeSelection() { if (this.document == null) { this.document = this.control.HtmlDocument; } NativeMethods.IHTMLSelectionObject selection = this.document.GetSelection(); object currentSelection = null; try { currentSelection = selection.CreateRange(); } catch { } ArrayList oldItems = this.items; HtmlSelectionType oldType = this.type; int oldLength = this.selectionLength; // Default to an empty selection this.type = HtmlSelectionType.Empty; this.selectionLength = 0; if (currentSelection != null) { this.selection = currentSelection; this.items = new ArrayList(); //If it's a text selection if (currentSelection is NativeMethods.IHTMLTxtRange) { NativeMethods.IHTMLTxtRange textRange = (NativeMethods.IHTMLTxtRange)currentSelection; NativeMethods.IHTMLElement parentElement = textRange.ParentElement(); // If the document is in full document mode or we're selecting a non-body tag, allow it to select // otherwise, leave the selection as empty (since we don't want the body tag to be selectable on an ASP.NET User Control) if (this.IsSelectableElement(new HtmlElement(parentElement, this.control))) { // Add the parent of the text selection if (parentElement != null) { this.text = textRange.GetText(); if (this.text != null) { this.selectionLength = this.text.Length; } else { this.selectionLength = 0; } this.type = HtmlSelectionType.TextSelection; this.items.Add(parentElement); } } } // If it is a control selection else if (currentSelection is NativeMethods.IHtmlControlRange) { NativeMethods.IHtmlControlRange controlRange = (NativeMethods.IHtmlControlRange)currentSelection; int selectedCount = controlRange.GetLength(); // Add all elements selected if (selectedCount > 0) { this.type = HtmlSelectionType.ElementSelection; for (int i = 0; i < selectedCount; i++) { NativeMethods.IHTMLElement currentElement = controlRange.Item(i); this.items.Add(currentElement); } this.selectionLength = selectedCount; } } } this.sameParentValid = false; bool selectionChanged = false; //Now check if there was a change of selection //If the two selections have different lengths, then the selection has changed if (this.type != oldType) { selectionChanged = true; } else if (this.selectionLength != oldLength) { selectionChanged = true; } else { if (this.items != null) { //If the two selections have a different element, then the selection has changed for (int i = 0; i < this.items.Count; i++) { if (this.items[i] != oldItems[i]) { selectionChanged = true; break; } } } } if (selectionChanged) { //Set this.elements to null so no one can retrieve a dirty copy of the selection element wrappers this.elements = null; OnSelectionChanged(EventArgs.Empty); return(true); } return(false); }