Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / WinForms / System / WinForms / Design / Behavior / SelectionManager.cs / 1 / SelectionManager.cs
namespace System.Windows.Forms.Design.Behavior { using System; using System.Collections; using System.ComponentModel; using System.ComponentModel.Design; using System.Design; using System.Diagnostics; using System.Drawing; using System.Windows.Forms.Design; ////// /// The SelectionBehavior is pushed onto the BehaviorStack in response to a /// positively hit tested SelectionGlyph. The SelectionBehavior performs /// two main tasks: 1) forward messages to the related ControlDesigner, and 2) /// calls upon the SelectionManager to push a potention DragBehavior. /// internal sealed class SelectionManager : IDisposable { private Adorner selectionAdorner;//used to provide all selection glyphs private Adorner bodyAdorner;//used to track all body glyphs for each control private BehaviorService behaviorService;//ptr back to our BehaviorService private IServiceProvider serviceProvider;//standard service provider private Hashtable componentToDesigner;//used for quick look up of designers related to comps private Control rootComponent;//root component being designed private ISelectionService selSvc;//we cache the selection service for perf. private IDesignerHost designerHost;//we cache the designerhost for perf. private bool needRefresh; // do we need to refresh? private Rectangle[] prevSelectionBounds;//used to only repaint the changing part of the selection private object prevPrimarySelection; //used to check if the primary selection changed private Rectangle[] curSelectionBounds; private int curCompIndex; private DesignerActionUI designerActionUI = null; // the "container" for all things related to the designer action (smartags) UI private bool selectionChanging; //we dont want the OnSelectionChanged to be recursively called. ////// /// Constructor. Here we query for necessary services and cache them for perf. reasons. /// We also hook to Component Added/Removed/Changed notifications so we can keep in sync /// when the designers' components change. Also, we create our custom Adorner and add /// it to the BehaviorService. /// public SelectionManager(IServiceProvider serviceProvider, BehaviorService behaviorService) { prevSelectionBounds = null; prevPrimarySelection = null; this.behaviorService = behaviorService; this.serviceProvider = serviceProvider; selSvc = (ISelectionService)serviceProvider.GetService(typeof(ISelectionService)); designerHost = (IDesignerHost)serviceProvider.GetService(typeof(IDesignerHost)); if (designerHost == null || selSvc == null) { Debug.Fail("SelectionManager - Host or SelSvc is null, can't continue"); } //sync the BehaviorService's begindrag event behaviorService.BeginDrag += new BehaviorDragDropEventHandler(this.OnBeginDrag); //sync the BehaviorService's Synchronize event behaviorService.Synchronize += new EventHandler(this.OnSynchronize); selSvc.SelectionChanged += new EventHandler(this.OnSelectionChanged); rootComponent = (Control)designerHost.RootComponent; //create and add both of our adorners, //one for selection, one for bodies selectionAdorner = new Adorner(); bodyAdorner = new Adorner(); behaviorService.Adorners.Add(bodyAdorner); behaviorService.Adorners.Add(selectionAdorner);//adding this will cause the adorner to get setup with a ptr to the beh.svc. componentToDesigner = new Hashtable(); IComponentChangeService cs = (IComponentChangeService)serviceProvider.GetService(typeof(IComponentChangeService)); if (cs != null) { cs.ComponentAdded += new ComponentEventHandler(this.OnComponentAdded); cs.ComponentRemoved += new ComponentEventHandler(this.OnComponentRemoved); cs.ComponentChanged += new ComponentChangedEventHandler(this.OnComponentChanged); } designerHost.TransactionClosed += new DesignerTransactionCloseEventHandler(OnTransactionClosed); // designeraction UI DesignerOptionService options = designerHost.GetService(typeof(DesignerOptionService)) as DesignerOptionService; if (options != null) { PropertyDescriptor p = options.Options.Properties["UseSmartTags"]; if (p != null && p.PropertyType == typeof(bool) && (bool)p.GetValue(null)) { designerActionUI = new DesignerActionUI(serviceProvider, selectionAdorner); behaviorService.DesignerActionUI = designerActionUI; } } } ////// /// Returns the Adorner that contains all the /// BodyGlyphs for the current selection state. /// internal Adorner BodyGlyphAdorner { get { return bodyAdorner; } } ////// There are certain cases like Adding Item to ToolStrips through InSitu Editor, where there is ParentTransaction that has to be cancelled depending upon the user action /// When this parent transaction is cancelled, there may be no reason to REFRESH the selectionManager which actually clears all the glyphs and readds them /// This REFRESH causes a lot of flicker and can be avoided by setting this property to false. Since this property is checked in the TransactionClosed, the SelectionManager /// won't REFRESH and hence just eat up the refresh thus avoiding unnecessary flicker. /// internal bool NeedRefresh { get { return needRefresh; } set { needRefresh = value; } } ////// /// Returns the Adorner that contains all the /// BodyGlyphs for the current selection state. /// internal Adorner SelectionGlyphAdorner { get { return selectionAdorner; } } ////// This method fist calls the recursive AddControlGlyphs() method. /// When finished, we add the final glyph(s) to the root comp. /// private void AddAllControlGlyphs(Control parent, ArrayList selComps, object primarySelection) { foreach (Control control in parent.Controls) { AddAllControlGlyphs(control, selComps, primarySelection); } GlyphSelectionType selType = GlyphSelectionType.NotSelected; if (selComps.Contains(parent)) { if (parent.Equals(primarySelection)) { selType = GlyphSelectionType.SelectedPrimary; } else { selType = GlyphSelectionType.Selected; } } AddControlGlyphs(parent, selType); } ////// Recursive method that goes through and adds all the glyphs /// of every child to our global Adorner. /// private void AddControlGlyphs(Control c, GlyphSelectionType selType) { ControlDesigner cd = (ControlDesigner)componentToDesigner[c]; if (cd != null) { ControlBodyGlyph bodyGlyph = cd.GetControlGlyphInternal(selType); if (bodyGlyph != null) { bodyAdorner.Glyphs.Add(bodyGlyph); if (selType == GlyphSelectionType.SelectedPrimary || selType == GlyphSelectionType.Selected) { if (curSelectionBounds[curCompIndex] == Rectangle.Empty) { curSelectionBounds[curCompIndex] = bodyGlyph.Bounds; } else { curSelectionBounds[curCompIndex] = Rectangle.Union(curSelectionBounds[curCompIndex], bodyGlyph.Bounds); } } } GlyphCollection glyphs = cd.GetGlyphs(selType); if (glyphs != null) { selectionAdorner.Glyphs.AddRange(glyphs); if (selType == GlyphSelectionType.SelectedPrimary || selType == GlyphSelectionType.Selected) { foreach (Glyph glyph in glyphs) { curSelectionBounds[curCompIndex] = Rectangle.Union(curSelectionBounds[curCompIndex], glyph.Bounds); } } } } if (selType == GlyphSelectionType.SelectedPrimary || selType == GlyphSelectionType.Selected) { curCompIndex++; } } ////// /// Unhook all of our event notifications, clear our adorner and remove it from the Beh.Svc. /// // We don't need to Dispose rootComponent. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed")] public void Dispose() { if (designerHost != null) { designerHost.TransactionClosed -= new DesignerTransactionCloseEventHandler(OnTransactionClosed); designerHost = null; } if (serviceProvider != null) { IComponentChangeService cs = (IComponentChangeService)serviceProvider.GetService(typeof(IComponentChangeService)); if (cs != null) { cs.ComponentAdded -= new ComponentEventHandler(this.OnComponentAdded); cs.ComponentChanged -= new ComponentChangedEventHandler(this.OnComponentChanged); cs.ComponentRemoved -= new ComponentEventHandler(this.OnComponentRemoved); } if (selSvc != null) { selSvc.SelectionChanged -= new EventHandler(this.OnSelectionChanged); selSvc = null; } serviceProvider = null; } if (behaviorService != null) { behaviorService.Adorners.Remove(bodyAdorner); behaviorService.Adorners.Remove(selectionAdorner); behaviorService.BeginDrag -= new BehaviorDragDropEventHandler(this.OnBeginDrag); behaviorService.Synchronize -= new EventHandler(this.OnSynchronize); behaviorService = null; } if (selectionAdorner != null) { selectionAdorner.Glyphs.Clear(); selectionAdorner = null; } if (bodyAdorner != null) { bodyAdorner.Glyphs.Clear(); bodyAdorner = null; } if (designerActionUI != null) { designerActionUI.Dispose(); designerActionUI = null; } } ////// /// Refreshes all selection Glyphs. /// public void Refresh() { NeedRefresh = false; OnSelectionChanged(this, null); } ////// When a component is added, we get the designer and add it /// to our hashtable for quick lookup. /// private void OnComponentAdded(object source, ComponentEventArgs ce) { IComponent component = ce.Component; IDesigner designer = designerHost.GetDesigner(component); if (designer is ControlDesigner) { componentToDesigner.Add(component, designer); } } ////// Before a drag, remove all glyphs that are involved /// in the drag operation and any that don't allow drops. /// private void OnBeginDrag(object source, BehaviorDragDropEventArgs e) { ArrayList dragComps = new ArrayList(e.DragComponents); ArrayList glyphsToRemove = new ArrayList(); foreach (ControlBodyGlyph g in bodyAdorner.Glyphs) { if (g.RelatedComponent is Control) { if (dragComps.Contains(g.RelatedComponent) || !((Control)g.RelatedComponent).AllowDrop) { glyphsToRemove.Add(g); } } } foreach (Glyph g in glyphsToRemove) { bodyAdorner.Glyphs.Remove(g); } } // Called by the DropSourceBehavior when dragging into a new host internal void OnBeginDrag(BehaviorDragDropEventArgs e) { OnBeginDrag(null, e); } ////// When a component is changed - we need to refresh the selection. /// private void OnComponentChanged(object source, ComponentChangedEventArgs ce) { if (selSvc.GetComponentSelected(ce.Component)) { if (!designerHost.InTransaction) { Refresh(); } else { NeedRefresh = true; } } } ////// When a component is removed - we remove the key & value from /// our hashtable. /// private void OnComponentRemoved(object source, ComponentEventArgs ce) { if (componentToDesigner.Contains(ce.Component)) { componentToDesigner.Remove(ce.Component); } //remove the associated designeractionpanel if (designerActionUI != null) { designerActionUI.RemoveActionGlyph(ce.Component); } } ////// Computes the region representing the difference between the old /// selection and the new selection. /// private Region DetermineRegionToRefresh(object primarySelection) { Region toRefresh = new Region(Rectangle.Empty); Rectangle[] larger; Rectangle[] smaller; if (curSelectionBounds.Length >= prevSelectionBounds.Length) { larger = curSelectionBounds; smaller = prevSelectionBounds; } else { larger = prevSelectionBounds; smaller = curSelectionBounds; } // we need to make sure all of the rects in the smaller array are // accounted for. Any that don't intersect a rect in the larger // array need to be included in the region to repaint. bool[] intersected = new bool[smaller.Length]; for (int i = 0; i < smaller.Length; i++) { intersected[i] = false; } // determine which rects in the larger array need to be // included in the region to invalidate by intersecting // with rects in the smaller array. for(int l = 0; l < larger.Length; l++) { bool largeIntersected = false; Rectangle large = larger[l]; for (int s = 0; s < smaller.Length; s++) { if (large.IntersectsWith(smaller[s])) { Rectangle small = smaller[s]; largeIntersected = true; if (large != small) { toRefresh.Union(large); toRefresh.Union(small); } intersected[s] = true; break; } } if (!largeIntersected) { toRefresh.Union(large); } } // now add any rects from the smaller array // that weren't accounted for for (int k = 0; k < intersected.Length; k++) { if (!intersected[k]) { toRefresh.Union(smaller[k]); } } using (Graphics g = behaviorService.AdornerWindowGraphics) { //If all that changed was the primary selection, then the refresh region was empty, //but we do need to update the 2 controls. VSWhidbey #269806 if (toRefresh.IsEmpty(g) && primarySelection != null && !primarySelection.Equals(prevPrimarySelection)) { for (int i = 0; i < curSelectionBounds.Length; i++) { toRefresh.Union(curSelectionBounds[i]); } } } return toRefresh; } ////// Event handler for the behaviorService's Synchronize event /// private void OnSynchronize(object sender, EventArgs e) { Refresh(); } ////// On every selectionchange, we remove all glyphs, get the newly /// selected components, and re-add all glyphs back to the Adorner. /// private void OnSelectionChanged(object sender, EventArgs e) { // Note: selectionChanging would guard against a re-entrant code... // Since we dont want to be in messed up state when adding new Glyphs. if (!selectionChanging) { selectionChanging = true; selectionAdorner.Glyphs.Clear(); bodyAdorner.Glyphs.Clear(); ArrayList selComps = new ArrayList(selSvc.GetSelectedComponents()); object primarySelection = selSvc.PrimarySelection; //add all control glyphs to all controls on rootComp curCompIndex = 0; curSelectionBounds = new Rectangle[selComps.Count]; AddAllControlGlyphs(rootComponent, selComps, primarySelection); if (prevSelectionBounds != null) { Region toUpdate = DetermineRegionToRefresh(primarySelection); using (Graphics g = behaviorService.AdornerWindowGraphics) { if (!toUpdate.IsEmpty(g)) { selectionAdorner.Invalidate(toUpdate); } } } else { // There was no previous selection, so just invalidate // the current selection if (curSelectionBounds.Length > 0) { Rectangle toUpdate = curSelectionBounds[0]; for (int i = 1; i < curSelectionBounds.Length; i++) { toUpdate = Rectangle.Union(toUpdate, curSelectionBounds[i]); } if (toUpdate != Rectangle.Empty) { selectionAdorner.Invalidate(toUpdate); } } else { selectionAdorner.Invalidate(); } } prevPrimarySelection = primarySelection; if (curSelectionBounds.Length > 0) { prevSelectionBounds = new Rectangle[curSelectionBounds.Length]; Array.Copy(curSelectionBounds, prevSelectionBounds, curSelectionBounds.Length); } else { prevSelectionBounds = null; } selectionChanging = false; } } ////// When a transaction that involves one of our components closes, /// refresh to reflect any changes. /// private void OnTransactionClosed(object sender, DesignerTransactionCloseEventArgs e) { if (e.LastTransaction && NeedRefresh) { Refresh(); } } } } // 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
- HMACSHA512.cs
- BrowserDefinitionCollection.cs
- ActiveXSite.cs
- returneventsaver.cs
- _AuthenticationState.cs
- KeyNameIdentifierClause.cs
- HtmlUtf8RawTextWriter.cs
- TaiwanCalendar.cs
- EmptyControlCollection.cs
- TextEvent.cs
- TextEndOfParagraph.cs
- XmlCharType.cs
- SafeHandle.cs
- ParserExtension.cs
- ToolStripDropDown.cs
- _DigestClient.cs
- HtmlFormParameterReader.cs
- HtmlInputText.cs
- AccessDataSourceView.cs
- BookmarkWorkItem.cs
- EvidenceTypeDescriptor.cs
- TraceContextRecord.cs
- JsonByteArrayDataContract.cs
- RuntimeHandles.cs
- Base64WriteStateInfo.cs
- BitmapEditor.cs
- StateFinalizationDesigner.cs
- DateTimeUtil.cs
- PathFigure.cs
- TransformerInfoCollection.cs
- XPathNavigator.cs
- BufferedStream.cs
- PipelineModuleStepContainer.cs
- CompensationHandlingFilter.cs
- RuleSetDialog.cs
- HandlerBase.cs
- CodeTypeOfExpression.cs
- TreeViewHitTestInfo.cs
- SmtpNegotiateAuthenticationModule.cs
- NameScopePropertyAttribute.cs
- CompositeControl.cs
- Int32Collection.cs
- CustomAssemblyResolver.cs
- TagMapInfo.cs
- CodeTryCatchFinallyStatement.cs
- ContextMenu.cs
- DataStorage.cs
- TextReturnReader.cs
- StringFormat.cs
- FormsAuthenticationTicket.cs
- GroupBox.cs
- PrinterUnitConvert.cs
- SpecialNameAttribute.cs
- SessionStateItemCollection.cs
- CommonXSendMessage.cs
- SecurityUtils.cs
- Span.cs
- TreeViewEvent.cs
- CodeMemberField.cs
- Msmq.cs
- DataGridViewColumnStateChangedEventArgs.cs
- BuildProviderCollection.cs
- Control.cs
- TypeUtil.cs
- SecurityTokenRequirement.cs
- ToolStripItem.cs
- ADMembershipUser.cs
- SinglePageViewer.cs
- SerializationFieldInfo.cs
- IndependentlyAnimatedPropertyMetadata.cs
- TabPanel.cs
- LinqDataSourceDeleteEventArgs.cs
- SendSecurityHeaderElement.cs
- DesignTimeXamlWriter.cs
- ProbeMatchesCD1.cs
- CodeTypeParameter.cs
- WindowsTitleBar.cs
- CultureNotFoundException.cs
- LocalBuilder.cs
- SignedPkcs7.cs
- InvalidCardException.cs
- AppDomainShutdownMonitor.cs
- RequestBringIntoViewEventArgs.cs
- SecurityAlgorithmSuite.cs
- HttpValueCollection.cs
- HttpSocketManager.cs
- TdsValueSetter.cs
- XPathBinder.cs
- TextTreeObjectNode.cs
- NTAccount.cs
- TemplateAction.cs
- DateRangeEvent.cs
- TimeEnumHelper.cs
- DocumentEventArgs.cs
- RijndaelManaged.cs
- BamlStream.cs
- ChtmlLinkAdapter.cs
- DecoderFallbackWithFailureFlag.cs
- BuildResult.cs
- QueryAccessibilityHelpEvent.cs