Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / WinForms / System / WinForms / Design / Behavior / DragAssistanceManager.cs / 1 / DragAssistanceManager.cs
//#define DEBUGSNAPLINES 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.Diagnostics.CodeAnalysis; using System.Drawing; using System.Windows.Forms.Design; ////// /// The DragAssistanceManager, for lack of a better name, is responsible for integrating /// SnapLines into the DragBehavior. At the beginning of a DragBehavior this class /// is instantiated and at every mouse move this class is called and given the opportunity /// to adjust the position of the drag. The DragAssistanceManager needs to work as fast /// as possible - so not to interupt a drag operation. Because of this, this class has /// many global variables that are re-used, in hopes to limit the # of allocations per /// mouse move / drag operation. Also, for loops are used extensively (instead of /// foreach calls) to eliminate the creation of an enumerator. /// [SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")] internal sealed class DragAssistanceManager { private BehaviorService behaviorService; private IServiceProvider serviceProvider; private Graphics graphics;//graphics to the adornerwindow private IntPtr rootComponentHandle;//used for mapping window points of nested controls private Point dragOffset;//the offset from the new drag pos compared to the last private Rectangle cachedDragRect;//used to store drag rect between erasing & waiting to render private Pen edgePen = SystemPens.Highlight; private bool disposeEdgePen = false; private Pen marginAndPaddingPen = SystemPens.InactiveCaption; private bool disposeMarginPen = false; private Pen baselinePen = new Pen(Color.Fuchsia); //These are global lists of all the existing vertical and hoirizontal snaplines //on the designer's surface excluding the targetControl. All SnapLine coords in these //lists have been properly adjusted for the AdornerWindow coords. // private ArrayList verticalSnapLines = new ArrayList(); private ArrayList horizontalSnapLines = new ArrayList(); //These are SnapLines that represent our target control. private ArrayList targetVerticalSnapLines = new ArrayList(); private ArrayList targetHorizontalSnapLines = new ArrayList(); //This is a list of all the different type of SnapLines our target control //has. When compiling our global SnapLine lists, if we see a SnapLineType //that doesn't exist on our target - we can safely ignore it private ArrayList targetSnapLineTypes = new ArrayList(); //These are created in our init() method (so we don't have to recreate them //for every mousemove). These arrays represent the closest distance to any //snap point on our target control. Once these are calculated - we can: 1) //remove anything > than snapDistance and 2) determine the smallest distance //overall private int[] verticalDistances; private int[] horizontalDistances; //These are cleared and populated on every mouse move. These lists contain //all the new vertical and horizontal lines we need to draw. At the end //of each mouse move - these lines are stored off in the vertLines and horzLines //arrays. This way - we can keep track of old snap lines and can avoid //erasing and redrawing the same line. HA. private ArrayList tempVertLines = new ArrayList(); private ArrayList tempHorzLines = new ArrayList(); private Line[] vertLines = new Line[0]; private Line[] horzLines = new Line[0]; //When we draw snap lines - we only draw lines from the targetControl to the //control we're snapping to. To do this, we'll keep a hashtable... //format: snapLineToBounds[SnapLine]=ControlBounds. private Hashtable snapLineToBounds = new Hashtable(); //We remember the last set of (vert & horz) lines we draw so that //we can push them to the beh. svc. From there, if we receive a //test hook message requesting these - we got 'em private Line[] recentLines; private Image backgroundImage; //instead of calling .invalidate on the windows below us, we'll just draw over w/the background image private const int snapDistance = 8; //default snapping distance (pixels) private int snapPointX, snapPointY; //defines the snap adjustment that needs to be made during the mousemove/drag operation private const int INVALID_VALUE = 0x1111;//used to represent 'un-set' distances private bool resizing; // Are we resizing? private bool ctrlDrag; // Are we in a ctrl-drag? ////// /// Internal constructor called that only takes a service provider. Here it is assumed that all /// painting will be done to the AdornerWindow and that there are no target controsl to exclude /// from snapping. /// internal DragAssistanceManager(IServiceProvider serviceProvider) : this (serviceProvider, null, null, null, false, false) { } ////// /// Internal constructor that takes the service provider and the list of dragCompoents. /// internal DragAssistanceManager(IServiceProvider serviceProvider, ArrayList dragComponents) : this (serviceProvider, null, dragComponents, null, false, false) { } ////// /// Internal constructor that takes the service provider, the list of dragCompoents, and a boolean /// indicating that we are resizing. /// internal DragAssistanceManager(IServiceProvider serviceProvider, ArrayList dragComponents, bool resizing) : this (serviceProvider, null, dragComponents, null, resizing, false) { } ////// /// Internal constructor called by DragBehavior. /// internal DragAssistanceManager(IServiceProvider serviceProvider, Graphics graphics, ArrayList dragComponents, Image backgroundImage, bool ctrlDrag) : this(serviceProvider, graphics, dragComponents, backgroundImage, false, ctrlDrag) { } ////// /// Internal constructor called by DragBehavior. /// [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")] internal DragAssistanceManager(IServiceProvider serviceProvider, Graphics graphics, ArrayList dragComponents, Image backgroundImage, bool resizing, bool ctrlDrag) { #if DEBUGSNAPLINES Debug.WriteLine("DragAssistanceManager - Initialize-----------------------------------------"); #endif this.serviceProvider = serviceProvider; this.behaviorService = serviceProvider.GetService(typeof(BehaviorService)) as BehaviorService; IDesignerHost host = serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost; IUIService uiService = serviceProvider.GetService(typeof(IUIService)) as IUIService; if (host == null || behaviorService == null) { Debug.Fail("Cannot get DesignerHost or BehaviorService"); return; } if (graphics == null) { this.graphics = behaviorService.AdornerWindowGraphics; } else { this.graphics = graphics; } if (uiService != null) { //Can't use 'as' here since Color is a value type if (uiService.Styles["VsColorSnaplines"] is Color) { edgePen = new Pen((Color) uiService.Styles["VsColorSnaplines"]); disposeEdgePen = true; } if (uiService.Styles["VsColorSnaplinesTextBaseline"] is Color) { baselinePen.Dispose(); baselinePen = new Pen((Color) uiService.Styles["VsColorSnaplinesTextBaseline"]); } if (uiService.Styles["VsColorSnaplinesMarginAndPadding"] is Color) { marginAndPaddingPen = new Pen((Color) uiService.Styles["VsColorSnaplinesMarginAndPadding"]); disposeMarginPen = true; } } this.backgroundImage = backgroundImage; this.rootComponentHandle = host.RootComponent is Control ? ((Control)host.RootComponent).Handle : IntPtr.Zero; this.resizing = resizing; this.ctrlDrag = ctrlDrag; Initialize(dragComponents, host); } ////// Adjusts then adds each snap line the designer has to offer to /// either our global horizontal and vertical lists or our target lists. /// Note that we also keep track of our target snapline types - 'cause /// we can safely ignore all other types. If valid target is false- then /// we don't yet know what we're snapping against - so we'll exclude /// the check below to skip unwanted snap line types. /// private void AddSnapLines(ControlDesigner controlDesigner, ArrayList horizontalList, ArrayList verticalList, bool isTarget, bool validTarget) { IList snapLines = controlDesigner.SnapLines; //Used for padding snaplines Rectangle controlRect = controlDesigner.Control.ClientRectangle; //Used for all others Rectangle controlBounds = controlDesigner.Control.Bounds; // Now map the location controlBounds.Location = controlRect.Location = behaviorService.ControlToAdornerWindow(controlDesigner.Control); // Remember the offset -- we need those later int xOffset = controlBounds.Left; int yOffset = controlBounds.Top; // THIS IS ONLY NEEDED FOR PADDING SNAPLINES //We need to adjust the bounds to the client area. This is so that we don't //include borders + titlebar in the snaplines. VSWhidbey #274860 & 342105 //In order to add padding, we need to get the offset from the usable client area of our control //and the actual origin of our control. In other words: how big is the non-client area here? // Ex: we want to add padding on a form to the insides of the borders and below the titlebar. Point offset = controlDesigner.GetOffsetToClientArea(); controlRect.X += offset.X;//offset for non-client area controlRect.Y += offset.Y;//offset for non-client area //END PADDING SNAPLINES //Adjust each snapline to local coords and add it to our global list foreach (SnapLine snapLine in snapLines) { if (isTarget) { //we will remove padding snaplines from targets - it doesn't make sense to snap to //the target's padding lines if (snapLine.Filter != null && snapLine.Filter.StartsWith(SnapLine.Padding)) { #if DEBUGSNAPLINES Debug.WriteLine("\t**Found a padding line on our target, we'll ignore this one."); #endif continue; } if (validTarget && !targetSnapLineTypes.Contains(snapLine.SnapLineType)) { targetSnapLineTypes.Add(snapLine.SnapLineType); #if DEBUGSNAPLINES Debug.WriteLine("\t**Found unique target type: " + snapLine.SnapLineType + ", added to target type list"); #endif } } else { if (validTarget && !targetSnapLineTypes.Contains(snapLine.SnapLineType)) { #if DEBUGSNAPLINES Debug.WriteLine("\t**Current SnapLine's Type (" + snapLine.SnapLineType +") is not in targetSnapLine's Types - skipping"); #endif continue; } //store off the bounds in our hashtable, so if we draw snaplines we know the length of the line //we need to remember different bounds based on what type of snapline this is. VSWhidbey #342105 if ((snapLine.Filter != null) && snapLine.Filter.StartsWith(SnapLine.Padding)) { snapLineToBounds.Add(snapLine, controlRect); } else { snapLineToBounds.Add(snapLine, controlBounds); } } if (snapLine.IsHorizontal) { snapLine.AdjustOffset(yOffset); horizontalList.Add(snapLine); } else { snapLine.AdjustOffset(xOffset); verticalList.Add(snapLine); } } } ////// Build up a distance array of all same-type-alignment pts to the /// closest point on our targetControl. Also, keep track of the smallest /// distance overall. /// private int BuildDistanceArray(ArrayList snapLines, ArrayList targetSnapLines, int[] distances, Rectangle dragBounds) { int smallestDistance = INVALID_VALUE; int highestPriority = 0;//none for (int i = 0; i < snapLines.Count; i++) { SnapLine snapLine = (SnapLine)snapLines[i]; #if DEBUGSNAPLINES Debug.WriteLine("looking at snapline: " + snapLine.ToString()); #endif if (IsMarginOrPaddingSnapLine(snapLine)) { //validate margin and padding snaplines (to make sure it intersects with the dragbounds) //if not, skip this guy if (!ValidateMarginOrPaddingLine(snapLine, dragBounds)) { distances[i] = INVALID_VALUE; continue; } } int smallestDelta = INVALID_VALUE;//some large # for (int j = 0; j < targetSnapLines.Count; j++) { SnapLine targetSnapLine = (SnapLine)targetSnapLines[j]; if (SnapLine.ShouldSnap(snapLine, targetSnapLine)) { #if DEBUGSNAPLINES Debug.WriteLine("Last SnapLine is of the same type as this: " + targetSnapLine); #endif int delta = targetSnapLine.Offset - snapLine.Offset; if (Math.Abs(delta) < Math.Abs(smallestDelta)) { smallestDelta = delta; #if DEBUGSNAPLINES Debug.WriteLine("We have a new smallest delta: " + smallestDelta); #endif } } } distances[i] = smallestDelta; int pri = (int)((SnapLine)snapLines[i]).Priority; //save off this delta for the overall smallest delta! // Need to check the priority here as well if the distance is the same. VSWhidbey 245479 & 338279. // // E.g. smallestDistance so far is 1, for a Low snapline. // We now find another distance of -1, for a Medium snapline. // The old check if (Math.Abs(smallestDelta) < Math.Abs(smallestDistance)) // would not set smallestDistance to -1, since the ABSOLUTE values are the // same. Since the return value is used to phycially move the control, // we would move the control in the direction of the Low snapline, but // draw the Medium snapline in the opposite direction. if ((Math.Abs(smallestDelta) < Math.Abs(smallestDistance)) || ((Math.Abs(smallestDelta) == Math.Abs(smallestDistance)) && (pri > highestPriority))) { smallestDistance = smallestDelta; if (pri != (int)SnapLinePriority.Always) { highestPriority = pri; } } } return smallestDistance; } ////// Here, we erase all of our old horizontal and vertical snaplines /// UNLESS they are also contained in our tempHorzLines or tempVertLines /// arrays - if they are - then erasing them would be redundant (since /// we know we want to draw them on this mousemove) /// private Line[] EraseOldSnapLines(Line[] lines, ArrayList tempLines) { bool foundMatch = false; Rectangle invalidRect = Rectangle.Empty; if (lines != null) { for (int i = 0; i < lines.Length; i++) { Line line = lines[i]; foundMatch = false; if (tempLines != null) { for (int j = 0; j < tempLines.Count; j++) { if (line.LineType != ((Line)tempLines[j]).LineType) { // If the lines are not the same type, then we should forcefully try to remove it. // Say you have a Panel with a Button in it. By default Panel.Padding = 0, and // Button.Margin = 3. As you move the button to the left, you will first get the // combined LEFT margin+padding snap line. If you keep moving the button, you will // now snap to the Left edge, and you will get the Blue snapline. You now // move the button back to the right, and you will immediately snap to the // LEFT Padding snapline. // But what's gonna happen. Both the old (Left) snapline, and the LEFT Padding snapline // (remember these are the panels) have the same coordinates, since Panel.Padding // is 0. Thus Line.GetDiffs will return a non-null diffs. BUT e.g the first line // will result in an invalidRect of (x1,y1,0,0), this we end up invalidating // only a small portion of the existing Blue (left) Snapline. // That's actually not okay since VERTICAL (e.g. LEFT) padding snaplines // actually end up getting drawn HORIZONTALLY - thus we didn't really // invalidate correctly. // // VSWhidbey 169705 continue; } Line[] diffs = Line.GetDiffs(line, (Line)tempLines[j]); if (diffs != null) { for (int k = 0; k < diffs.Length; k++) { invalidRect = new Rectangle(diffs[k].x1, diffs[k].y1, diffs[k].x2 - diffs[k].x1, diffs[k].y2 - diffs[k].y1); invalidRect.Inflate(1,1); if (backgroundImage != null) { graphics.DrawImage(backgroundImage, invalidRect, invalidRect, GraphicsUnit.Pixel); } else { #if DEBUGSNAPLINES using (Graphics g = behaviorService.AdornerWindowGraphics) { System.Threading.Thread.Sleep(750); g.FillRectangle(Brushes.Red, invalidRect); System.Threading.Thread.Sleep(750); } #endif behaviorService.Invalidate(invalidRect); } } foundMatch = true; break; } } } if (!foundMatch) { invalidRect = new Rectangle(line.x1, line.y1, line.x2 - line.x1, line.y2 - line.y1); invalidRect.Inflate(1,1); if (backgroundImage != null) { graphics.DrawImage(backgroundImage, invalidRect, invalidRect, GraphicsUnit.Pixel); } else { behaviorService.Invalidate(invalidRect); } #if DEBUGSNAPLINES Debug.WriteLine("******Found a line to erase: " + line.ToString()); #endif } } } if (tempLines != null) { //Now, store off all the new lines (from the temp structures), so //next time around (next mousemove message) we know which lines //to erase and which ones to keep lines = new Line[tempLines.Count]; tempLines.CopyTo(lines); } else { lines = new Line[0]; } #if DEBUGSNAPLINES Debug.WriteLine("---Stored all temp lines---"); #endif return lines; } internal void EraseSnapLines() { EraseOldSnapLines(vertLines, null); EraseOldSnapLines(horzLines, null); } ////// /// This internal method returns a snap line[] representing the last SnapLines that /// were rendered before this algorithm was stopped (usually by an OnMouseUp). /// This is used for storing additional toolbox drag/drop info and testing hooks. /// internal Line[] GetRecentLines() { if (recentLines != null) { return recentLines; } return new Line[0]; } private void IdentifyAndStoreValidLines(ArrayList snapLines, int[] distances, Rectangle dragBounds, int smallestDistance) { int highestPriority = 1;//low //identify top pri for (int i = 0 ; i < distances.Length; i++) { if (distances[i] == smallestDistance) { int pri = (int)((SnapLine)snapLines[i]).Priority; if ((pri > highestPriority) && (pri != (int)SnapLinePriority.Always)) {//Always is a special category VSWhidbey 255346 highestPriority = pri; } } } //store all snapLines equal to the smallest distance (of the highest priority) for (int i = 0; i < distances.Length; i++) { if ((distances[i] == smallestDistance) && (((int)((SnapLine)snapLines[i]).Priority == highestPriority) || ((int)((SnapLine)snapLines[i]).Priority == (int)SnapLinePriority.Always))) { //always render SnapLines with Priority.Always which has the same distance. VSWhidbey 255346 StoreSnapLine((SnapLine)snapLines[i], dragBounds); } } } // Returns true of this child component (off the root control) should add its snaplines to the collection private bool AddChildCompSnaplines(IComponent comp, ArrayList dragComponents, Rectangle clipBounds, Control targetControl) { Control control = comp as Control; if (control == null || //has to be a control to get snaplines (dragComponents != null && dragComponents.Contains(comp) && !ctrlDrag) || //cannot be something that we are dragging, unless we are in a ctrlDrag IsChildOfParent(control, targetControl) ||//cannot be a child of the control we will drag !clipBounds.IntersectsWith(control.Bounds) || //has to be partially visible on the rootcomp's surface control.Parent == null || // control must have a parent. !control.Visible) { //control itself has to be visible -- we do mean visible, not ShadowedVisible return false; } Control c = control; if (!c.Equals(targetControl)) { IDesignerHost host = serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost; if (host != null) { ControlDesigner controlDesigner = host.GetDesigner(c) as ControlDesigner; if (controlDesigner != null) { return controlDesigner.ControlSupportsSnaplines; } } } return true; } // Returns true if we should add snaplines for this control private bool AddControlSnaplinesWhenResizing(ControlDesigner designer, Control control, Control targetControl) { // do not add snaplines if // we are resizing // the control is a container control with AutoSize set to true // and the control is the parent of the targetControl -- VSWhidbey #224878 if (resizing && (designer is ParentControlDesigner) && (control.AutoSize == true) && (targetControl != null) && (targetControl.Parent != null) && (targetControl.Parent.Equals(control))) { return false; } return true; } ////// Initializes our class - we cache all snap lines for every /// control we can find. This is done for perf. reasons. /// private void Initialize(ArrayList dragComponents, IDesignerHost host) { //our targetControl will always be the 0th component in our dragComponents //array list (a.k.a. the primary selected component). Control targetControl = null; if (dragComponents != null && dragComponents.Count > 0) { targetControl = dragComponents[0] as Control; } Control rootControl = host.RootComponent as Control; //the clipping bounds will be used to ignore all controls that are completely outside of //our rootcomponent's bounds -this way we won't end up snapping to controls that are not //visible on the form's surface Rectangle clipBounds = new Rectangle(0,0,rootControl.ClientRectangle.Width, rootControl.ClientRectangle.Height); clipBounds.Inflate(-1, -1); //determine the screen offset from our rootComponent to the AdornerWindow //(since all drag notification coords will be in adorner window coords) if (targetControl != null) { dragOffset = behaviorService.ControlToAdornerWindow(targetControl); } else { dragOffset = behaviorService.MapAdornerWindowPoint(rootControl.Handle, Point.Empty); if (rootControl.Parent != null && rootControl.Parent.IsMirrored) { dragOffset.Offset(-rootControl.Width, 0); } } if (targetControl != null) { ControlDesigner designer = host.GetDesigner(targetControl) as ControlDesigner; bool disposeDesigner = false; //get all the target snapline information // we need to create one then if (designer == null) { designer = TypeDescriptor.CreateDesigner(targetControl, typeof(IDesigner)) as ControlDesigner; if (designer != null) { //Make sure the control is not forced visible designer.ForceVisible = false; designer.Initialize(targetControl); disposeDesigner = true; } } AddSnapLines(designer, targetHorizontalSnapLines, targetVerticalSnapLines, true, targetControl != null); if (disposeDesigner) { designer.Dispose(); } } //get SnapLines for all our children (nested too) off our root control foreach (IComponent comp in host.Container.Components) { if (!AddChildCompSnaplines(comp, dragComponents, clipBounds, targetControl)) { continue; } ControlDesigner designer = host.GetDesigner(comp) as ControlDesigner; if (designer != null) { if (AddControlSnaplinesWhenResizing(designer, comp as Control, targetControl)) { AddSnapLines(designer, horizontalSnapLines, verticalSnapLines, false, targetControl != null); } // Does the designer have internal control designers for which we need to add snaplines (like SplitPanelContainer, ToolStripContainer) int numInternalDesigners = designer.NumberOfInternalControlDesigners(); for (int i = 0; i < numInternalDesigners; i++) { // Yup we did ControlDesigner internalDesigner = designer.InternalControlDesigner(i); if (internalDesigner != null && AddChildCompSnaplines(internalDesigner.Component, dragComponents, clipBounds, targetControl) && AddControlSnaplinesWhenResizing(internalDesigner, internalDesigner.Component as Control, targetControl)) { AddSnapLines(internalDesigner, horizontalSnapLines, verticalSnapLines, false, targetControl != null); } } } } //Now that we know how many snaplines everyone has, we can create //temp arrays now. Intentionally avoiding this on every mousemove. verticalDistances = new int[verticalSnapLines.Count]; horizontalDistances = new int[horizontalSnapLines.Count]; #if DEBUGSNAPLINES PrintSnapLineArrays(); #endif } ////// Helper function that determines if the child control is related to the parent. /// private static bool IsChildOfParent(Control child, Control parent) { if (child == null || parent == null) { return false; } Control currentParent = child.Parent; while (currentParent != null) { if (currentParent.Equals(parent)) { return true; } currentParent = currentParent.Parent; } return false; } ////// Helper function that identifies margin or padding snaplines /// private static bool IsMarginOrPaddingSnapLine(SnapLine snapLine) { return snapLine.Filter != null && (snapLine.Filter.StartsWith(SnapLine.Margin) || snapLine.Filter.StartsWith(SnapLine.Padding)); } ////// Returns the offset in which the targetControl's rect needs to be /// re-positioned (given the direction by 'directionOffset') in order to align /// with the nearest possible snapline. This is called by commandSet /// during keyboard movements to auto-snap the control around the designer. /// internal Point OffsetToNearestSnapLocation(Control targetControl, IList targetSnaplines, Point directionOffset) { targetHorizontalSnapLines.Clear(); targetVerticalSnapLines.Clear(); //manually add our snaplines as targets foreach (SnapLine snapline in targetSnaplines) { if (snapline.IsHorizontal) { targetHorizontalSnapLines.Add(snapline); } else { targetVerticalSnapLines.Add(snapline); } } return OffsetToNearestSnapLocation(targetControl, directionOffset); } ////// Returns the offset in which the targetControl's rect needs to be /// re-positioned (given the direction by 'directionOffset') in order to align /// with the nearest possible snapline. This is called by commandSet /// during keyboard movements to auto-snap the control around the designer. /// internal Point OffsetToNearestSnapLocation(Control targetControl, Point directionOffset) { Point offset = Point.Empty; Rectangle currentBounds = new Rectangle(behaviorService.ControlToAdornerWindow(targetControl), targetControl.Size); if (directionOffset.X != 0) {//movement somewhere in the x dir //first, build up our distance array BuildDistanceArray(verticalSnapLines, targetVerticalSnapLines, verticalDistances, currentBounds); //now start with the smallest distance and find the first snapline we would intercept given our horizontal direction int minRange = directionOffset.X < 0 ? 0: currentBounds.X; int maxRange = directionOffset.X < 0 ? currentBounds.Right : Int32.MaxValue; offset.X = FindSmallestValidDistance(verticalSnapLines, verticalDistances, minRange, maxRange, directionOffset.X); if (offset.X != 0) { //store off the line structs for actual rendering IdentifyAndStoreValidLines(verticalSnapLines, verticalDistances, currentBounds, offset.X); if (directionOffset.X < 0) { offset.X *= -1; } } } if (directionOffset.Y != 0) {//movement somewhere in the y dir //first, build up our distance array BuildDistanceArray(horizontalSnapLines, targetHorizontalSnapLines, horizontalDistances, currentBounds); //now start with the smallest distance and find the first snapline we would intercept given our horizontal direction int minRange = directionOffset.Y < 0 ? 0: currentBounds.Y; int maxRange = directionOffset.Y < 0 ? currentBounds.Bottom: Int32.MaxValue; offset.Y = FindSmallestValidDistance(horizontalSnapLines, horizontalDistances, minRange, maxRange, directionOffset.Y); if (offset.Y != 0) { //store off the line structs for actual rendering IdentifyAndStoreValidLines(horizontalSnapLines, horizontalDistances, currentBounds, offset.Y); if (directionOffset.Y < 0) { offset.Y *= -1; } } } if (!offset.IsEmpty) { //setup the cached info for drawing cachedDragRect = currentBounds; cachedDragRect.Offset(offset.X, offset.Y); if (offset.X != 0) { vertLines = new Line[tempVertLines.Count]; tempVertLines.CopyTo(vertLines); } if (offset.Y != 0) { horzLines = new Line[tempHorzLines.Count]; tempHorzLines.CopyTo(horzLines); } } return offset; } private static int FindSmallestValidDistance(ArrayList snapLines, int[] distances, int min, int max, int direction) { int distanceValue =0; int snapLineIndex = 0; //loop while we still have valid distance to check and try to find the smallest valid distance while (true) { //get the next smallest snapline index snapLineIndex = SmallestDistanceIndex(distances, direction, out distanceValue); if (snapLineIndex == INVALID_VALUE) { //ran out of valid distances break; } if (IsWithinValidRange(((SnapLine)snapLines[snapLineIndex]).Offset, min, max)) { //found it - make sure we restore the original value for rendering the //snap line in the future distances[snapLineIndex] = distanceValue; return distanceValue; } } return 0; } private static bool IsWithinValidRange(int offset, int min, int max) { return offset > min && offset < max; } private static int SmallestDistanceIndex(int[] distances, int direction, out int distanceValue) { distanceValue = INVALID_VALUE; int smallestIndex = INVALID_VALUE; //check for valid array if (distances.Length ==0) { return smallestIndex; } //find the next smallest for(int i = 0; i < distances.Length; i++) { //If a distance is 0 or if it is to our left and we're //heading right or if it is to our right and we're //heading left then we can null this value out if (distances[i] == 0 || distances[i] > 0 && direction > 0 || distances[i] < 0 && direction < 0) { distances[i] = INVALID_VALUE; } if (Math.Abs(distances[i]) < distanceValue) { distanceValue = Math.Abs(distances[i]); smallestIndex = i; } } if (smallestIndex < distances.Length) { //return and clear the smallest one we found distances[smallestIndex] = INVALID_VALUE; } return smallestIndex; } ////// Actually draws the snaplines based on type, location, and specified pen /// private void RenderSnapLines(Line[] lines, Rectangle dragRect) { Pen currentPen = null; for (int i = 0; i < lines.Length; i++) { if (lines[i].LineType == LineType.Margin || lines[i].LineType == LineType.Padding ) { currentPen = marginAndPaddingPen; if (lines[i].x1 == lines[i].x2) {//vertical margin int coord = Math.Max(dragRect.Top, lines[i].OriginalBounds.Top); coord = coord + (Math.Min(dragRect.Bottom, lines[i].OriginalBounds.Bottom) - coord)/2; lines[i].y1 = lines[i].y2 = coord; if (lines[i].LineType == LineType.Margin) { lines[i].x1 = Math.Min(dragRect.Right, lines[i].OriginalBounds.Right); lines[i].x2 = Math.Max(dragRect.Left, lines[i].OriginalBounds.Left); } else if (lines[i].PaddingLineType == PaddingLineType.PaddingLeft) { lines[i].x1 = lines[i].OriginalBounds.Left; lines[i].x2 = dragRect.Left; } else { Debug.Assert(lines[i].PaddingLineType == PaddingLineType.PaddingRight); lines[i].x1 = dragRect.Right; lines[i].x2 = lines[i].OriginalBounds.Right; } lines[i].x2 --;//off by 1 adjust #if DEBUGSNAPLINES Debug.WriteLine("----- RenderSnapLines ----------------------------------"); Debug.WriteLine(lines[i].LineType.ToString() + " line " + i.ToString()); Debug.WriteLine("dragRect = " + dragRect.ToString()); Debug.WriteLine("OriginalBounds = " + lines[i].OriginalBounds.ToString()); Debug.WriteLine("dragRect.Left + (dragRect.Width/2) = " + (dragRect.Left + (dragRect.Width/2)).ToString()); Debug.WriteLine("lines[i].OriginalBounds.Left + (lines[i].OriginalBounds.Width/2) = " + (lines[i].OriginalBounds.Left + (lines[i].OriginalBounds.Width/2)).ToString()); Debug.WriteLine("--------------------------------------------------------"); #endif } else {//horizontal margin int coord = Math.Max(dragRect.Left, lines[i].OriginalBounds.Left); coord = coord + (Math.Min(dragRect.Right, lines[i].OriginalBounds.Right) - coord)/2; lines[i].x1 = lines[i].x2 = coord; if (lines[i].LineType == LineType.Margin) { lines[i].y1 = Math.Min(dragRect.Bottom, lines[i].OriginalBounds.Bottom); lines[i].y2 = Math.Max(dragRect.Top, lines[i].OriginalBounds.Top); } else if (lines[i].PaddingLineType == PaddingLineType.PaddingTop) { lines[i].y1 = lines[i].OriginalBounds.Top; lines[i].y2 = dragRect.Top; } else { Debug.Assert(lines[i].PaddingLineType == PaddingLineType.PaddingBottom); lines[i].y1 = dragRect.Bottom; lines[i].y2 = lines[i].OriginalBounds.Bottom; } lines[i].y2 --;//off by 1 adjust } } else if (lines[i].LineType == LineType.Baseline) { currentPen = baselinePen; lines[i].x2 -=1;//off by 1 adjust } else { //default to edgePen currentPen = edgePen; if (lines[i].x1 == lines[i].x2) { lines[i].y2 --;//off by 1 adjustment } else { lines[i].x2 --;//off by 1 adjustment } } graphics.DrawLine(currentPen, lines[i].x1, lines[i].y1, lines[i].x2, lines[i].y2); #if DEBUGSNAPLINES Debug.WriteLine("Rendering Line: " + lines[i].ToString()); #endif } } ////// Performance improvement: /// /// Given an snapline we will render, check if it overlaps /// with an existing snapline. If so, combine the two. /// private static void CombineSnaplines(Line snapLine, ArrayList currentLines) { bool merged = false; for (int i= 0; i < currentLines.Count; i++) { Line curLine = (Line)currentLines[i]; Line mergedLine = Line.Overlap(snapLine, curLine); if (mergedLine != null) { currentLines[i] = mergedLine; merged = true; } } if (!merged) { currentLines.Add(snapLine); } } ////// Here, we store all the SnapLines we will render. This way we can /// erase them when they are no longer needed. /// [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")] private void StoreSnapLine(SnapLine snapLine, Rectangle dragBounds) { Rectangle bounds = (Rectangle)snapLineToBounds[snapLine]; Line line = null; // In order for CombineSnapelines to work correctly, we have to determine the type first LineType type = LineType.Standard; if (IsMarginOrPaddingSnapLine(snapLine)) { type = snapLine.Filter.StartsWith(SnapLine.Margin) ? LineType.Margin : LineType.Padding; } //propagate the baseline through to the linetype else if (snapLine.SnapLineType == SnapLineType.Baseline) { type = LineType.Baseline; } if (snapLine.IsVertical) { line = new Line(snapLine.Offset, Math.Min(dragBounds.Top + (snapPointY != INVALID_VALUE ? snapPointY : 0), bounds.Top), snapLine.Offset, Math.Max(dragBounds.Bottom + (snapPointY != INVALID_VALUE ? snapPointY : 0), bounds.Bottom)); line.LineType = type; // Performance improvement: Check if the newly added line overlaps existing lines and if so, combine them. CombineSnaplines(line, tempVertLines); } else { line = new Line(Math.Min(dragBounds.Left + (snapPointX != INVALID_VALUE ? snapPointX : 0), bounds.Left), snapLine.Offset, Math.Max(dragBounds.Right + (snapPointX != INVALID_VALUE ? snapPointX : 0), bounds.Right), snapLine.Offset); line.LineType = type; // Performance improvement: Check if the newly added line overlaps existing lines and if so, combine them. CombineSnaplines(line, tempHorzLines); } if (IsMarginOrPaddingSnapLine(snapLine)) { line.OriginalBounds = bounds; //VSWhidbey #379775 - need to know which padding line (left, right) we are storing. The original //check in RenderSnapLines was wrong. It assume that the dragRect was completely within the OriginalBounds //which is not necessarily true if (line.LineType == LineType.Padding) { switch (snapLine.Filter) { case SnapLine.PaddingRight: line.PaddingLineType = PaddingLineType.PaddingRight; break; case SnapLine.PaddingLeft: line.PaddingLineType = PaddingLineType.PaddingLeft; break; case SnapLine.PaddingTop: line.PaddingLineType = PaddingLineType.PaddingTop; break; case SnapLine.PaddingBottom: line.PaddingLineType = PaddingLineType.PaddingBottom; break; default: Debug.Fail("Unknown snapline filter type"); break; } } } #if DEBUGSNAPLINES Debug.WriteLine("Storing Line: " + line.ToString()); #endif } ////// This function validates a Margin or Padding SnapLine. A valid Margin SnapLine is /// one that will be drawn only if the target control being dragged somehow /// intersects (vertically or horizontally) the coords of the given snapLine. /// This is done so we don't start drawing margin lines when controls are /// large distances apart (too much mess); /// [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")] private bool ValidateMarginOrPaddingLine(SnapLine snapLine, Rectangle dragBounds) { Rectangle bounds = (Rectangle)snapLineToBounds[snapLine]; if (snapLine.IsVertical) { if (bounds.Top < dragBounds.Top) { if (bounds.Top + bounds.Height < dragBounds.Top) { return false; } } else if (dragBounds.Top + dragBounds.Height < bounds.Top) { return false; } } else { if (bounds.Left < dragBounds.Left) { if (bounds.Left + bounds.Width < dragBounds.Left) { return false; } } else if (dragBounds.Left + dragBounds.Width < bounds.Left) { return false; } } #if DEBUGSNAPLINES Debug.WriteLine("Margin/Padding SnapLine " + snapLine + " is valid - it does intersect w/DragBounds."); #endif //valid overlapping margin line return true; } internal Point OnMouseMove(Rectangle dragBounds, SnapLine[] snapLines) { bool didSnap = false; return OnMouseMove(dragBounds, snapLines, ref didSnap, true); } ////// Called by the DragBehavior on every mouse move. We first offset /// all of our drag-control's snap lines by the amount of the mouse move /// then follow our 2-pass heuristic to determine which SnapLines to render. /// internal Point OnMouseMove(Rectangle dragBounds, SnapLine[] snapLines, ref bool didSnap, bool shouldSnapHorizontally) { if (snapLines == null || snapLines.Length == 0){ return Point.Empty; } targetHorizontalSnapLines.Clear(); targetVerticalSnapLines.Clear(); //manually add our snaplines as targets foreach (SnapLine snapline in snapLines) { if (snapline.IsHorizontal) { targetHorizontalSnapLines.Add(snapline); } else { targetVerticalSnapLines.Add(snapline); } } return OnMouseMove(dragBounds, false, ref didSnap, shouldSnapHorizontally); } ////// Called by the DragBehavior on every mouse move. We first offset /// all of our drag-control's snap lines by the amount of the mouse move /// then follow our 2-pass heuristic to determine which SnapLines to render. /// internal Point OnMouseMove(Rectangle dragBounds) { bool didSnap = false; return OnMouseMove(dragBounds, true, ref didSnap, true); } ////// Called by the resizebehavior. It needs to know whether we really snapped or not. /// The snapPoint could be (0,0) even though we snapped. /// internal Point OnMouseMove(Control targetControl, SnapLine[] snapLines, ref bool didSnap, bool shouldSnapHorizontally) { Rectangle dragBounds = new Rectangle(behaviorService.ControlToAdornerWindow(targetControl), targetControl.Size); didSnap = false; return OnMouseMove(dragBounds, snapLines, ref didSnap, shouldSnapHorizontally); } ////// Called by the DragBehavior on every mouse move. We first offset /// all of our drag-control's snap lines by the amount of the mouse move /// then follow our 2-pass heuristic to determine which SnapLines to render. /// private Point OnMouseMove(Rectangle dragBounds, bool offsetSnapLines, ref bool didSnap, bool shouldSnapHorizontally) { tempVertLines.Clear(); tempHorzLines.Clear(); dragOffset = new Point(dragBounds.X - dragOffset.X, dragBounds.Y - dragOffset.Y); if (offsetSnapLines) { //offset our targetSnapLines by the amount we have dragged it for (int i = 0; i < targetHorizontalSnapLines.Count; i++) { ((SnapLine)targetHorizontalSnapLines[i]).AdjustOffset(dragOffset.Y); } for (int i = 0; i < targetVerticalSnapLines.Count; i++) { ((SnapLine)targetVerticalSnapLines[i]).AdjustOffset(dragOffset.X); } } #if DEBUGSNAPLINES Debug.WriteLine("We just offset all our target's snaplines according to new drag position. Offset = " + dragOffset); PrintSnapLineArrays(); #endif //int smallestDistanceVert = INVALID_VALUE; //saved off in first pass - used in our second pass //int smallestDistanceHorz = INVALID_VALUE; //First pass - build up a distance array of all same-type-alignment pts to the //closest point on our targetControl. Also, keep track of the smallest //distance overall int smallestDistanceVert = BuildDistanceArray(verticalSnapLines, targetVerticalSnapLines, verticalDistances, dragBounds); int smallestDistanceHorz = INVALID_VALUE; if (shouldSnapHorizontally) { smallestDistanceHorz =BuildDistanceArray(horizontalSnapLines, targetHorizontalSnapLines, horizontalDistances, dragBounds); } #if DEBUGSNAPLINES PrintDistanceArrays(); #endif //Second Pass! We only need to do a second pass if the smallest delta is <= SnapDistance. //If this is the case - then we draw snap lines for every line equal to the smallest //distance available in the distance array snapPointX = (Math.Abs(smallestDistanceVert) <= snapDistance) ? -smallestDistanceVert : INVALID_VALUE; snapPointY = (Math.Abs(smallestDistanceHorz) <= snapDistance) ? -smallestDistanceHorz : INVALID_VALUE; // certain behaviors (like resize) might want to know whether we really snapped or not. // They can't check the returned snapPoint for (0,0) since that is a valid snapPoint. didSnap = false; if (snapPointX != INVALID_VALUE) { IdentifyAndStoreValidLines(verticalSnapLines, verticalDistances, dragBounds, smallestDistanceVert); didSnap = true; } if (snapPointY != INVALID_VALUE) { IdentifyAndStoreValidLines(horizontalSnapLines, horizontalDistances, dragBounds, smallestDistanceHorz); didSnap = true; } Point snapPoint = new Point(snapPointX != INVALID_VALUE ? snapPointX : 0, snapPointY != INVALID_VALUE ? snapPointY : 0); Rectangle tempDragRect = new Rectangle(dragBounds.Left + snapPoint.X, dragBounds.Top + snapPoint.Y, dragBounds.Width, dragBounds.Height); //out with the old... vertLines = EraseOldSnapLines(vertLines, tempVertLines); horzLines = EraseOldSnapLines(horzLines, tempHorzLines); //store this drag rect - we'll use it when we are (eventually) //called back on to actually render our lines //NOTE NOTE NOTE: If OnMouseMove is called during a resize operation, then cachedDragRect is not guaranteed to work. //See VSWhidbey #340048. That is why I introduced RenderSnapLinesInternal(dragRect) cachedDragRect = tempDragRect; //reset the dragoffset to this last location dragOffset = dragBounds.Location; //this 'snapPoint' will be the amount we want the dragBehavior to shift the //dragging control by ('cause we snapped somewhere) return snapPoint; } //NOTE NOTE NOTE: If OnMouseMove is called during a resize operation, then cachedDragRect is not guaranteed to work. //See VSWhidbey #340048. That is why I introduced RenderSnapLinesInternal(dragRect) ////// Called by the ResizeBehavior after it has finished drawing /// internal void RenderSnapLinesInternal(Rectangle dragRect) { cachedDragRect = dragRect; RenderSnapLinesInternal(); } ////// Called by the DropSourceBehavior after it /// finished drawing its' draging images so that /// we can draw our lines on top of everything. /// internal void RenderSnapLinesInternal() { RenderSnapLines(vertLines, cachedDragRect); RenderSnapLines(horzLines, cachedDragRect); recentLines = new Line[vertLines.Length + horzLines.Length]; vertLines.CopyTo(recentLines, 0); horzLines.CopyTo(recentLines, vertLines.Length); } ////// Clean up all of our references. /// internal void OnMouseUp() { //Here, we store off our recent snapline info to the //behavior service - this is used for testing purposes if (behaviorService != null) { Line[] recent = GetRecentLines(); string[] lines = new string[recent.Length]; for (int i = 0; i < recent.Length; i++) { lines[i] = recent[i].ToString(); } this.behaviorService.RecentSnapLines = lines; } EraseSnapLines(); graphics.Dispose(); if (disposeEdgePen && edgePen != null) { edgePen.Dispose(); } if (disposeMarginPen && marginAndPaddingPen != null) { marginAndPaddingPen.Dispose(); } if (baselinePen != null) { baselinePen.Dispose(); } if (backgroundImage != null) { backgroundImage.Dispose(); } #if DEBUGSNAPLINES Debug.WriteLine("DragAssistanceManager - MouseUp-----------------------------------------"); #endif } ////// Our 'line' class - used to manage two points and /// calculate the difference between any two lines. /// internal class Line { public int x1, y1, x2, y2; private LineType lineType; private PaddingLineType paddingLineType; private Rectangle originalBounds; public LineType LineType { get { return lineType; } set { lineType = value; } } public Rectangle OriginalBounds { get { return this.originalBounds; } set { this.originalBounds = value; } } public PaddingLineType PaddingLineType { get { return paddingLineType; } set { paddingLineType = value; } } public Line(int x1, int y1, int x2, int y2) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.lineType = LineType.Standard; } private Line(int x1, int y1, int x2, int y2, LineType type) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.lineType = type; } public static Line[] GetDiffs(Line l1, Line l2) { //x's align if (l1.x1 == l1.x2 && l1.x1 == l2.x1) { return new Line[2] {new Line(l1.x1, Math.Min(l1.y1, l2.y1), l1.x1, Math.Max(l1.y1, l2.y1)), new Line(l1.x1, Math.Min(l1.y2, l2.y2), l1.x1, Math.Max(l1.y2, l2.y2))}; } //y's align if (l1.y1 == l1.y2 && l1.y1 == l2.y1) { return new Line[2] {new Line(Math.Min(l1.x1, l2.x1), l1.y1, Math.Max(l1.x1, l2.x1), l1.y1), new Line(Math.Min(l1.x2, l2.x2), l1.y1, Math.Max(l1.x2, l2.x2), l1.y1)}; } return null; } public static Line Overlap(Line l1, Line l2) { // Need to be the same type if (l1.LineType != l2.LineType) { return null; } // only makes sense to do this for Standard and Baseline if ((l1.LineType != LineType.Standard) && (l1.LineType != LineType.Baseline)) { return null; } // 2 overlapping vertical lines if ((l1.x1 == l1.x2) && (l2.x1 == l2.x2) && (l1.x1 == l2.x1)) { return new Line(l1.x1, Math.Min(l1.y1, l2.y1), l1.x2, Math.Max(l1.y2, l2.y2), l1.LineType); } // 2 overlapping horizontal lines if ((l1.y1 == l1.y2) && (l2.y1 == l2.y2) && (l1.y1 == l2.y2)) { return new Line(Math.Min(l1.x1, l2.x1), l1.y1, Math.Max(l1.x2, l2.x2), l1.y2, l1.LineType); } return null; } public override string ToString() { return "Line, type = " + lineType + ", dims =(" + x1 + ", " + y1 + ")->(" + x2 + ", " + y2 + ")"; } } ////// Describes different types of lines (used for margins, etc..) /// internal enum LineType { Standard, Margin, Padding, Baseline } ////// Describes what kind of padding line we have /// internal enum PaddingLineType { None, PaddingRight, PaddingLeft, PaddingTop, PaddingBottom } #if DEBUGSNAPLINES private void PrintDistanceArrays() { Debug.WriteLine(">>>Printing Distance Arrays..."); Debug.WriteLine("--Horizontal"); for (int i = 0; i < horizontalDistances.Length; i++) { Debug.WriteLine("\t" + i + ":" + horizontalDistances[i]); } Debug.WriteLine("--Vertical"); for (int i = 0; i < verticalDistances.Length; i++) { Debug.WriteLine("\t" + i + ":" + verticalDistances[i]); } Debug.WriteLine(">>>Done Printing Distance Arrays"); } private void PrintSnapLineArrays() { Debug.WriteLine(">>>Printing SnapLine Arrays..."); Debug.WriteLine("--Target Control's SnapLines--"); Debug.WriteLine("--Horizontal"); foreach (SnapLine snapLine in targetHorizontalSnapLines) { Debug.WriteLine("\t" + snapLine.ToString()); } Debug.WriteLine("--Vertical"); foreach (SnapLine snapLine in targetVerticalSnapLines) { Debug.WriteLine("\t" + snapLine.ToString()); } Debug.WriteLine("--Global SnapLines--"); Debug.WriteLine("--Horizontal"); foreach (SnapLine snapLine in horizontalSnapLines) { Debug.WriteLine("\t" + snapLine.ToString()); } Debug.WriteLine("--Vertical"); foreach (SnapLine snapLine in verticalSnapLines) { Debug.WriteLine("\t" + snapLine.ToString()); } Debug.WriteLine("--Valid SnapLinesTypes--"); foreach (SnapLineType type in targetSnapLineTypes) { Debug.WriteLine("\t" + type.ToString()); } Debug.WriteLine(">>>Done Printing SnapLine Arrays"); } #endif } } // 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
- InvalidDataException.cs
- TextComposition.cs
- TypeDescriptionProviderAttribute.cs
- Path.cs
- MeasurementDCInfo.cs
- Control.cs
- XslAstAnalyzer.cs
- CompilerLocalReference.cs
- FileSystemInfo.cs
- BamlTreeUpdater.cs
- PtsHost.cs
- FunctionDetailsReader.cs
- AutomationElementCollection.cs
- FactoryRecord.cs
- AlphabeticalEnumConverter.cs
- ColumnMap.cs
- DataControlPagerLinkButton.cs
- RelationshipEndCollection.cs
- SmiRequestExecutor.cs
- VersionedStreamOwner.cs
- DelegateBodyWriter.cs
- DataTableTypeConverter.cs
- DependencyPropertyAttribute.cs
- CursorConverter.cs
- DoubleAnimationUsingKeyFrames.cs
- ModelVisual3D.cs
- NativeActivityContext.cs
- SetterBase.cs
- DesignSurfaceManager.cs
- ListArgumentProvider.cs
- ToolStripDropDownButton.cs
- HealthMonitoringSectionHelper.cs
- ChangeNode.cs
- SystemWebExtensionsSectionGroup.cs
- SafeFreeMibTable.cs
- DataGridTable.cs
- XmlArrayAttribute.cs
- AssemblyHelper.cs
- PageWrapper.cs
- TrackingProfileCache.cs
- WindowInteractionStateTracker.cs
- GregorianCalendarHelper.cs
- CompensateDesigner.cs
- InstanceCreationEditor.cs
- TextFormatter.cs
- TextTreeText.cs
- NextPreviousPagerField.cs
- RoleGroup.cs
- RegistryConfigurationProvider.cs
- ResourceSet.cs
- FontWeights.cs
- ImageSourceValueSerializer.cs
- UIElement3DAutomationPeer.cs
- DataKey.cs
- OleDbSchemaGuid.cs
- sqlmetadatafactory.cs
- XmlBaseReader.cs
- IsolatedStoragePermission.cs
- AutoGeneratedFieldProperties.cs
- HyperLink.cs
- VerticalAlignConverter.cs
- InsufficientExecutionStackException.cs
- HtmlEmptyTagControlBuilder.cs
- FloaterParaClient.cs
- QueryOptionExpression.cs
- Base64Encoder.cs
- SQLInt32Storage.cs
- WebResponse.cs
- SqlDuplicator.cs
- WebEventCodes.cs
- DoubleAnimationClockResource.cs
- CreateUserWizard.cs
- NumericUpDownAccelerationCollection.cs
- Inflater.cs
- StringAnimationUsingKeyFrames.cs
- arabicshape.cs
- SchemaElementDecl.cs
- ISO2022Encoding.cs
- TemplateControl.cs
- DefaultValueTypeConverter.cs
- TagNameToTypeMapper.cs
- XmlParser.cs
- CodeNamespace.cs
- AppModelKnownContentFactory.cs
- XmlRawWriter.cs
- ByteBufferPool.cs
- OleDbDataAdapter.cs
- Section.cs
- IconHelper.cs
- SQLBinaryStorage.cs
- SqlTransaction.cs
- XPathPatternBuilder.cs
- RPIdentityRequirement.cs
- ArrayConverter.cs
- ContentPropertyAttribute.cs
- SpeechRecognitionEngine.cs
- MessageEncodingBindingElement.cs
- BaseDataList.cs
- XmlReader.cs
- SqlRetyper.cs