using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing; using System.Reflection; using System.Text; using System.Windows.Forms; using System.Windows.Forms.Design; using System.Windows.Forms.Design.Behavior; namespace DevComponents.DotNetBar.Design { public class ComponentDesignerWithAction : ComponentDesigner { private Adorner _DesignerActionAdorner = null; public override void Initialize(System.ComponentModel.IComponent component) { base.Initialize(component); if (DesignerActionUIEnabled) { ISelectionService selectionService = (ISelectionService) GetService(typeof(ISelectionService)); if (selectionService != null) selectionService.SelectionChanged += SelectionChanged; _DesignerActionAdorner = new Adorner(); // If our component is removed we need to clean-up IComponentChangeService cc = (IComponentChangeService) GetService(typeof(IComponentChangeService)); if (cc != null) { cc.ComponentRemoving += ComponentRemoving; cc.ComponentRemoved += ComponentRemoved; } } } private void ComponentRemoved(object sender, ComponentEventArgs e) { if (e.Component is BaseItem) { BaseItem parent = this.Component as BaseItem; BaseItem item = e.Component as BaseItem; if (item != null && parent != null && parent.SubItems.Contains(item)) { IComponentChangeService cc = (IComponentChangeService)GetService(typeof(IComponentChangeService)); if (cc != null) cc.OnComponentChanging(parent, TypeDescriptor.GetProperties(parent)["SubItems"]); parent.SubItems.Remove(item); if (cc != null) cc.OnComponentChanged(parent, TypeDescriptor.GetProperties(parent)["SubItems"], null, null); this.RecalcLayout(); } } } public virtual void RecalcLayout() { } private void ComponentRemoving(object sender, ComponentEventArgs e) { if(e.Component == this.Component) RemoveGlyph(); } protected override void Dispose(bool disposing) { if (DesignerActionUIEnabled) { ISelectionService selectionService = (ISelectionService) GetService(typeof(ISelectionService)); if (selectionService != null) selectionService.SelectionChanged -= SelectionChanged; IComponentChangeService cc = (IComponentChangeService)GetService(typeof(IComponentChangeService)); if (cc != null) { cc.ComponentRemoving -= ComponentRemoving; cc.ComponentRemoved -= ComponentRemoved; } } base.Dispose(disposing); } public bool IsSelected = false; private void SelectionChanged(object sender, EventArgs e) { bool selected = false; ISelectionService selectionService = (ISelectionService) GetService(typeof(ISelectionService)); if (selectionService == null) return; if (selectionService.PrimarySelection == this.Component) selected = true; else { ICollection selectedComponents = selectionService.GetSelectedComponents(); foreach (object o in selectedComponents) { if (o.Equals(this.Component)) { selected = true; break; } } } OnDesignerSelectionChanged(selected); if (selected) { Control hostControl = GetContainerControl(); if (hostControl != null) { Rectangle itemScreenBounds = hostControl.RectangleToScreen(ComponentBounds); _DesignerGlyph = CreateDesignerGlyphWrapper((Component) this.Component, GetParentControl(), itemScreenBounds, this.ActionLists); } } else { RemoveGlyph(); } IsSelected = selected; } protected virtual Rectangle ComponentBounds { get { BaseItem item = this.Component as BaseItem; if (item != null) return item.Bounds; return Rectangle.Empty; } } public virtual Control GetHostControl() { return GetParentControl(); } protected virtual Control GetParentControl() { return GetContainerControl(); } protected virtual Control GetContainerControl() { BaseItem item = this.Component as BaseItem; if (item != null) return (Control) item.ContainerControl; return null; } protected virtual void OnDesignerSelectionChanged(bool isSelected) { } protected virtual bool DesignerActionUIEnabled { get { return true; } } private Glyph _DesignerGlyph = null; private void RemoveGlyph() { BehaviorService svc = (BehaviorService) this.GetService(typeof(BehaviorService)); if (svc == null) return; _DesignerActionAdorner.Glyphs.Clear(); if (svc.Adorners.Contains(_DesignerActionAdorner)) svc.Adorners.Remove(_DesignerActionAdorner); if (_ActionListToolStrip != null) _ActionListToolStrip.LocationChanged -= HostLocationChanged; _ActionListToolStrip = null; InvalidateDesignerSurface(); } private void InvalidateDesignerSurface() { BehaviorService behaviorService = (BehaviorService) GetService(typeof(BehaviorService)); if (behaviorService == null) return; object actionUi = GetActionUI(behaviorService); if (actionUi == null) return; object mainParentWindow = ReflectionHelpers.GetValueField(actionUi, "mainParentWindow", BindingFlags.Instance | BindingFlags.NonPublic); if (mainParentWindow is IWin32Window) { WinApi.RedrawWindow(((IWin32Window) mainParentWindow).Handle, IntPtr.Zero, IntPtr.Zero, (uint) (WinApi.RedrawWindowFlags.RDW_INVALIDATE | WinApi.RedrawWindowFlags.RDW_ALLCHILDREN)); } } private ToolStripDropDown _ActionListToolStrip = null; private Glyph CreateDesignerGlyphWrapper(Component targetComponent, Control ownerControl, Rectangle screenBounds, DesignerActionListCollection actionLists) { BehaviorService behaviorService = (BehaviorService) GetService(typeof(BehaviorService)); if (targetComponent != null && behaviorService != null && actionLists != null) { try { object actionUi = GetActionUI(behaviorService); FieldInfo fieldInfo1 = ReflectionHelpers.GetFieldInfo(actionUi, "designerActionHost", BindingFlags.Instance | BindingFlags.NonPublic); ToolStripDropDown designerActionHost = null; object mainParentWindow = ReflectionHelpers.GetValueField(actionUi, "mainParentWindow", BindingFlags.Instance | BindingFlags.NonPublic); if (!(fieldInfo1.GetValue(actionUi) is ToolStripDropDown)) { ConstructorInfo constructorInfo = ReflectionHelpers.GetConstructorInfo(fieldInfo1.FieldType, new Type[2] { actionUi.GetType(), typeof(IWin32Window) }); designerActionHost = constructorInfo.Invoke(new object[2] { actionUi, mainParentWindow }) as ToolStripDropDown; designerActionHost.AutoSize = false; designerActionHost.Padding = System.Windows.Forms.Padding.Empty; designerActionHost.Renderer = (ToolStripRenderer) new NoBorderRenderer(); designerActionHost.Text = "DesignerActionTopLevelForm"; fieldInfo1.SetValue(actionUi, (object) designerActionHost); } else { designerActionHost = fieldInfo1.GetValue(actionUi) as ToolStripDropDown; } Glyph glyph = ReflectionHelpers.InvokeMethod(actionUi, "GetDesignerActionGlyph", BindingFlags.Instance | BindingFlags.NonPublic, new object[2] { (object) targetComponent, (object) actionLists }) as Glyph; if (glyph != null) { BarUtilities.InvokeDelayed(new MethodInvoker(delegate { SetGlyphBounds(glyph, screenBounds, behaviorService); }), 100); if (designerActionHost != null) { designerActionHost.LocationChanged += HostLocationChanged; Point p = new Point(glyph.Bounds.Right, glyph.Bounds.Y); designerActionHost.Bounds = new Rectangle(behaviorService.AdornerWindowPointToScreen(p), designerActionHost.Size); } FieldInfo fieldInfo2 = ReflectionHelpers.GetFieldInfo((object) glyph.Behavior, "serviceProvider", BindingFlags.Instance | BindingFlags.NonPublic); GlyphServiceProvider glyphServiceProvider = new GlyphServiceProvider((IServiceProvider) fieldInfo2.GetValue((object) glyph.Behavior)); fieldInfo2.SetValue((object) glyph.Behavior, (object) glyphServiceProvider); //SmartTagInfoCache.Default.Add(info.TargetComponent, new SmartTagCacheElement(glyph, info.TargetComponent, (Control)null, actionUi, info.BehaviorService)); behaviorService.Adorners.Add(_DesignerActionAdorner); _DesignerActionAdorner.Glyphs.Add(glyph); //TestGlyph testGlyph = new TestGlyph(behaviorService, this); //_DesignerActionAdorner.Glyphs.Add(testGlyph); if (mainParentWindow is Control) ((Control) mainParentWindow).Invalidate(); } if (mainParentWindow is IWin32Window) { WinApi.RedrawWindow(((IWin32Window) mainParentWindow).Handle, IntPtr.Zero, IntPtr.Zero, (uint) (WinApi.RedrawWindowFlags.RDW_INVALIDATE | WinApi.RedrawWindowFlags.RDW_ALLCHILDREN)); } if (_ActionListToolStrip != designerActionHost) { if (_ActionListToolStrip != null) _ActionListToolStrip.LocationChanged -= HostLocationChanged; _ActionListToolStrip = designerActionHost; } return glyph; } catch { return (Glyph) null; } } return (Glyph) null; } private bool _SettingBounds = false; private void HostLocationChanged(object sender, EventArgs e) { if (_SettingBounds) return; ToolStripDropDown toolStripDropDown = sender as ToolStripDropDown; BehaviorService svc = (BehaviorService) this.GetService(typeof(BehaviorService)); if (toolStripDropDown == null || _DesignerGlyph == null || svc == null) return; _SettingBounds = true; Point p = new Point(_DesignerGlyph.Bounds.Right, _DesignerGlyph.Bounds.Y); Rectangle r = new Rectangle(svc.AdornerWindowPointToScreen(p), toolStripDropDown.Size); toolStripDropDown.Bounds = r; _SettingBounds = false; } private void SetGlyphBounds(Glyph gl, Rectangle itemBounds, BehaviorService behaviorService) { Size glyphSize = GetGlyphSize(); Point adornerWindow = behaviorService.ScreenToAdornerWindow(new Point(itemBounds.Right - 6, itemBounds.Y)); Point p = behaviorService.ScreenToAdornerWindow(Point.Empty); ReflectionHelpers.SetValueField((object) gl, "bounds", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField, (object) new Rectangle(adornerWindow, glyphSize)); InvalidateDesignerSurface(); } private class NoBorderRenderer : ToolStripProfessionalRenderer { public NoBorderRenderer() { } protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) { } } private object GetActionUI(BehaviorService behaviorService) { if (behaviorService == null) return null; return ReflectionHelpers.GetValueProperty((object) behaviorService, "DesignerActionUI", BindingFlags.Instance | BindingFlags.NonPublic); } private Rectangle GetGlyphBounds(Rectangle componentBounds) { Size glyphSize = GetGlyphSize(); return new Rectangle(componentBounds.Right - glyphSize.Width, componentBounds.Y, glyphSize.Width, glyphSize.Height); } private Size GetGlyphSize() { try { Type type = typeof(ControlDesigner).Assembly.GetType("System.Windows.Forms.DpiHelper"); if (type != (Type) null) { if ((bool) type.GetProperty("IsScalingRequired", BindingFlags.Static | BindingFlags.Public) .GetValue((object) null, (object[]) null)) { object[] parameters = new object[2] { (object) new Bitmap(10, 10), (object) 0 }; type.GetMethod("ScaleBitmapLogicalToDevice", BindingFlags.Static | BindingFlags.Public) .Invoke((object) null, parameters); return ((Image) parameters[0]).Size; } } } catch (Exception e) { Console.WriteLine(e); } return new Size(10, 10); } class TestBehavior : Behavior { } class TestGlyph : Glyph { ComponentDesignerWithAction _Item; BehaviorService _BehaviorSvc; public TestGlyph(BehaviorService behaviorSvc, ComponentDesignerWithAction item) : base(new TestBehavior()) { _BehaviorSvc = behaviorSvc; _Item = item; } public ComponentDesignerWithAction Item { get { return _Item; } } public override Rectangle Bounds { get { // Glyph coordinates are in adorner window coordinates, so we must map using the behavior service. Rectangle bounds = Rectangle.Empty; if (_Item != null && _Item.GetHostControl() != null) { Point edge = _BehaviorSvc.ControlToAdornerWindow(_Item.GetHostControl()); bounds = _Item.ComponentBounds; bounds.Offset(edge); } return bounds; } } public override Cursor GetHitTest(Point p) { if (_Item != null && !_Item.IsSelected) return null; // GetHitTest is called to see if the point is // within this glyph. This gives us a chance to decide // what cursor to show. Returning null from here means // the mouse pointer is not currently inside of the glyph. // Returning a valid cursor here indicates the pointer is // inside the glyph, and also enables our Behavior property // as the active behavior. if (Bounds.Contains(p)) { return Cursors.SizeAll; } return null; } public Rectangle CompleteBounds { get { Rectangle bounds = Rectangle.Empty; if (_Item != null && _Item.GetHostControl() != null) { Point edge = _BehaviorSvc.ControlToAdornerWindow(_Item.GetContainerControl()); bounds = _Item.ComponentBounds; bounds.Offset(edge); } return bounds; } } public override void Paint(PaintEventArgs pe) { // Draw our glyph if (_Item != null) { if (_Item.IsSelected) { Rectangle r = CompleteBounds; r.Width--; r.Height--; Graphics g = pe.Graphics; using(SolidBrush brush=new SolidBrush(Color.FromArgb(129,Color.Red))) { g.FillRectangle(brush, r); } } } } } } }