1 namespace System.Workflow.ComponentModel.Design 2 { 3 using System; 4 using System.IO; 5 using System.Data; 6 using System.Drawing; 7 using System.Security; 8 using System.Resources; 9 using System.Reflection; 10 using System.Diagnostics; 11 using System.Collections; 12 using System.Windows.Forms; 13 using System.ComponentModel; 14 using System.Drawing.Design; 15 using System.Drawing.Imaging; 16 using System.Drawing.Printing; 17 using System.Drawing.Drawing2D; 18 using System.Workflow.Interop; 19 using System.Collections.Generic; 20 using System.Windows.Forms.Design; 21 using System.Security.Permissions; 22 using System.ComponentModel.Design; 23 using System.Runtime.InteropServices; 24 using System.Collections.ObjectModel; 25 using System.Diagnostics.CodeAnalysis; 26 /// What did I change in this file 27 /// 1. Eliminated the layout manager and introduced classes for WorkflowLayout and PrintPreviewLayout 28 /// 2. Eliminated the event syncing of PageSetupData change. We call performlayout on the current designer service whenever the pagesetupdata changes 29 30 /// Designer Features: 31 /// Selection on click and thru drag rectangle 32 /// Reconfigurable background 33 /// Scrolling 34 /// Ensure Visible functionality 35 /// Accessibility 36 /// Zoom 37 /// Rehostable 38 /// Extensible 39 /// Small memory footprint 40 /// Ability to move around objects using drag drop 41 /// Ability to drop the objects using drag drop 42 /// Printing support 43 /// Theme support 44 /// Magnifier 45 /// AutoScroll 46 /// AutoExpand 47 /// USE THIS FOR PERFORMANCE TEST: Debug.WriteLine("******Root drawing: " + Convert.ToString((DateTime.Now.Ticks - ticks) / 10000) + "ms"); 48 /// 49 /// Here are some details about the coordinate system, 50 /// 51 /// Screen CoOrdinate System: Starts at 0,0 of the screen 52 /// Client CoOrdinate System: Starts at 0,0 of the control 53 /// Logical CoOrdinate System: The workflowview supports zooming and scroll, we want to hide this 54 /// complexity from the activity writter and hence whenever we get a coordinate we translate it based 55 /// scroll position, zoom level and layout. This helps us to sheild the activity designers from complexity 56 /// of zooming, scaling and layouting. The designer writters deal with one coordinate system which is unscaled and 57 /// starts at 0,0 58 /// 59 /// 60 61 [ToolboxItem(false)] 62 [ActivityDesignerTheme(typeof(AmbientTheme), Xml = WorkflowView.ThemeXml)] 63 [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] 64 public class WorkflowView : UserControl, IServiceProvider, IMessageFilter 65 { 66 #region Theme Initializer XML 67 internal const string ThemeXml = 68 "<AmbientTheme xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/workflow\"" + 69 " ApplyTo=\"System.Workflow.ComponentModel.Design.WorkflowView\"" + 70 " ShowConfigErrors=\"True\"" + 71 " DrawShadow=\"False\"" + 72 " DrawGrayscale=\"False\"" + 73 " DropIndicatorColor=\"0xFF006400\"" + 74 " SelectionForeColor=\"0xFF0000FF\"" + 75 " SelectionPatternColor=\"0xFF606060\"" + 76 " ForeColor=\"0xFF808080\"" + 77 " BackColor=\"0xFFFFFFFF\"" + 78 " ShowGrid=\"False\"" + 79 " GridColor=\"0xFFC0C0C0\"" + 80 " TextQuality=\"Aliased\"" + 81 " DrawRounded=\"True\"" + 82 " ShowDesignerBorder=\"True\"" + 83 " />"; 84 #endregion 85 86 #region Members Variables 87 [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] 88 private enum TabButtonIds { MultiPage = 1, Zoom, Pan } 89 90 //Designer Hookup 91 private IServiceProvider serviceProvider = null; 92 93 private ActivityDesigner rootDesigner = null; 94 95 //Zoom 96 private float zoomLevel = 1.0f; 97 private int shadowDepth = WorkflowTheme.CurrentTheme.AmbientTheme.ShadowDepth; 98 99 //MessageFilters 100 private List<WorkflowDesignerMessageFilter> stockMessageFilters = new List<WorkflowDesignerMessageFilter>(); 101 private List<WorkflowDesignerMessageFilter> customMessageFilters = new List<WorkflowDesignerMessageFilter>(); 102 103 // 104 105 private Bitmap viewPortBitmap = null; 106 107 //Misc. 108 private WorkflowToolTip workflowToolTip = null; 109 110 private CommandSet commandSet = null; 111 private DynamicAction fitAllAction = null; 112 113 //print 114 private int prePreviewZoom = 100; 115 private Point prePreviewScroll = Point.Empty; 116 private WorkflowPrintDocument printDocument = null; 117 118 //Active layout 119 private WorkflowLayout activeLayout = null; 120 private WorkflowLayout defaultLayout = null; 121 122 //One time callable delegates 123 private EventHandler layoutEventHandler = null; 124 private EventHandler ensureVisibleEventHandler = null; 125 126 private Stack<HitTestInfo> messageHitTestContexts = new Stack<HitTestInfo>(); 127 128 private HScrollBar hScrollBar; 129 private VScrollBar vScrollBar; 130 131 private TabControl toolContainer; 132 private EventHandler idleEventListeners; 133 private EventHandler idleEventHandler; 134 135 private bool dragDropInProgress; 136 #endregion 137 138 #region Events 139 public event EventHandler ZoomChanged; 140 public event EventHandler RootDesignerChanged; 141 #endregion 142 143 #region Constructor and Dispose WorkflowView()144 public WorkflowView() 145 : this(new DesignSurface()) 146 { 147 } 148 WorkflowView(IServiceProvider serviceProvider)149 public WorkflowView(IServiceProvider serviceProvider) 150 { 151 Debug.Assert(serviceProvider != null); 152 if (serviceProvider == null) 153 throw new ArgumentNullException("serviceProvider"); 154 155 SuspendLayout(); 156 AllowDrop = true; 157 AutoScroll = false; 158 HScroll = false; 159 VScroll = false; 160 SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.Opaque | ControlStyles.AllPaintingInWmPaint | ControlStyles.Selectable | ControlStyles.EnableNotifyMessage, true); 161 162 this.serviceProvider = serviceProvider; 163 164 //*****Promote the services which are accessed from other components 165 IServiceContainer serviceContainer = GetService(typeof(IServiceContainer)) as IServiceContainer; 166 if (serviceContainer != null) 167 { 168 //Remove any existing designer service if there is any 169 serviceContainer.RemoveService(typeof(WorkflowView)); 170 serviceContainer.AddService(typeof(WorkflowView), this); 171 } 172 173 //set the UI Service to be used by themes 174 IUIService uiService = this.serviceProvider.GetService(typeof(IUIService)) as IUIService; 175 if (uiService != null) 176 WorkflowTheme.UIService = uiService; 177 178 //Make sure that we add scrollbars 179 EnsureScrollBars(new HScrollBar(), new VScrollBar()); 180 181 //Initialize the tooltip shown 182 this.workflowToolTip = new WorkflowToolTip(this); 183 184 //Sync the global theme change event, which is fired by the theme infrastructure for theme change 185 WorkflowTheme.ThemeChanged += new EventHandler(OnThemeChange); 186 187 //Create the core message filters 188 PopulateMessageFilters(true); 189 190 //Set the root designer, note that the dynamic action is dependent on the DynamicActionMessageFilter pushed 191 //when the root is set. 192 RootDesigner = ActivityDesigner.GetSafeRootDesigner(this); 193 this.fitAllAction = CreateDynamicAction(); 194 195 //If the active layout is still null then we will set the default layout as active layout 196 if (this.activeLayout == null || this.defaultLayout == null) 197 ActiveLayout = DefaultLayout = new WorkflowRootLayout(this.serviceProvider); 198 199 //Create the local command set and update all the commands once 200 IMenuCommandService menuCommandService = GetService(typeof(IMenuCommandService)) as IMenuCommandService; 201 if (menuCommandService != null) 202 { 203 this.commandSet = new CommandSet(this); 204 this.commandSet.UpdatePanCommands(true); 205 } 206 207 //Subscribe to selection change 208 ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService; 209 if (selectionService != null) 210 selectionService.SelectionChanged += new EventHandler(OnSelectionChanged); 211 212 //In case of non VS case we need to pumpin the Keyboard messages, the user control sets 213 //focus to the child controls by default which is a problem so we need to trap the 214 //messages by adding application level message filter, in case of VS this is not required and 215 //the message filter is never called. 216 Application.AddMessageFilter(this); 217 218 //We make sure that during the construction we dont do perform layouts on idle event 219 ResumeLayout(true); 220 } 221 Dispose(bool disposing)222 protected override void Dispose(bool disposing) 223 { 224 //Remove the proffered services 225 if (disposing) 226 { 227 try 228 { 229 SuspendLayout(); 230 231 Application.RemoveMessageFilter(this); 232 233 if (this.layoutEventHandler != null) 234 { 235 Idle -= this.layoutEventHandler; 236 this.layoutEventHandler = null; 237 } 238 239 if (this.ensureVisibleEventHandler != null) 240 { 241 Idle -= this.ensureVisibleEventHandler; 242 this.ensureVisibleEventHandler = null; 243 } 244 245 if (this.idleEventHandler != null) 246 { 247 this.idleEventListeners = null; 248 249 Form host = TopLevelControl as Form; 250 if (!Application.MessageLoop || (host != null && host.Modal)) 251 WorkflowTimer.Default.Unsubscribe(this.idleEventHandler); 252 else 253 Application.Idle -= this.idleEventHandler; 254 this.idleEventHandler = null; 255 } 256 257 ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService; 258 if (selectionService != null) 259 selectionService.SelectionChanged -= new EventHandler(OnSelectionChanged); 260 261 //Unsubscribe the theme change 262 WorkflowTheme.ThemeChanged -= new EventHandler(OnThemeChange); 263 264 //Remove the dynamic action 265 if (this.fitAllAction != null) 266 { 267 this.fitAllAction.Dispose(); 268 this.fitAllAction = null; 269 } 270 271 if (this.workflowToolTip != null) 272 { 273 ((IDisposable)this.workflowToolTip).Dispose(); 274 this.workflowToolTip = null; 275 } 276 277 DisposeMessageFilters(false); 278 DisposeMessageFilters(true); 279 280 //Dispose the layouts 281 this.activeLayout = null; 282 if (this.defaultLayout != null) 283 { 284 this.defaultLayout.Dispose(); 285 this.defaultLayout = null; 286 } 287 288 //Destroy other resources 289 if (this.viewPortBitmap != null) 290 { 291 this.viewPortBitmap.Dispose(); 292 this.viewPortBitmap = null; 293 } 294 295 if (this.commandSet != null) 296 { 297 this.commandSet.Dispose(); 298 this.commandSet = null; 299 } 300 301 HScrollBar.ValueChanged -= new EventHandler(OnScroll); 302 VScrollBar.ValueChanged -= new EventHandler(OnScroll); 303 304 if (this.toolContainer != null) 305 { 306 Controls.Remove(this.toolContainer); 307 this.toolContainer.TabStrip.Tabs.Clear(); 308 this.toolContainer.Dispose(); 309 this.toolContainer = null; 310 } 311 312 IServiceContainer serviceContainer = GetService(typeof(IServiceContainer)) as IServiceContainer; 313 if (serviceContainer != null) 314 { 315 serviceContainer.RemoveService(typeof(WorkflowView)); 316 } 317 } 318 finally 319 { 320 ResumeLayout(false); 321 } 322 } 323 324 base.Dispose(disposing); 325 } 326 #endregion 327 328 #region Public Properties 329 public int Zoom 330 { 331 get 332 { 333 return Convert.ToInt32(this.zoomLevel * 100); 334 } 335 336 set 337 { 338 if (Zoom == value) 339 return; 340 341 if (value < AmbientTheme.MinZoom || value > AmbientTheme.MaxZoom) 342 throw new NotSupportedException(DR.GetString(DR.ZoomLevelException2, AmbientTheme.MinZoom, AmbientTheme.MaxZoom)); 343 344 ScrollBar hScrollBar = HScrollBar; 345 ScrollBar vScrollBar = VScrollBar; 346 347 if (hScrollBar != null && vScrollBar != null) 348 { 349 PointF oldRelativeCenter = Point.Empty; 350 Point oldCenter = new Point(ScrollPosition.X, ScrollPosition.Y); 351 oldRelativeCenter = new PointF((float)oldCenter.X / (float)hScrollBar.Maximum, (float)oldCenter.Y / (float)vScrollBar.Maximum); 352 353 //recalculate the zoom and scroll range 354 this.zoomLevel = (float)value / 100.0f; 355 UpdateScrollRange(); 356 357 //center the view again 358 Point newCenter = new Point((int)((float)hScrollBar.Maximum * oldRelativeCenter.X), (int)((float)vScrollBar.Maximum * oldRelativeCenter.Y)); 359 ScrollPosition = new Point(newCenter.X, newCenter.Y); 360 361 if (this.rootDesigner != null) 362 this.rootDesigner.Location = this.activeLayout.RootDesignerAlignment; 363 364 InvalidateClientRectangle(Rectangle.Empty); 365 366 // 367 368 this.activeLayout.Update(null, WorkflowLayout.LayoutUpdateReason.ZoomChanged); 369 370 //force command refresh 371 //this is to workarond VS not refreshing Zoom drop down when doing area zoom-in 372 IUIService uis = GetService(typeof(IUIService)) as IUIService; 373 if (uis != null) 374 uis.SetUIDirty(); 375 376 //We need to update the zoom commands when the zoom is updated 377 if (this.commandSet != null) 378 this.commandSet.UpdateZoomCommands(true); 379 380 OnZoomChanged(); 381 } 382 } 383 } 384 385 public ActivityDesigner RootDesigner 386 { 387 get 388 { 389 return this.rootDesigner; 390 } 391 392 set 393 { 394 if (this.rootDesigner == value) 395 return; 396 397 DisposeMessageFilters(false); 398 399 this.rootDesigner = value; 400 401 if (this.rootDesigner != null) 402 { 403 PopulateMessageFilters(false); 404 ActiveLayout = DefaultLayout = this.rootDesigner.SupportedLayout; 405 } 406 407 OnRootDesignerChanged(); 408 409 base.PerformLayout(); 410 } 411 } 412 413 public int ShadowDepth 414 { 415 get 416 { 417 return this.shadowDepth; 418 } 419 420 set 421 { 422 if (value < AmbientTheme.MinShadowDepth || value > AmbientTheme.MaxShadowDepth) 423 throw new NotSupportedException(DR.GetString(DR.ShadowDepthException, AmbientTheme.MinShadowDepth, AmbientTheme.MaxShadowDepth)); 424 425 if (this.shadowDepth == value) 426 return; 427 428 this.shadowDepth = value; 429 InvalidateClientRectangle(Rectangle.Empty); 430 } 431 } 432 433 public Rectangle ViewPortRectangle 434 { 435 get 436 { 437 return new Rectangle(ScrollPosition, ViewPortSize); 438 } 439 } 440 441 public Size ViewPortSize 442 { 443 get 444 { 445 Size viewPortSize = ClientSize; 446 if (HScrollBar.Visible) 447 viewPortSize.Height = Math.Max(0, viewPortSize.Height - HScrollBar.Height); 448 if (VScrollBar.Visible) 449 viewPortSize.Width = Math.Max(0, viewPortSize.Width - VScrollBar.Width); 450 return viewPortSize; 451 } 452 } 453 454 public Point ScrollPosition 455 { 456 get 457 { 458 return new Point(HScrollBar.Value, VScrollBar.Value); 459 } 460 461 set 462 { 463 ScrollBar hScrollBar = HScrollBar; 464 if (hScrollBar != null) 465 { 466 value.X = Math.Min(value.X, hScrollBar.Maximum - hScrollBar.LargeChange + 1); 467 value.X = Math.Max(value.X, hScrollBar.Minimum); 468 hScrollBar.Value = value.X; 469 } 470 471 ScrollBar vScrollBar = VScrollBar; 472 if (vScrollBar != null) 473 { 474 value.Y = Math.Min(value.Y, vScrollBar.Maximum - vScrollBar.LargeChange + 1); 475 value.Y = Math.Max(value.Y, vScrollBar.Minimum); 476 vScrollBar.Value = value.Y; 477 } 478 } 479 } 480 481 public bool PrintPreviewMode 482 { 483 get 484 { 485 return (this.activeLayout == ((WorkflowPrintDocument)PrintDocument).PrintPreviewLayout); 486 } 487 488 set 489 { 490 if (PrintPreviewMode == value) 491 return; 492 493 if (value && PrinterSettings.InstalledPrinters.Count == 0) 494 { 495 DesignerHelpers.ShowError(this, DR.GetString(DR.ThereIsNoPrinterInstalledErrorMessage)); 496 value = false; 497 } 498 499 ActiveLayout = (value) ? ((WorkflowPrintDocument)PrintDocument).PrintPreviewLayout : DefaultLayout; 500 501 if (this.commandSet != null) 502 this.commandSet.UpdatePageLayoutCommands(true); 503 504 if (PrintPreviewMode) 505 { 506 this.prePreviewZoom = Zoom; 507 this.prePreviewScroll = ScrollPosition; 508 Zoom = 40; 509 } 510 else 511 { 512 Zoom = this.prePreviewZoom; 513 ScrollPosition = this.prePreviewScroll; 514 } 515 } 516 } 517 518 public PrintDocument PrintDocument 519 { 520 get 521 { 522 if (this.printDocument == null) 523 this.printDocument = new WorkflowPrintDocument(this); 524 525 return this.printDocument; 526 } 527 } 528 529 public event EventHandler Idle 530 { 531 add 532 { 533 //Add the listener to our list 534 this.idleEventListeners += value; 535 536 if (this.idleEventHandler == null) 537 { 538 this.idleEventHandler = new EventHandler(OnWorkflowIdle); 539 540 Form host = TopLevelControl as Form; 541 if (!Application.MessageLoop || (host != null && host.Modal)) 542 WorkflowTimer.Default.Subscribe(100, this.idleEventHandler); 543 else 544 Application.Idle += this.idleEventHandler; 545 } 546 } 547 548 remove 549 { 550 this.idleEventListeners -= value; 551 552 if (this.idleEventHandler != null && this.idleEventListeners == null) 553 { 554 Form host = TopLevelControl as Form; 555 if (host != null && host.Modal) 556 WorkflowTimer.Default.Unsubscribe(this.idleEventHandler); 557 else 558 Application.Idle -= this.idleEventHandler; 559 560 this.idleEventHandler = null; 561 } 562 } 563 } 564 565 public HScrollBar HScrollBar 566 { 567 get 568 { 569 return this.hScrollBar; 570 } 571 } 572 573 public VScrollBar VScrollBar 574 { 575 get 576 { 577 return this.vScrollBar; 578 } 579 } 580 581 public bool EnableFitToScreen 582 { 583 get 584 { 585 return (this.fitAllAction != null); 586 } 587 588 set 589 { 590 if (EnableFitToScreen == value) 591 return; 592 593 if (value) 594 { 595 if (this.fitAllAction == null) 596 this.fitAllAction = CreateDynamicAction(); 597 } 598 else 599 { 600 if (this.fitAllAction != null) 601 { 602 this.fitAllAction.Dispose(); 603 this.fitAllAction = null; 604 } 605 } 606 607 InvalidateClientRectangle(Rectangle.Empty); 608 } 609 } 610 #endregion 611 612 #region Protected Properties 613 #endregion 614 615 #region Private Properties 616 internal bool DragDropInProgress 617 { 618 get 619 { 620 return this.dragDropInProgress; 621 } 622 } 623 624 internal bool ShowToolContainer 625 { 626 get 627 { 628 return (this.toolContainer != null); 629 } 630 631 set 632 { 633 if (ShowToolContainer == value) 634 return; 635 636 try 637 { 638 SuspendLayout(); 639 640 if (value) 641 { 642 this.toolContainer = new TabControl(DockStyle.Right, AnchorAlignment.Far); 643 Controls.Add(this.toolContainer); 644 EnsureScrollBars(this.hScrollBar, this.toolContainer.ScrollBar as VScrollBar); 645 646 string[,] tabButtonInfo = new string[/*Caption Resource ID*/, /*Bitmap Resource ID*/] { { "MultipageLayoutCaption", "MultipageLayout" }, { "ZoomCaption", "Zoom" }, { "PanCaption", "AutoPan" } }; 647 for (int i = 0; i < tabButtonInfo.GetLength(0); i++) 648 { 649 Bitmap tabImage = DR.GetImage(tabButtonInfo[i, 1]) as Bitmap; 650 string buttonCaption = DR.GetString(tabButtonInfo[i, 0]); 651 this.toolContainer.TabStrip.Tabs.Add(new ItemInfo(i + 1, tabImage, buttonCaption)); 652 } 653 654 this.toolContainer.TabStrip.TabChange += new SelectionChangeEventHandler<TabSelectionChangeEventArgs>(OnTabChange); 655 if (this.commandSet != null) 656 { 657 this.commandSet.UpdatePageLayoutCommands(true); 658 this.commandSet.UpdateZoomCommands(true); 659 this.commandSet.UpdatePanCommands(true); 660 } 661 } 662 else 663 { 664 this.toolContainer.TabStrip.TabChange -= new SelectionChangeEventHandler<TabSelectionChangeEventArgs>(OnTabChange); 665 this.toolContainer.TabStrip.Tabs.Clear(); 666 667 Controls.Remove(this.toolContainer); 668 this.toolContainer.Dispose(); 669 this.toolContainer = null; 670 671 EnsureScrollBars(this.hScrollBar, new VScrollBar()); 672 } 673 } 674 finally 675 { 676 ResumeLayout(true); 677 } 678 } 679 } 680 681 internal HitTestInfo MessageHitTestContext 682 { 683 get 684 { 685 return this.messageHitTestContexts.Peek(); 686 } 687 } 688 689 internal WorkflowLayout ActiveLayout 690 { 691 get 692 { 693 return this.activeLayout; 694 } 695 696 set 697 { 698 Debug.Assert(value != null); 699 if (value == null) 700 throw new ArgumentNullException("Layout cannot be null!"); 701 702 Cursor cursor = Cursor.Current; 703 try 704 { 705 Cursor.Current = Cursors.WaitCursor; 706 707 this.activeLayout = value; 708 if (this.activeLayout != ((WorkflowPrintDocument)PrintDocument).PrintPreviewLayout) 709 DefaultLayout = this.activeLayout; 710 711 base.PerformLayout(); 712 if (this.commandSet != null) 713 this.commandSet.UpdatePageLayoutCommands(true); 714 } 715 finally 716 { 717 Cursor.Current = cursor; 718 } 719 } 720 } 721 722 private WorkflowLayout DefaultLayout 723 { 724 get 725 { 726 if (this.defaultLayout == null) 727 this.defaultLayout = new WorkflowRootLayout(this); 728 return this.defaultLayout; 729 } 730 731 set 732 { 733 if (value == null) 734 throw new ArgumentNullException(DR.GetString(DR.Error_WorkflowLayoutNull)); 735 736 if (this.defaultLayout == value) 737 return; 738 739 if (this.defaultLayout != null) 740 this.defaultLayout.Dispose(); 741 742 this.defaultLayout = value; 743 } 744 } 745 746 private float ScaleZoomFactor 747 { 748 get 749 { 750 return (this.zoomLevel * this.activeLayout.Scaling); 751 } 752 } 753 #endregion 754 755 #region Public Methods AddDesignerMessageFilter(WorkflowDesignerMessageFilter designerMessageFilter)756 public void AddDesignerMessageFilter(WorkflowDesignerMessageFilter designerMessageFilter) 757 { 758 if (designerMessageFilter == null) 759 throw new ArgumentNullException("designerMessageFilter"); 760 761 if (Capture) 762 Capture = false; 763 764 this.customMessageFilters.Insert(0, designerMessageFilter); 765 designerMessageFilter.SetParentView(this); 766 } 767 RemoveDesignerMessageFilter(WorkflowDesignerMessageFilter designerMessageFilter)768 public void RemoveDesignerMessageFilter(WorkflowDesignerMessageFilter designerMessageFilter) 769 { 770 if (designerMessageFilter == null) 771 throw new ArgumentNullException("designerMessageFilter"); 772 773 if (this.customMessageFilters.Contains(designerMessageFilter)) 774 { 775 if (Capture) 776 Capture = false; 777 778 this.customMessageFilters.Remove(designerMessageFilter); 779 ((IDisposable)designerMessageFilter).Dispose(); 780 } 781 } 782 ShowInPlaceToolTip(string toolTipText, Rectangle toolTipRectangle)783 public void ShowInPlaceToolTip(string toolTipText, Rectangle toolTipRectangle) 784 { 785 if (toolTipText == null) 786 throw new ArgumentNullException("toolTipText"); 787 788 if (toolTipRectangle.IsEmpty) 789 throw new ArgumentException(SR.GetString(SR.Error_EmptyToolTipRectangle)); 790 791 this.workflowToolTip.SetText(toolTipText, toolTipRectangle); 792 } 793 ShowInfoTip(string text)794 public void ShowInfoTip(string text) 795 { 796 if (text == null) 797 throw new ArgumentNullException("text"); 798 799 this.workflowToolTip.SetText(String.Empty, text); 800 } 801 ShowInfoTip(string title, string text)802 public void ShowInfoTip(string title, string text) 803 { 804 if (title == null) 805 throw new ArgumentNullException("title"); 806 807 if (text == null) 808 throw new ArgumentNullException("text"); 809 810 this.workflowToolTip.SetText(title, text); 811 } 812 EnsureVisible(object selectableObject)813 public void EnsureVisible(object selectableObject) 814 { 815 if (selectableObject == null) 816 throw new ArgumentNullException("selectableObject"); 817 818 // make sure that all the parents are expanded 819 Activity activity = selectableObject as Activity; 820 while (activity != null) 821 { 822 ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(activity); 823 CompositeActivityDesigner parentDesigner = activityDesigner.ParentDesigner; 824 if (parentDesigner != null) 825 { 826 if (activityDesigner != null) 827 parentDesigner.EnsureVisibleContainedDesigner(activityDesigner); 828 activity = parentDesigner.Activity; 829 } 830 else 831 { 832 activity = null; 833 } 834 } 835 836 //this is to handle the case when we call ensure visible of a scope which currently has 837 //activity from the secondary flow selected. instead we should always switch to the main flow 838 activity = selectableObject as Activity; 839 if (activity != null) 840 { 841 CompositeActivityDesigner compositeDesigner = ActivityDesigner.GetDesigner(activity) as CompositeActivityDesigner; 842 if (compositeDesigner != null) 843 compositeDesigner.EnsureVisibleContainedDesigner(compositeDesigner); 844 } 845 846 PerformLayout(false); 847 848 if (this.ensureVisibleEventHandler == null) 849 { 850 this.ensureVisibleEventHandler = new EventHandler(OnEnsureVisible); 851 Idle += this.ensureVisibleEventHandler; 852 } 853 } 854 PerformLayout(bool immediateUpdate)855 public void PerformLayout(bool immediateUpdate) 856 { 857 if (immediateUpdate) 858 { 859 if (this.layoutEventHandler != null) 860 { 861 Idle -= this.layoutEventHandler; 862 this.layoutEventHandler = null; 863 } 864 base.PerformLayout(); //invalidate rectangle really cares for the this.layoutEventHandler being null 865 } 866 else if (this.layoutEventHandler == null) 867 { 868 this.layoutEventHandler = new EventHandler(OnPerformLayout); 869 Idle += this.layoutEventHandler; 870 } 871 } 872 SaveViewState(Stream viewState)873 public void SaveViewState(Stream viewState) 874 { 875 if (viewState == null) 876 throw new ArgumentNullException("viewState"); 877 878 IDesignerHost designerHost = (IDesignerHost)GetService(typeof(IDesignerHost)); 879 if (designerHost == null) 880 throw new Exception(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName)); 881 882 BinaryWriter writer = new BinaryWriter(viewState); 883 884 // write workflow properties 885 writer.Write(this.PrintPreviewMode); 886 writer.Write(this.Zoom); 887 888 // write components 889 DesignerHelpers.SerializeDesignerStates(designerHost, writer); 890 891 // write scroll position 892 writer.Write(this.ScrollPosition.X); 893 writer.Write(this.ScrollPosition.Y); 894 } 895 LoadViewState(Stream viewState)896 public void LoadViewState(Stream viewState) 897 { 898 if (viewState == null) 899 throw new ArgumentNullException("viewState"); 900 901 bool outdated = false; 902 Point scrollPosition = new Point(0, 0); 903 904 IDesignerHost designerHost = (IDesignerHost)GetService(typeof(IDesignerHost)); 905 if (designerHost == null) 906 throw new Exception(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName)); 907 908 viewState.Position = 0; 909 910 BinaryReader reader = new BinaryReader(viewState); 911 912 // read workflow properties 913 this.PrintPreviewMode = reader.ReadBoolean(); 914 this.Zoom = reader.ReadInt32(); 915 try 916 { 917 // get activities 918 outdated = DesignerHelpers.DeserializeDesignerStates(designerHost, reader); 919 920 // we will apply the scrolling only if if there is perfect match 921 // between the components in the workflow and the persisted data. 922 // It might be different if files were updated outside of VS, or if 923 // VS crashes. 924 if (!outdated) 925 { 926 scrollPosition.X = reader.ReadInt32(); 927 scrollPosition.Y = reader.ReadInt32(); 928 } 929 } 930 finally 931 { 932 // flush the layout to apply the new settings, this will set the scrollers extents 933 base.PerformLayout(); 934 this.ScrollPosition = scrollPosition; 935 } 936 } 937 938 /// <summary> 939 /// Changes zoom level on the design surface such that the entire workflow is displayed in the view 940 /// </summary> FitToScreenSize()941 public void FitToScreenSize() 942 { 943 if (HScrollBar.Maximum > ViewPortSize.Width || VScrollBar.Maximum > ViewPortSize.Height) 944 { 945 int newZoom = (int)(100.0f / ActiveLayout.Scaling * Math.Min((float)ViewPortSize.Width / (float)ActiveLayout.Extent.Width, (float)ViewPortSize.Height / (float)ActiveLayout.Extent.Height)); 946 Zoom = Math.Min(Math.Max(newZoom, AmbientTheme.MinZoom), AmbientTheme.MaxZoom); 947 } 948 } 949 950 /// <summary> 951 /// Sets the zoom level to 100% so that the workflow size is restored to actial workflow size 952 /// </summary> FitToWorkflowSize()953 public void FitToWorkflowSize() 954 { 955 if (Zoom != 100) 956 Zoom = 100; 957 } 958 959 /// <summary> 960 /// Saves workflow as image to a file based on the format specified 961 /// </summary> 962 /// <param name="imageFile">Path to file where to save the image</param> 963 /// <param name="imageFormat">Format in which to save the image</param> SaveWorkflowImage(string imageFile, ImageFormat imageFormat)964 public void SaveWorkflowImage(string imageFile, ImageFormat imageFormat) 965 { 966 if (imageFile == null) 967 throw new ArgumentNullException("imageFile"); 968 969 if (imageFormat == null) 970 throw new ArgumentNullException("imageFormat"); 971 972 Bitmap workflowBitmap = TakeWorkflowSnapShot(); 973 if (workflowBitmap != null) 974 { 975 workflowBitmap.Save(imageFile, imageFormat); 976 workflowBitmap.Dispose(); 977 } 978 } 979 980 /// <summary> 981 /// Saves workflow as image to a stream based on encoding specified 982 /// </summary> 983 /// <param name="stream">Stream where to save the workflow</param> 984 /// <param name="imageFormat">Format in which to save the image</param> SaveWorkflowImage(Stream stream, ImageFormat imageFormat)985 public void SaveWorkflowImage(Stream stream, ImageFormat imageFormat) 986 { 987 if (stream == null) 988 throw new ArgumentNullException("stream"); 989 990 if (imageFormat == null) 991 throw new ArgumentNullException("imageFormat"); 992 993 Bitmap workflowBitmap = TakeWorkflowSnapShot(); 994 if (workflowBitmap != null) 995 { 996 workflowBitmap.Save(stream, imageFormat); 997 workflowBitmap.Dispose(); 998 } 999 } 1000 1001 /// <summary> 1002 /// Stores the workflow image to clipboard. 1003 /// </summary> SaveWorkflowImageToClipboard()1004 public void SaveWorkflowImageToClipboard() 1005 { 1006 Bitmap workflowBitmap = TakeWorkflowSnapShot(); 1007 if (workflowBitmap != null) 1008 { 1009 Clipboard.SetDataObject(workflowBitmap, true); 1010 workflowBitmap.Dispose(); 1011 } 1012 } 1013 #endregion 1014 1015 #region Protected Methods 1016 1017 #region Overridden Methods handling UI events 1018 #region Drawing OnPaint(PaintEventArgs e)1019 protected override void OnPaint(PaintEventArgs e) 1020 { 1021 base.OnPaint(e); 1022 1023 //We set the highest quality interpolation so that we do not loose the image quality 1024 GraphicsContainer graphicsState = e.Graphics.BeginContainer(); 1025 e.Graphics.SmoothingMode = SmoothingMode.HighQuality; 1026 e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 1027 e.Graphics.CompositingQuality = CompositingQuality.HighQuality; 1028 1029 bool takeWorkflowSnapShot = (this.viewPortBitmap == null || this.viewPortBitmap.Size != ViewPortSize); 1030 if (takeWorkflowSnapShot) 1031 { 1032 if (this.viewPortBitmap != null) 1033 this.viewPortBitmap.Dispose(); 1034 this.viewPortBitmap = new Bitmap(Math.Max(1, ViewPortSize.Width), Math.Max(1, ViewPortSize.Height), e.Graphics); 1035 } 1036 1037 //Create viewport information and take the workflow snapshot before passing on the information to the active layout 1038 ViewPortData viewPortData = new ViewPortData(); 1039 viewPortData.LogicalViewPort = ClientRectangleToLogical(new Rectangle(Point.Empty, ViewPortSize)); 1040 viewPortData.MemoryBitmap = this.viewPortBitmap; 1041 viewPortData.Scaling = new SizeF(ScaleZoomFactor, ScaleZoomFactor); 1042 viewPortData.Translation = ScrollPosition; 1043 viewPortData.ShadowDepth = new Size(this.shadowDepth, this.shadowDepth); 1044 viewPortData.ViewPortSize = ViewPortSize; 1045 1046 //capture the workflow onto in-memory bitmap 1047 if (this.layoutEventHandler == null || takeWorkflowSnapShot) 1048 WorkflowView.TakeWorkflowSnapShot(this, viewPortData); 1049 1050 //copy workflow from the bitmap onto corresponding pages on the screen 1051 try 1052 { 1053 this.activeLayout.OnPaintWorkflow(e, viewPortData); 1054 } 1055 catch (Exception ex) 1056 { 1057 //If a layout throws an exception then we will not draw the layout 1058 // 1059 Debug.WriteLine(ex); 1060 } 1061 1062 //If any of the message filters throws an exception we continue to draw 1063 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty)) 1064 { 1065 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1066 { 1067 try 1068 { 1069 if (((IWorkflowDesignerMessageSink)filter).OnPaintWorkflowAdornments(e, ViewPortRectangle)) 1070 break; 1071 } 1072 catch (Exception ex) 1073 { 1074 //Ignore the filter throwing the exception and continue to function 1075 Debug.WriteLine(ex); 1076 } 1077 } 1078 } 1079 1080 e.Graphics.EndContainer(graphicsState); 1081 1082 e.Graphics.FillRectangle(SystemBrushes.Control, new Rectangle(Width - SystemInformation.VerticalScrollBarWidth, Height - SystemInformation.HorizontalScrollBarHeight, SystemInformation.VerticalScrollBarWidth, SystemInformation.HorizontalScrollBarHeight)); 1083 } 1084 OnZoomChanged()1085 protected virtual void OnZoomChanged() 1086 { 1087 if (this.ZoomChanged != null) 1088 this.ZoomChanged(this, EventArgs.Empty); 1089 } 1090 OnRootDesignerChanged()1091 protected virtual void OnRootDesignerChanged() 1092 { 1093 if (this.RootDesignerChanged != null) 1094 this.RootDesignerChanged(this, EventArgs.Empty); 1095 } 1096 #endregion 1097 1098 #region Mouse Events OnMouseDown(MouseEventArgs e)1099 protected override void OnMouseDown(MouseEventArgs e) 1100 { 1101 base.OnMouseDown(e); 1102 1103 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e)) 1104 { 1105 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1106 { 1107 if (((IWorkflowDesignerMessageSink)filter).OnMouseDown(e)) 1108 break; 1109 } 1110 } 1111 } 1112 OnMouseMove(MouseEventArgs e)1113 protected override void OnMouseMove(MouseEventArgs e) 1114 { 1115 base.OnMouseMove(e); 1116 1117 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e)) 1118 { 1119 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1120 { 1121 if (((IWorkflowDesignerMessageSink)filter).OnMouseMove(e)) 1122 break; 1123 } 1124 } 1125 } 1126 OnMouseUp(MouseEventArgs e)1127 protected override void OnMouseUp(MouseEventArgs e) 1128 { 1129 base.OnMouseUp(e); 1130 1131 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e)) 1132 { 1133 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1134 { 1135 if (((IWorkflowDesignerMessageSink)filter).OnMouseUp(e)) 1136 break; 1137 } 1138 } 1139 } 1140 OnMouseDoubleClick(MouseEventArgs e)1141 protected override void OnMouseDoubleClick(MouseEventArgs e) 1142 { 1143 base.OnMouseDoubleClick(e); 1144 1145 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e)) 1146 { 1147 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1148 { 1149 if (((IWorkflowDesignerMessageSink)filter).OnMouseDoubleClick(e)) 1150 break; 1151 } 1152 } 1153 } 1154 OnMouseEnter(EventArgs e)1155 protected override void OnMouseEnter(EventArgs e) 1156 { 1157 base.OnMouseEnter(e); 1158 1159 Point clientPoint = PointToClient(Control.MousePosition); 1160 MouseEventArgs eventArgs = new MouseEventArgs(Control.MouseButtons, 1, clientPoint.X, clientPoint.Y, 0); 1161 1162 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, eventArgs)) 1163 { 1164 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1165 { 1166 if (((IWorkflowDesignerMessageSink)filter).OnMouseEnter(eventArgs)) 1167 break; 1168 } 1169 } 1170 } 1171 OnMouseHover(EventArgs e)1172 protected override void OnMouseHover(EventArgs e) 1173 { 1174 base.OnMouseHover(e); 1175 1176 Point clientPoint = PointToClient(Control.MousePosition); 1177 MouseEventArgs eventArgs = new MouseEventArgs(Control.MouseButtons, 1, clientPoint.X, clientPoint.Y, 0); 1178 1179 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, eventArgs)) 1180 { 1181 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1182 { 1183 if (((IWorkflowDesignerMessageSink)filter).OnMouseHover(eventArgs)) 1184 break; 1185 } 1186 } 1187 } 1188 OnMouseLeave(EventArgs e)1189 protected override void OnMouseLeave(EventArgs e) 1190 { 1191 base.OnMouseLeave(e); 1192 1193 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty)) 1194 { 1195 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1196 { 1197 if (((IWorkflowDesignerMessageSink)filter).OnMouseLeave()) 1198 break; 1199 } 1200 } 1201 } 1202 OnMouseCaptureChanged(EventArgs e)1203 protected override void OnMouseCaptureChanged(EventArgs e) 1204 { 1205 base.OnMouseCaptureChanged(e); 1206 1207 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty)) 1208 { 1209 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1210 { 1211 if (((IWorkflowDesignerMessageSink)filter).OnMouseCaptureChanged()) 1212 break; 1213 } 1214 } 1215 } 1216 OnMouseWheel(MouseEventArgs e)1217 protected override void OnMouseWheel(MouseEventArgs e) 1218 { 1219 base.OnMouseWheel(e); 1220 1221 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e)) 1222 { 1223 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1224 { 1225 if (((IWorkflowDesignerMessageSink)filter).OnMouseWheel(e)) 1226 break; 1227 } 1228 } 1229 } 1230 #endregion 1231 1232 #region Keyboard Events OnKeyDown(KeyEventArgs e)1233 protected override void OnKeyDown(KeyEventArgs e) 1234 { 1235 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e)) 1236 { 1237 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1238 { 1239 if (((IWorkflowDesignerMessageSink)filter).OnKeyDown(e)) 1240 break; 1241 } 1242 } 1243 1244 if (!e.Handled) 1245 base.OnKeyDown(e); 1246 } 1247 OnKeyUp(KeyEventArgs e)1248 protected override void OnKeyUp(KeyEventArgs e) 1249 { 1250 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e)) 1251 { 1252 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1253 { 1254 if (((IWorkflowDesignerMessageSink)filter).OnKeyUp(e)) 1255 break; 1256 } 1257 } 1258 1259 if (!e.Handled) 1260 base.OnKeyUp(e); 1261 } 1262 #endregion 1263 1264 #region Layouting Events OnLayout(LayoutEventArgs levent)1265 protected override void OnLayout(LayoutEventArgs levent) 1266 { 1267 base.OnLayout(levent); 1268 1269 ScrollBar hScrollBar = HScrollBar; 1270 ScrollBar vScrollBar = VScrollBar; 1271 1272 if (Controls.Contains(hScrollBar)) 1273 hScrollBar.Bounds = new Rectangle(0, Math.Max(0, Height - SystemInformation.HorizontalScrollBarHeight), Math.Max(Width - ((vScrollBar.Visible) ? SystemInformation.VerticalScrollBarWidth : 0), 0), SystemInformation.HorizontalScrollBarHeight); 1274 1275 if (Controls.Contains(vScrollBar)) 1276 vScrollBar.Bounds = new Rectangle(Math.Max(0, Width - SystemInformation.VerticalScrollBarWidth), 0, SystemInformation.VerticalScrollBarWidth, Math.Max(Height - ((hScrollBar.Visible) ? SystemInformation.HorizontalScrollBarHeight : 0), 0)); 1277 1278 if (this.toolContainer != null) 1279 { 1280 this.toolContainer.Location = new Point(Width - this.toolContainer.Width, 0); 1281 this.toolContainer.Height = Height - ((hScrollBar.Visible) ? hScrollBar.Height : 0); 1282 } 1283 1284 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, levent)) 1285 { 1286 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1287 ((IWorkflowDesignerMessageSink)filter).OnLayout(levent); 1288 } 1289 1290 //Layout the designers 1291 using (Graphics graphics = CreateGraphics()) 1292 { 1293 this.activeLayout.Update(graphics, WorkflowLayout.LayoutUpdateReason.LayoutChanged); 1294 1295 if (this.rootDesigner != null) 1296 this.rootDesigner.Location = this.activeLayout.RootDesignerAlignment; 1297 } 1298 1299 //Update the scroll range and redraw 1300 UpdateScrollRange(); 1301 InvalidateClientRectangle(Rectangle.Empty); 1302 } 1303 #endregion 1304 1305 #region DragDrop Events OnDragEnter(DragEventArgs dragEventArgs)1306 protected override void OnDragEnter(DragEventArgs dragEventArgs) 1307 { 1308 base.OnDragEnter(dragEventArgs); 1309 1310 this.dragDropInProgress = true; 1311 1312 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, dragEventArgs)) 1313 { 1314 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1315 { 1316 if (((IWorkflowDesignerMessageSink)filter).OnDragEnter(dragEventArgs)) 1317 break; 1318 } 1319 } 1320 } 1321 OnDragOver(DragEventArgs dragEventArgs)1322 protected override void OnDragOver(DragEventArgs dragEventArgs) 1323 { 1324 base.OnDragOver(dragEventArgs); 1325 1326 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, dragEventArgs)) 1327 { 1328 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1329 { 1330 if (((IWorkflowDesignerMessageSink)filter).OnDragOver(dragEventArgs)) 1331 break; 1332 } 1333 } 1334 } 1335 OnDragLeave(EventArgs e)1336 protected override void OnDragLeave(EventArgs e) 1337 { 1338 base.OnDragLeave(e); 1339 1340 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty)) 1341 { 1342 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1343 { 1344 if (((IWorkflowDesignerMessageSink)filter).OnDragLeave()) 1345 break; 1346 } 1347 } 1348 1349 this.dragDropInProgress = false; 1350 } 1351 OnDragDrop(DragEventArgs dragEventArgs)1352 protected override void OnDragDrop(DragEventArgs dragEventArgs) 1353 { 1354 base.OnDragDrop(dragEventArgs); 1355 1356 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, dragEventArgs)) 1357 { 1358 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1359 { 1360 if (((IWorkflowDesignerMessageSink)filter).OnDragDrop(dragEventArgs)) 1361 break; 1362 } 1363 } 1364 1365 this.dragDropInProgress = false; 1366 } 1367 OnGiveFeedback(GiveFeedbackEventArgs gfbevent)1368 protected override void OnGiveFeedback(GiveFeedbackEventArgs gfbevent) 1369 { 1370 base.OnGiveFeedback(gfbevent); 1371 1372 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, gfbevent)) 1373 { 1374 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1375 { 1376 if (((IWorkflowDesignerMessageSink)filter).OnGiveFeedback(gfbevent)) 1377 break; 1378 } 1379 } 1380 } 1381 OnQueryContinueDrag(QueryContinueDragEventArgs qcdevent)1382 protected override void OnQueryContinueDrag(QueryContinueDragEventArgs qcdevent) 1383 { 1384 base.OnQueryContinueDrag(qcdevent); 1385 1386 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, qcdevent)) 1387 { 1388 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1389 { 1390 if (((IWorkflowDesignerMessageSink)filter).OnQueryContinueDrag(qcdevent)) 1391 break; 1392 } 1393 } 1394 } 1395 #endregion 1396 1397 #region General Events 1398 //Handle context menus here reason being it can come from mouse r button click 1399 //or shift+F10, or there might be other keys too 1400 //We need to handle the WndProc and not the OnNotifyMessage because we need to set 1401 //the m.Result to handled (IntPtr.Zero) and dont let the base class see the message at all 1402 //see WinOE #787 "The keyboard "key" to launch the context menu launches the menu at 0,0" 1403 [UIPermission(SecurityAction.Assert, Window = UIPermissionWindow.AllWindows)] 1404 [SuppressMessage("Microsoft.Security", "CA2106", Justification = "This is SecurityCritical, therefore not callable from partial trust code.")] WndProc(ref Message m)1405 protected override void WndProc(ref Message m) 1406 { 1407 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty)) 1408 { 1409 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1410 { 1411 if (((IWorkflowDesignerMessageSink)filter).ProcessMessage(m)) 1412 break; 1413 } 1414 1415 const int WM_CONTEXTMENU = 0x007B; 1416 if (m.Msg == WM_CONTEXTMENU) 1417 { 1418 int LParam = (int)m.LParam; 1419 Point location = (LParam != -1) ? new Point(LParam) : Control.MousePosition; 1420 1421 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1422 { 1423 if (((IWorkflowDesignerMessageSink)filter).OnShowContextMenu(location)) 1424 break; 1425 } 1426 1427 //mark the message handled 1428 m.Result = IntPtr.Zero; 1429 //dont pass the message to the base but return immediatly 1430 return; 1431 } 1432 } 1433 1434 if (this.workflowToolTip != null && m.Msg == NativeMethods.WM_NOTIFY) 1435 this.workflowToolTip.RelayParentNotify(ref m); 1436 1437 try 1438 { 1439 if (m.Result == IntPtr.Zero) 1440 base.WndProc(ref m); 1441 } 1442 catch (Exception e) 1443 { 1444 if (e != CheckoutException.Canceled) 1445 DesignerHelpers.ShowError(this, e); 1446 } 1447 } 1448 OnControlAdded(ControlEventArgs e)1449 protected override void OnControlAdded(ControlEventArgs e) 1450 { 1451 if (e.Control != VScrollBar && e.Control != HScrollBar && e.Control != this.toolContainer) 1452 throw new InvalidOperationException(SR.GetString(SR.Error_InsertingChildControls)); 1453 } 1454 CreateAccessibilityInstance()1455 protected override AccessibleObject CreateAccessibilityInstance() 1456 { 1457 return new WorkflowViewAccessibleObject(this); 1458 } 1459 #endregion 1460 1461 #endregion 1462 1463 #endregion 1464 1465 #region Private Methods OnWorkflowIdle(object sender, EventArgs e)1466 private void OnWorkflowIdle(object sender, EventArgs e) 1467 { 1468 if (this.idleEventListeners != null) 1469 this.idleEventListeners(this, e); 1470 } 1471 UpdateLayout()1472 private void UpdateLayout() 1473 { 1474 if (this.layoutEventHandler != null) 1475 { 1476 PerformLayout(true); 1477 InvalidateClientRectangle(Rectangle.Empty); 1478 } 1479 } 1480 OnCommandKey(KeyEventArgs e)1481 internal void OnCommandKey(KeyEventArgs e) 1482 { 1483 this.OnKeyDown(e); 1484 this.OnKeyUp(e); 1485 } 1486 OnSelectionChanged(object sender, EventArgs e)1487 private void OnSelectionChanged(object sender, EventArgs e) 1488 { 1489 if (this.commandSet != null) 1490 this.commandSet.UpdateCommandSet(); 1491 1492 //Make sure that the ensure visible also works when the component is selected 1493 //from property browser dropdown 1494 //Make sure that when there is a selection change using the property browser 1495 //drop down we make sure that the designer associated with component selected by the user in the dropdown 1496 //is made visible. 1497 //To enable this functionality please note that selection change is not a good event as it will get 1498 //fired in multiple cases, instead we should add a event in extended ui service which will do this and move 1499 //the following code in the event handler of that event 1500 //Ref Bug#3925 1501 1502 if (RootDesigner != null && RootDesigner.Activity != null) 1503 { 1504 ISelectionService selectionService = GetService(typeof(ISelectionService)) as ISelectionService; 1505 if (selectionService != null && selectionService.GetComponentSelected(RootDesigner.Activity)) 1506 { 1507 IHelpService helpService = GetService(typeof(IHelpService)) as IHelpService; 1508 if (helpService != null) 1509 helpService.AddContextAttribute("Keyword", RootDesigner.Activity.GetType().FullName, HelpKeywordType.F1Keyword); 1510 } 1511 } 1512 } 1513 OnPerformLayout(object sender, EventArgs e)1514 private void OnPerformLayout(object sender, EventArgs e) 1515 { 1516 if (this.layoutEventHandler != null) 1517 { 1518 Idle -= this.layoutEventHandler; 1519 this.layoutEventHandler = null; 1520 1521 base.PerformLayout(); 1522 } 1523 } 1524 1525 //Gets the snapshot of the entire workflow TakeWorkflowSnapShot()1526 private Bitmap TakeWorkflowSnapShot() 1527 { 1528 Bitmap bitmap = null; 1529 ActivityDesigner rootDesigner = RootDesigner; 1530 if (rootDesigner != null) 1531 { 1532 using (Graphics graphics = CreateGraphics()) 1533 { 1534 ViewPortData viewPortData = new ViewPortData(); 1535 viewPortData.LogicalViewPort = new Rectangle(Point.Empty, new Size(rootDesigner.Bounds.Width + 2 * DefaultWorkflowLayout.Separator.Width, rootDesigner.Bounds.Height + 2 * DefaultWorkflowLayout.Separator.Height)); 1536 viewPortData.MemoryBitmap = new Bitmap(viewPortData.LogicalViewPort.Width, viewPortData.LogicalViewPort.Height, graphics); 1537 viewPortData.Scaling = new SizeF(1, 1); 1538 viewPortData.Translation = Point.Empty; 1539 viewPortData.ShadowDepth = new Size(0, 0); 1540 viewPortData.ViewPortSize = viewPortData.LogicalViewPort.Size; 1541 TakeWorkflowSnapShot(this, viewPortData); 1542 bitmap = viewPortData.MemoryBitmap; 1543 } 1544 } 1545 1546 return bitmap; 1547 } 1548 1549 //This function will give snapshot of what is drawn on the screen at any point of time 1550 //It will scale and translate the designers and drawing based on the viewport data 1551 //We need this function in OnPaint and taking snapshot of magnifier bitmap 1552 //At the end of this function; the ViewPortData.MemoryBitmap will contain the bitmap of the 1553 //workflow to be drawn as per layout TakeWorkflowSnapShot(WorkflowView workflowView, ViewPortData viewPortData)1554 internal static void TakeWorkflowSnapShot(WorkflowView workflowView, ViewPortData viewPortData) 1555 { 1556 //Get the drawing canvas 1557 Bitmap memoryBitmap = viewPortData.MemoryBitmap; 1558 Debug.Assert(memoryBitmap != null); 1559 1560 using (Graphics viewPortGraphics = Graphics.FromImage(memoryBitmap)) 1561 { 1562 //We set the highest quality interpolation so that we do not loose the image quality 1563 viewPortGraphics.SmoothingMode = SmoothingMode.HighQuality; 1564 viewPortGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 1565 1566 using (PaintEventArgs eventArgs = new PaintEventArgs(viewPortGraphics, viewPortData.LogicalViewPort)) 1567 { 1568 workflowView.ActiveLayout.OnPaint(eventArgs, viewPortData); 1569 } 1570 1571 //Create the scaling matrix 1572 Matrix transformationMatrix = new Matrix(); 1573 transformationMatrix.Scale(viewPortData.Scaling.Width, viewPortData.Scaling.Height, MatrixOrder.Prepend); 1574 1575 //When we draw on the viewport we draw in scaled and translated. 1576 //So that we minimize the calls to DrawImage 1577 //Make sure that we scale down the logical view port origin in order to take care of scaling factor 1578 //Before we select the transform factor we make sure that logicalviewport origin is scaled down 1579 Point[] logicalViewPortOrigin = new Point[] { viewPortData.LogicalViewPort.Location }; 1580 transformationMatrix.TransformPoints(logicalViewPortOrigin); 1581 1582 //For performance improvement and to eliminate one extra DrawImage...we draw the designers on the viewport 1583 //bitmap with visual depth consideration 1584 transformationMatrix.Translate(-logicalViewPortOrigin[0].X + viewPortData.ShadowDepth.Width, -logicalViewPortOrigin[0].Y + viewPortData.ShadowDepth.Height, MatrixOrder.Append); 1585 1586 //Select the transform into viewport graphics. 1587 //Viewport bitmap has the scaled and translated designers which we then map to 1588 //the actual graphics based on page layout 1589 viewPortGraphics.Transform = transformationMatrix; 1590 1591 //Draw the designers on bitmap 1592 if (workflowView.RootDesigner != null) 1593 { 1594 using (Region clipRegion = new Region()) 1595 using (GraphicsPath designerPath = ActivityDesignerPaint.GetDesignerPath(workflowView.RootDesigner, false)) 1596 { 1597 Region oldRegion = viewPortGraphics.Clip; 1598 1599 //First draw the grid and rectangle with the designer clip region 1600 clipRegion.MakeEmpty(); 1601 clipRegion.Union(designerPath); 1602 viewPortGraphics.Clip = clipRegion; 1603 AmbientTheme ambientTheme = WorkflowTheme.CurrentTheme.AmbientTheme; 1604 viewPortGraphics.FillRectangle(ambientTheme.BackgroundBrush, workflowView.RootDesigner.Bounds); 1605 if (ambientTheme.ShowGrid) 1606 ActivityDesignerPaint.DrawGrid(viewPortGraphics, workflowView.RootDesigner.Bounds); 1607 viewPortGraphics.Clip = oldRegion; 1608 1609 //Then draw the root with clip region extended 1610 try 1611 { 1612 using (PaintEventArgs paintEventArgs = new PaintEventArgs(viewPortGraphics, viewPortData.LogicalViewPort)) 1613 { 1614 ((IWorkflowDesignerMessageSink)workflowView.RootDesigner).OnPaint(paintEventArgs, viewPortData.LogicalViewPort); 1615 } 1616 } 1617 catch (Exception e) 1618 { 1619 //Eat the exception thrown in draw 1620 Debug.WriteLine(e); 1621 } 1622 } 1623 } 1624 1625 //Draw all the filters 1626 1627 1628 using (PaintEventArgs paintArgs = new PaintEventArgs(viewPortGraphics, workflowView.RootDesigner.Bounds)) 1629 { 1630 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(workflowView, EventArgs.Empty)) 1631 { 1632 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1633 { 1634 try 1635 { 1636 if (((IWorkflowDesignerMessageSink)filter).OnPaint(paintArgs, viewPortData.LogicalViewPort)) 1637 break; 1638 } 1639 catch (Exception e) 1640 { 1641 Debug.WriteLine(e); 1642 } 1643 } 1644 } 1645 } 1646 1647 viewPortGraphics.Transform = new Matrix(); 1648 1649 //Now that we have a bitmap which is bit offseted based visual depth we need to take copy of it 1650 //This is done so as to avoid expensive DrawImage call, what I am assuming here is that time it 1651 //will take to create a new bitmap from an existing one is less expensive in terms of speed than space 1652 //As you just need to copy bitmap bits in memory than to perform expesive Image Drawing operation 1653 if (!viewPortData.ShadowDepth.IsEmpty) 1654 { 1655 Bitmap temporaryBitmap = new Bitmap(memoryBitmap); 1656 1657 //THEMETODO: WE JUST NEED TO GRAYSCALE THIS, RATHER THAN DRAWING A SHADOW 1658 //Now that we have taken a copy we will draw over the existing bitmap so that we can make it as shadow bitmap 1659 using (Brush shadowDepthBrush = new SolidBrush(Color.FromArgb(220, Color.White))) 1660 viewPortGraphics.FillRectangle(shadowDepthBrush, new Rectangle(Point.Empty, new Size(memoryBitmap.Size.Width - viewPortData.ShadowDepth.Width - 1, memoryBitmap.Size.Height - viewPortData.ShadowDepth.Height - 1))); 1661 1662 //Now make sure that we draw the image from the temporary bitmap with white color set as transparent 1663 //so that we achive the 3D effect 1664 //Make sure that we take into consideration the transparency key 1665 ImageAttributes transparentColorKey = new ImageAttributes(); 1666 transparentColorKey.SetColorKey(viewPortData.TransparentColor, viewPortData.TransparentColor, ColorAdjustType.Default); 1667 transparentColorKey.SetColorKey(viewPortData.TransparentColor, viewPortData.TransparentColor, ColorAdjustType.Bitmap); 1668 viewPortGraphics.DrawImage(temporaryBitmap, new Rectangle(-viewPortData.ShadowDepth.Width, -viewPortData.ShadowDepth.Height, memoryBitmap.Width, memoryBitmap.Height), 0, 0, memoryBitmap.Width, memoryBitmap.Height, GraphicsUnit.Pixel, transparentColorKey); 1669 1670 //Now dispose the temporary bitmap 1671 temporaryBitmap.Dispose(); 1672 } 1673 } 1674 } 1675 OnThemeChange(object sender, EventArgs e)1676 internal void OnThemeChange(object sender, EventArgs e) 1677 { 1678 ShadowDepth = WorkflowTheme.CurrentTheme.AmbientTheme.ShadowDepth; 1679 1680 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, EventArgs.Empty)) 1681 { 1682 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1683 { 1684 try 1685 { 1686 ((IWorkflowDesignerMessageSink)filter).OnThemeChange(); 1687 } 1688 catch (Exception ex) 1689 { 1690 Debug.WriteLine(ex); 1691 } 1692 } 1693 } 1694 1695 base.PerformLayout(); 1696 } 1697 OnEnsureVisible(object sender, EventArgs e)1698 private void OnEnsureVisible(object sender, EventArgs e) 1699 { 1700 if (this.ensureVisibleEventHandler != null) 1701 { 1702 Idle -= this.ensureVisibleEventHandler; 1703 this.ensureVisibleEventHandler = null; 1704 } 1705 1706 ISelectionService selectionService = (ISelectionService)GetService(typeof(ISelectionService)); 1707 if (selectionService != null && selectionService.SelectionCount > 0) 1708 { 1709 //We do not want to regenerate a layout event in ensure visible 1710 ArrayList selectedComponents = new ArrayList(selectionService.GetSelectedComponents()); 1711 for (int i = selectedComponents.Count - 1; i >= 0; i--) 1712 { 1713 Rectangle rectangleToMakeVisible = Rectangle.Empty; 1714 if (selectedComponents[i] is Activity) 1715 { 1716 ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(selectedComponents[i] as Activity); 1717 if (activityDesigner != null) 1718 { 1719 rectangleToMakeVisible = activityDesigner.Bounds; 1720 rectangleToMakeVisible.Inflate(WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize); 1721 rectangleToMakeVisible.Inflate(WorkflowTheme.CurrentTheme.AmbientTheme.SelectionSize); 1722 } 1723 } 1724 else if (selectedComponents[i] is HitTestInfo) 1725 { 1726 rectangleToMakeVisible = ((HitTestInfo)selectedComponents[i]).Bounds; 1727 } 1728 1729 if (!rectangleToMakeVisible.IsEmpty) 1730 EnsureVisible(rectangleToMakeVisible); 1731 } 1732 } 1733 } 1734 EnsureVisible(Rectangle rect)1735 private void EnsureVisible(Rectangle rect) 1736 { 1737 Rectangle clientRectangle = ClientRectangleToLogical(new Rectangle(Point.Empty, ViewPortSize)); 1738 1739 if (!clientRectangle.Contains(rect.Location) || !clientRectangle.Contains(new Point(rect.Right, rect.Bottom))) 1740 { 1741 Size scrollDelta = new Size(); 1742 if (!clientRectangle.Contains(new Point(rect.Left, clientRectangle.Top)) || !clientRectangle.Contains(new Point(rect.Right, clientRectangle.Top))) 1743 { 1744 if (rect.Width > clientRectangle.Width) 1745 scrollDelta.Width = (rect.Left + rect.Width / 2) - (clientRectangle.Left + clientRectangle.Width / 2); 1746 else if (rect.Left < clientRectangle.Left) 1747 scrollDelta.Width = (rect.Left - clientRectangle.Left); 1748 else 1749 scrollDelta.Width = (rect.Right - clientRectangle.Right); 1750 } 1751 1752 if (!clientRectangle.Contains(new Point(clientRectangle.Left, rect.Top)) || !clientRectangle.Contains(new Point(clientRectangle.Left, rect.Bottom))) 1753 { 1754 if ((rect.Top < clientRectangle.Top) || (rect.Height > clientRectangle.Height)) 1755 scrollDelta.Height = (rect.Top - clientRectangle.Top); 1756 else 1757 scrollDelta.Height = rect.Bottom - clientRectangle.Bottom; 1758 } 1759 1760 scrollDelta = LogicalSizeToClient(scrollDelta); 1761 Point scrollPosition = ScrollPosition; 1762 ScrollPosition = new Point(scrollPosition.X + scrollDelta.Width, scrollPosition.Y + scrollDelta.Height); 1763 } 1764 } 1765 OnScroll(object sender, EventArgs e)1766 private void OnScroll(object sender, EventArgs e) 1767 { 1768 //Lets speedup the scrolling logic 1769 InvalidateClientRectangle(Rectangle.Empty); 1770 1771 ScrollBar scrollBar = sender as ScrollBar; 1772 if (scrollBar != null) 1773 { 1774 using (WorkflowMessageDispatchData dispatchData = new WorkflowMessageDispatchData(this, e)) 1775 { 1776 foreach (WorkflowDesignerMessageFilter filter in dispatchData.Filters) 1777 { 1778 try 1779 { 1780 ((IWorkflowDesignerMessageSink)filter).OnScroll(scrollBar, scrollBar.Value); 1781 } 1782 catch (Exception ex) 1783 { 1784 Debug.WriteLine(ex); 1785 } 1786 } 1787 } 1788 } 1789 } 1790 UpdateScrollRange()1791 private void UpdateScrollRange() 1792 { 1793 if (ViewPortSize.Width < 0 || ViewPortSize.Height < 0) 1794 return; 1795 1796 Size currentSize = ViewPortSize; 1797 Size maximumScrollSize = LogicalSizeToClient(this.activeLayout.Extent); 1798 Size largeChangeSize = new Size(Math.Min(maximumScrollSize.Width, currentSize.Width), Math.Min(maximumScrollSize.Height, currentSize.Height)); 1799 1800 if (hScrollBar.Maximum != maximumScrollSize.Width) 1801 hScrollBar.Maximum = maximumScrollSize.Width; 1802 if (vScrollBar.Maximum != maximumScrollSize.Height) 1803 vScrollBar.Maximum = maximumScrollSize.Height; 1804 1805 if (hScrollBar.LargeChange != largeChangeSize.Width) 1806 { 1807 hScrollBar.SmallChange = largeChangeSize.Width / 15; 1808 hScrollBar.LargeChange = largeChangeSize.Width + 1; 1809 } 1810 if (vScrollBar.LargeChange != largeChangeSize.Height) 1811 { 1812 vScrollBar.SmallChange = largeChangeSize.Height / 15; 1813 vScrollBar.LargeChange = largeChangeSize.Height + 1; 1814 } 1815 1816 int xMaxScrollPos = maximumScrollSize.Width - hScrollBar.LargeChange; 1817 xMaxScrollPos = (xMaxScrollPos < 0) ? 0 : xMaxScrollPos; 1818 if (hScrollBar.Value > xMaxScrollPos) 1819 hScrollBar.Value = xMaxScrollPos; 1820 1821 int yMaxScrollPos = maximumScrollSize.Height - vScrollBar.LargeChange; 1822 yMaxScrollPos = (yMaxScrollPos < 0) ? 0 : yMaxScrollPos; 1823 if (vScrollBar.Value > yMaxScrollPos) 1824 vScrollBar.Value = yMaxScrollPos; 1825 1826 RefreshDynamicAction(); 1827 1828 bool hScrollBarVisible = hScrollBar.Visible; 1829 if (Controls.Contains(hScrollBar)) 1830 hScrollBar.Visible = (hScrollBar.Maximum > currentSize.Width); 1831 1832 bool vScrollBarVisible = vScrollBar.Visible; 1833 if (Controls.Contains(vScrollBar)) 1834 vScrollBar.Visible = (vScrollBar.Maximum > currentSize.Height); 1835 1836 if (hScrollBarVisible != hScrollBar.Visible || vScrollBar.Visible != vScrollBarVisible) 1837 { 1838 base.PerformLayout(); 1839 Refresh(); 1840 } 1841 } 1842 CreateDynamicAction()1843 private DynamicAction CreateDynamicAction() 1844 { 1845 DynamicAction fitAllAction = new DynamicAction(); 1846 fitAllAction.ButtonSize = DynamicAction.ButtonSizes.Large; 1847 fitAllAction.DockAlignment = DesignerContentAlignment.BottomRight; 1848 fitAllAction.DockMargin = new Size(5, 5); 1849 1850 ActionButton fitallButton = new ActionButton(new Image[] { DR.GetImage(DR.FitToScreen) as Bitmap }); 1851 fitallButton.StateChanged += new EventHandler(OnFitToScreen); 1852 fitAllAction.Buttons.Add(fitallButton); 1853 1854 return fitAllAction; 1855 } 1856 RefreshDynamicAction()1857 private void RefreshDynamicAction() 1858 { 1859 DynamicActionMessageFilter dynamicActionFilter = GetService(typeof(DynamicActionMessageFilter)) as DynamicActionMessageFilter; 1860 if (dynamicActionFilter == null || this.fitAllAction == null) 1861 return; 1862 1863 if (HScrollBar.Maximum > ViewPortSize.Width || VScrollBar.Maximum > ViewPortSize.Height) 1864 { 1865 //This means we need to show the zoomin icon 1866 this.fitAllAction.Buttons[0].Description = DR.GetString(DR.FitToScreenDescription); 1867 this.fitAllAction.Buttons[0].StateImages = new Bitmap[] { DR.GetImage(DR.FitToScreen) as Bitmap }; 1868 dynamicActionFilter.AddAction(this.fitAllAction); 1869 } 1870 else if (Zoom != 100) 1871 { 1872 //We need to show zoomout icon 1873 this.fitAllAction.Buttons[0].Description = DR.GetString(DR.FitToWorkflowDescription); 1874 this.fitAllAction.Buttons[0].StateImages = new Bitmap[] { DR.GetImage(DR.FitToWorkflow) as Bitmap }; 1875 dynamicActionFilter.AddAction(this.fitAllAction); 1876 } 1877 else 1878 { 1879 //In neither case we remove the action 1880 dynamicActionFilter.RemoveAction(this.fitAllAction); 1881 this.fitAllAction.Buttons[0].State = ActionButton.States.Normal; 1882 } 1883 } 1884 OnFitToScreen(object sender, EventArgs e)1885 private void OnFitToScreen(object sender, EventArgs e) 1886 { 1887 ActionButton fitallButton = sender as ActionButton; 1888 if (fitallButton == null || fitallButton.State != ActionButton.States.Pressed) 1889 return; 1890 1891 if (HScrollBar.Maximum > ViewPortSize.Width || VScrollBar.Maximum > ViewPortSize.Height) 1892 FitToScreenSize(); 1893 else if (Zoom != 100) 1894 FitToWorkflowSize(); 1895 } 1896 OnTabChange(object sender, TabSelectionChangeEventArgs e)1897 private void OnTabChange(object sender, TabSelectionChangeEventArgs e) 1898 { 1899 if (e.CurrentItem.Identifier == (int)TabButtonIds.MultiPage || 1900 e.CurrentItem.Identifier == (int)TabButtonIds.Zoom || 1901 e.CurrentItem.Identifier == (int)TabButtonIds.Pan) 1902 { 1903 Rectangle buttonRect = e.SelectedTabBounds; 1904 CommandID menuID = null; 1905 1906 if (e.CurrentItem.Identifier == (int)TabButtonIds.MultiPage) 1907 menuID = WorkflowMenuCommands.PageLayoutMenu; 1908 else if (e.CurrentItem.Identifier == (int)TabButtonIds.Zoom) 1909 menuID = WorkflowMenuCommands.ZoomMenu; 1910 else 1911 menuID = WorkflowMenuCommands.PanMenu; 1912 1913 IMenuCommandService menuCommandService = (IMenuCommandService)GetService(typeof(IMenuCommandService)); 1914 if (menuCommandService != null) 1915 menuCommandService.ShowContextMenu(menuID, buttonRect.Right, buttonRect.Top); 1916 } 1917 } 1918 EnsureScrollBars(HScrollBar newHorizScrollBar, VScrollBar newVertScrollBar)1919 private void EnsureScrollBars(HScrollBar newHorizScrollBar, VScrollBar newVertScrollBar) 1920 { 1921 try 1922 { 1923 SuspendLayout(); 1924 1925 if (this.hScrollBar != newHorizScrollBar) 1926 { 1927 if (this.hScrollBar != null) 1928 { 1929 this.hScrollBar.ValueChanged -= new EventHandler(OnScroll); 1930 if (Controls.Contains(this.hScrollBar)) 1931 Controls.Remove(this.hScrollBar); 1932 } 1933 1934 this.hScrollBar = newHorizScrollBar; 1935 if (this.hScrollBar.Parent == null) 1936 { 1937 this.hScrollBar.TabStop = false; 1938 Controls.Add(this.hScrollBar); 1939 } 1940 } 1941 1942 if (this.vScrollBar != newVertScrollBar) 1943 { 1944 if (this.vScrollBar != null) 1945 { 1946 this.vScrollBar.ValueChanged -= new EventHandler(OnScroll); 1947 if (Controls.Contains(this.vScrollBar)) 1948 Controls.Remove(this.vScrollBar); 1949 } 1950 1951 this.vScrollBar = newVertScrollBar; 1952 if (this.vScrollBar.Parent == null) 1953 { 1954 this.vScrollBar.TabStop = false; 1955 Controls.Add(this.vScrollBar); 1956 } 1957 } 1958 1959 this.hScrollBar.ValueChanged += new EventHandler(OnScroll); 1960 this.vScrollBar.ValueChanged += new EventHandler(OnScroll); 1961 } 1962 finally 1963 { 1964 ResumeLayout(true); 1965 } 1966 } 1967 PopulateMessageFilters(bool stockFilters)1968 private void PopulateMessageFilters(bool stockFilters) 1969 { 1970 IList<WorkflowDesignerMessageFilter> filters = (stockFilters) ? this.stockMessageFilters : this.customMessageFilters; 1971 Debug.Assert(filters.Count == 0); 1972 1973 if (stockFilters) 1974 { 1975 filters.Add(new GlyphManager()); 1976 filters.Add(new WindowManager()); 1977 } 1978 else 1979 { 1980 Debug.Assert(this.rootDesigner != null); 1981 1982 if (Capture) 1983 Capture = false; 1984 1985 IList customFilters = ((IWorkflowRootDesigner)this.rootDesigner).MessageFilters; 1986 foreach (WorkflowDesignerMessageFilter filter in customFilters) 1987 filters.Add(filter); 1988 } 1989 1990 foreach (WorkflowDesignerMessageFilter filter in filters) 1991 filter.SetParentView(this); 1992 } 1993 DisposeMessageFilters(bool stockFilters)1994 private void DisposeMessageFilters(bool stockFilters) 1995 { 1996 List<WorkflowDesignerMessageFilter> filters = (stockFilters) ? this.stockMessageFilters : this.customMessageFilters; 1997 1998 //We dispose all the message filters, this is done by copying because some of the 1999 //message filters might remove other dependent messagefilters 2000 ArrayList clonedFilterList = new ArrayList(filters.ToArray()); 2001 foreach (WorkflowDesignerMessageFilter filter in clonedFilterList) 2002 ((IDisposable)filter).Dispose(); 2003 filters.Clear(); 2004 } 2005 #endregion 2006 2007 #region Coordinate Transformation Functions InvalidateClientRectangle(Rectangle clientRectangle)2008 public void InvalidateClientRectangle(Rectangle clientRectangle) 2009 { 2010 if (this.layoutEventHandler == null) 2011 { 2012 if (!clientRectangle.IsEmpty) 2013 { 2014 //Inflate the invalidated rectangle. When zoom factor is less than 1; there is a loss of precision 2015 clientRectangle.Inflate(1, 1); 2016 base.Invalidate(clientRectangle); 2017 } 2018 else 2019 { 2020 base.Invalidate(); 2021 } 2022 } 2023 } 2024 InvalidateLogicalRectangle(Rectangle logicalRectangle)2025 public void InvalidateLogicalRectangle(Rectangle logicalRectangle) 2026 { 2027 InvalidateClientRectangle(LogicalRectangleToClient(logicalRectangle)); 2028 } 2029 LogicalPointToScreen(Point logicalPoint)2030 public Point LogicalPointToScreen(Point logicalPoint) 2031 { 2032 return PointToScreen(LogicalPointToClient(logicalPoint)); 2033 } 2034 ScreenPointToLogical(Point screenPoint)2035 public Point ScreenPointToLogical(Point screenPoint) 2036 { 2037 return ClientPointToLogical(PointToClient(screenPoint)); 2038 } 2039 LogicalPointToClient(Point logicalPoint)2040 public Point LogicalPointToClient(Point logicalPoint) 2041 { 2042 return LogicalPointToClient(logicalPoint, true); 2043 } 2044 ClientPointToLogical(Point clientPoint)2045 public Point ClientPointToLogical(Point clientPoint) 2046 { 2047 return ClientPointToLogical(clientPoint, true); 2048 } 2049 LogicalSizeToClient(Size logicalSize)2050 public Size LogicalSizeToClient(Size logicalSize) 2051 { 2052 Point[] points = new Point[] { new Point(logicalSize) }; 2053 2054 //Scale the point 2055 Matrix scalingMatrix = new Matrix(); 2056 scalingMatrix.Scale(ScaleZoomFactor, ScaleZoomFactor); 2057 scalingMatrix.TransformPoints(points); 2058 return new Size(points[0]); 2059 } 2060 ClientSizeToLogical(Size clientSize)2061 public Size ClientSizeToLogical(Size clientSize) 2062 { 2063 //Scale the size, size scaling does not require translate 2064 Point[] points = new Point[] { new Point(clientSize) }; 2065 Matrix scalingMatrix = new Matrix(); 2066 scalingMatrix.Scale(ScaleZoomFactor, ScaleZoomFactor); 2067 scalingMatrix.Invert(); 2068 scalingMatrix.TransformPoints(points); 2069 scalingMatrix.Invert(); 2070 return new Size(points[0]); 2071 } 2072 LogicalRectangleToClient(Rectangle rectangle)2073 public Rectangle LogicalRectangleToClient(Rectangle rectangle) 2074 { 2075 Debug.Assert(this.activeLayout != null, "active layout should not be null"); 2076 Rectangle clientViewPort = (this.activeLayout != null) ? this.activeLayout.MapOutRectangleFromLayout(rectangle) : rectangle; 2077 // 2078 2079 2080 return new Rectangle(LogicalPointToClient(clientViewPort.Location, false), LogicalSizeToClient(clientViewPort.Size)); 2081 } 2082 ClientRectangleToLogical(Rectangle rectangle)2083 public Rectangle ClientRectangleToLogical(Rectangle rectangle) 2084 { 2085 //We translate the client viewport to logical view port. 2086 //To do this we first get the view port rectangle scale it down 2087 //then translate it to area of page we would be viewing 2088 Rectangle scaledLogicalViewPort = new Rectangle(ClientPointToLogical(rectangle.Location, false), ClientSizeToLogical(rectangle.Size)); 2089 return this.activeLayout.MapInRectangleToLayout(scaledLogicalViewPort); 2090 } 2091 IsClientPointInActiveLayout(Point clientPoint)2092 internal bool IsClientPointInActiveLayout(Point clientPoint) 2093 { 2094 Point logicalPoint = ClientPointToLogical(clientPoint, false); 2095 return this.activeLayout.IsCoOrdInLayout(logicalPoint); 2096 } 2097 2098 /* 2099 * Client scale is when we transform the coordinate based on zoom and translate it based on scrolling position and layout 2100 * Logical scale is when we transform the coordinate and map it to a flat coordinate system which goes from 0,0 to m,n 2101 * We also consider the ActiveLayout to transform the coordinates. 2102 */ LogicalPointToClient(Point point, bool mapToLayout)2103 private Point LogicalPointToClient(Point point, bool mapToLayout) 2104 { 2105 if (mapToLayout) 2106 point = this.activeLayout.MapOutCoOrdFromLayout(point); 2107 2108 //Scale the point 2109 Matrix scalingMatrix = new Matrix(); 2110 scalingMatrix.Scale(ScaleZoomFactor, ScaleZoomFactor); 2111 Point[] points = new Point[] { point }; 2112 scalingMatrix.TransformPoints(points); 2113 2114 //Translate the point 2115 Matrix translateMatrix = new Matrix(); 2116 translateMatrix.Translate(-ScrollPosition.X, -ScrollPosition.Y); 2117 translateMatrix.TransformPoints(points); 2118 return points[0]; 2119 } 2120 ClientPointToLogical(Point point, bool mapToLayout)2121 private Point ClientPointToLogical(Point point, bool mapToLayout) 2122 { 2123 Point[] points = new Point[] { point }; 2124 2125 //Translate the point 2126 Matrix translateMatrix = new Matrix(); 2127 translateMatrix.Translate(ScrollPosition.X, ScrollPosition.Y); 2128 translateMatrix.TransformPoints(points); 2129 2130 //Scale down the point 2131 Matrix scalingMatrix = new Matrix(); 2132 scalingMatrix.Scale(ScaleZoomFactor, ScaleZoomFactor); 2133 scalingMatrix.Invert(); 2134 scalingMatrix.TransformPoints(points); 2135 scalingMatrix.Invert(); 2136 if (!mapToLayout) 2137 return points[0]; 2138 else 2139 return this.activeLayout.MapInCoOrdToLayout(points[0]); 2140 } 2141 #endregion 2142 2143 #region IServiceProvider Implemetation IServiceProvider.GetService(Type serviceType)2144 object IServiceProvider.GetService(Type serviceType) 2145 { 2146 return GetService(serviceType); 2147 } 2148 GetService(Type serviceType)2149 protected override object GetService(Type serviceType) 2150 { 2151 object retVal = null; 2152 2153 if (serviceType == typeof(CommandID)) 2154 retVal = new CommandID(new Guid("5f1c3c8d-60f1-4b98-b85b-8679f97e8eac"), 0); 2155 else 2156 retVal = this.serviceProvider.GetService(serviceType); 2157 2158 return retVal; 2159 } 2160 #endregion 2161 2162 #region Class WorkflowMessageDispatchData 2163 private sealed class WorkflowMessageDispatchData : IDisposable 2164 { 2165 private WorkflowView workflowView; 2166 private HitTestInfo messageContext = null; 2167 WorkflowMessageDispatchData(WorkflowView workflowView, EventArgs e)2168 public WorkflowMessageDispatchData(WorkflowView workflowView, EventArgs e) 2169 { 2170 this.workflowView = workflowView; 2171 2172 if (this.workflowView.RootDesigner != null && this.workflowView.stockMessageFilters.Count > 0) 2173 { 2174 Point clientPoint = Point.Empty; 2175 if (e is MouseEventArgs || e is DragEventArgs) 2176 { 2177 if (e is MouseEventArgs) 2178 { 2179 clientPoint = new Point(((MouseEventArgs)e).X, ((MouseEventArgs)e).Y); 2180 } 2181 else if (e is DragEventArgs) 2182 { 2183 clientPoint = this.workflowView.PointToClient(new Point(((DragEventArgs)e).X, ((DragEventArgs)e).Y)); 2184 this.workflowView.UpdateLayout(); 2185 } 2186 2187 Point logicalPoint = this.workflowView.ClientPointToLogical(clientPoint); 2188 HitTestInfo hitTestInfo = this.workflowView.RootDesigner.HitTest(logicalPoint); 2189 this.messageContext = (hitTestInfo != null) ? hitTestInfo : HitTestInfo.Nowhere; 2190 this.workflowView.messageHitTestContexts.Push(this.messageContext); 2191 } 2192 } 2193 } 2194 IDisposable.Dispose()2195 void IDisposable.Dispose() 2196 { 2197 if (this.workflowView != null && this.messageContext != null) 2198 { 2199 HitTestInfo hittestInfo = this.workflowView.messageHitTestContexts.Pop(); 2200 if (hittestInfo != this.messageContext) 2201 Debug.Assert(false, "WorkflowView poped wrong message context"); 2202 } 2203 } 2204 2205 public ReadOnlyCollection<WorkflowDesignerMessageFilter> Filters 2206 { 2207 get 2208 { 2209 //We recreate a new list everytime as in some of the messages dispatched, we there can 2210 //be additional filters which might be added 2211 List<WorkflowDesignerMessageFilter> mergedFilterList = new List<WorkflowDesignerMessageFilter>(); 2212 mergedFilterList.AddRange(this.workflowView.customMessageFilters); 2213 mergedFilterList.AddRange(this.workflowView.stockMessageFilters); 2214 return mergedFilterList.AsReadOnly(); 2215 } 2216 } 2217 } 2218 #endregion 2219 2220 #region IMessageFilter Implementation IMessageFilter.PreFilterMessage(ref Message m)2221 bool IMessageFilter.PreFilterMessage(ref Message m) 2222 { 2223 bool handled = false; 2224 if (m.Msg == NativeMethods.WM_KEYDOWN || m.Msg == NativeMethods.WM_SYSKEYDOWN || 2225 m.Msg == NativeMethods.WM_KEYUP || m.Msg == NativeMethods.WM_SYSKEYUP) 2226 { 2227 Control control = Control.FromHandle(m.HWnd); 2228 if (control != null && (control == this || Controls.Contains(control))) 2229 { 2230 KeyEventArgs eventArgs = new KeyEventArgs((Keys)(unchecked((int)(long)m.WParam)) | ModifierKeys); 2231 if (m.Msg == NativeMethods.WM_KEYDOWN || m.Msg == NativeMethods.WM_SYSKEYDOWN) 2232 OnKeyDown(eventArgs); 2233 else 2234 OnKeyUp(eventArgs); 2235 2236 handled = eventArgs.Handled; 2237 } 2238 } 2239 2240 return handled; 2241 } 2242 #endregion 2243 } 2244 2245 #region Class WorkflowViewAccessibleObject 2246 [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] 2247 public class WorkflowViewAccessibleObject : Control.ControlAccessibleObject 2248 { 2249 private WorkflowView workflowView; 2250 WorkflowViewAccessibleObject(WorkflowView workflowView)2251 public WorkflowViewAccessibleObject(WorkflowView workflowView) 2252 : base(workflowView) 2253 { 2254 if (workflowView == null) 2255 throw new ArgumentNullException("workflowView"); 2256 this.workflowView = workflowView; 2257 } 2258 2259 public override Rectangle Bounds 2260 { 2261 get 2262 { 2263 return new Rectangle(this.workflowView.PointToScreen(Point.Empty), this.workflowView.ViewPortSize); 2264 } 2265 } 2266 2267 public override string DefaultAction 2268 { 2269 get 2270 { 2271 return DR.GetString(DR.AccessibleAction); 2272 } 2273 } 2274 2275 public override string Description 2276 { 2277 get 2278 { 2279 return DR.GetString(DR.WorkflowViewAccessibleDescription); 2280 } 2281 } 2282 2283 public override string Help 2284 { 2285 get 2286 { 2287 return DR.GetString(DR.WorkflowViewAccessibleHelp); 2288 } 2289 } 2290 2291 public override string Name 2292 { 2293 get 2294 { 2295 return DR.GetString(DR.WorkflowViewAccessibleName); 2296 } 2297 2298 set 2299 { 2300 } 2301 } 2302 2303 public override AccessibleRole Role 2304 { 2305 get 2306 { 2307 return AccessibleRole.Diagram; 2308 } 2309 } 2310 GetChild(int index)2311 public override AccessibleObject GetChild(int index) 2312 { 2313 return (this.workflowView.RootDesigner != null && index == 0) ? this.workflowView.RootDesigner.AccessibilityObject : base.GetChild(index); 2314 } 2315 GetChildCount()2316 public override int GetChildCount() 2317 { 2318 return (this.workflowView.RootDesigner != null) ? 1 : -1; 2319 } 2320 Navigate(AccessibleNavigation navdir)2321 public override AccessibleObject Navigate(AccessibleNavigation navdir) 2322 { 2323 if (navdir == AccessibleNavigation.FirstChild || navdir == AccessibleNavigation.LastChild) 2324 return GetChild(0); 2325 else 2326 return base.Navigate(navdir); 2327 } 2328 } 2329 #endregion 2330 2331 #region WorkflowTimer 2332 internal sealed class WorkflowTimer : IDisposable 2333 { 2334 private static WorkflowTimer workflowTimer; 2335 2336 private const int TimerInterval = 50; 2337 private Timer timer = null; 2338 private List<ElapsedEventUnit> elapsedEvents = new List<ElapsedEventUnit>(); 2339 2340 internal static WorkflowTimer Default 2341 { 2342 get 2343 { 2344 if (WorkflowTimer.workflowTimer == null) 2345 WorkflowTimer.workflowTimer = new WorkflowTimer(); 2346 return WorkflowTimer.workflowTimer; 2347 } 2348 } 2349 WorkflowTimer()2350 private WorkflowTimer() 2351 { 2352 this.timer = new Timer(); 2353 this.timer.Interval = WorkflowTimer.TimerInterval; 2354 this.timer.Tick += new EventHandler(OnTimer); 2355 this.timer.Stop(); 2356 } 2357 ~WorkflowTimer()2358 ~WorkflowTimer() 2359 { 2360 Dispose(false); 2361 } 2362 Dispose()2363 public void Dispose() 2364 { 2365 Dispose(true); 2366 GC.SuppressFinalize(this); 2367 } 2368 Dispose(bool disposing)2369 private void Dispose(bool disposing) 2370 { 2371 if (this.timer != null) 2372 { 2373 if (this.timer.Enabled) 2374 this.timer.Stop(); 2375 2376 this.timer.Dispose(); 2377 this.timer = null; 2378 } 2379 } 2380 Subscribe(int elapsedInterval, EventHandler elapsedEventHandler)2381 internal void Subscribe(int elapsedInterval, EventHandler elapsedEventHandler) 2382 { 2383 this.elapsedEvents.Add(new ElapsedEventUnit(elapsedInterval / WorkflowTimer.TimerInterval, elapsedEventHandler)); 2384 if (!this.timer.Enabled) 2385 this.timer.Start(); 2386 } 2387 Unsubscribe(EventHandler elapsedEventHandler)2388 internal void Unsubscribe(EventHandler elapsedEventHandler) 2389 { 2390 List<ElapsedEventUnit> removableElapsedEvents = new List<ElapsedEventUnit>(); 2391 foreach (ElapsedEventUnit elapsedEvent in this.elapsedEvents) 2392 { 2393 if (elapsedEvent.elapsedEventHandler == elapsedEventHandler) 2394 removableElapsedEvents.Add(elapsedEvent); 2395 } 2396 2397 foreach (ElapsedEventUnit elapsedEvent in removableElapsedEvents) 2398 this.elapsedEvents.Remove(elapsedEvent); 2399 2400 if (this.elapsedEvents.Count == 0 && this.timer.Enabled) 2401 this.timer.Stop(); 2402 } 2403 OnTimer(object sender, EventArgs e)2404 private void OnTimer(object sender, EventArgs e) 2405 { 2406 List<ElapsedEventUnit> clonedList = new List<ElapsedEventUnit>(this.elapsedEvents); 2407 foreach (ElapsedEventUnit elapsedEvent in clonedList) 2408 { 2409 elapsedEvent.elapsedTime += 1; 2410 if (elapsedEvent.elapsedInterval <= elapsedEvent.elapsedTime) 2411 { 2412 elapsedEvent.elapsedTime = 0; 2413 elapsedEvent.elapsedEventHandler(this, EventArgs.Empty); 2414 } 2415 } 2416 } 2417 2418 private sealed class ElapsedEventUnit 2419 { 2420 internal EventHandler elapsedEventHandler; 2421 internal int elapsedInterval; 2422 internal int elapsedTime; 2423 ElapsedEventUnit(int interval, EventHandler eventHandler)2424 internal ElapsedEventUnit(int interval, EventHandler eventHandler) 2425 { 2426 this.elapsedInterval = interval; 2427 this.elapsedEventHandler = eventHandler; 2428 } 2429 } 2430 } 2431 #endregion 2432 } 2433