1 //----------------------------------------------------------------
2 // <copyright company="Microsoft Corporation">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //----------------------------------------------------------------
7 namespace System.Activities.Presentation.Annotations
9 using System.Activities.Presentation.Hosting;
10 using System.Activities.Presentation.Model;
11 using System.Activities.Presentation.View;
12 using System.ComponentModel;
15 using System.Windows.Threading;
17 internal class AnnotationManager
19 private bool isInitialized;
21 private WorkflowViewElement workflowViewElement;
22 private IAnnotationVisualProvider annotationVisualProvider;
24 private ModelItem modelItem;
25 private EditingContext editingContext;
26 private IAnnotationIndicator indicator;
27 private IDockedAnnotation dockedAnnotation;
28 private IFloatingAnnotation floatingAnnotation;
30 private bool isViewStateChangedInternally;
31 private AnnotationStatus status;
32 private AnnotationAdorner annotationAdorner;
33 private DispatcherTimer tryHideTimer;
34 private bool hasAnnotation;
36 private IIntegratedHelpService helpService;
38 internal AnnotationManager(WorkflowViewElement workflowViewElement)
40 this.workflowViewElement = workflowViewElement;
43 public IAnnotationVisualProvider AnnotationVisualProvider
47 return this.annotationVisualProvider;
52 if (this.annotationVisualProvider != value)
54 if (this.isInitialized)
56 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CouldNotChangeValueAfterInitialization));
59 this.annotationVisualProvider = value;
64 protected internal virtual AnnotationAdornerService AnnotationAdornerService
68 return this.EditingContext.Services.GetService<AnnotationAdornerService>();
72 private ModelItem ModelItem
76 return this.modelItem;
81 if (this.modelItem != value)
83 Fx.Assert(!this.isInitialized, "could not change value after initialization");
85 this.modelItem = value;
90 private EditingContext EditingContext
94 return this.editingContext;
99 if (this.editingContext != value)
101 Fx.Assert(!this.isInitialized, "could not change value after initialization");
103 this.editingContext = value;
108 private IAnnotationIndicator Indicator
112 if (this.indicator == null)
114 this.indicator = this.AnnotationVisualProvider.GetAnnotationIndicator();
117 return this.indicator;
121 private IFloatingAnnotation FloatingAnnotation
125 if (this.floatingAnnotation == null)
127 this.floatingAnnotation = this.AnnotationVisualProvider.GetFloatingAnnotation();
129 this.floatingAnnotation.IsReadOnly = this.EditingContext.Items.GetValue<ReadOnlyState>().IsReadOnly;
130 this.floatingAnnotation.IsMouseOverChanged += new EventHandler(this.OnFloatingAnnotationIsMouseOverChanged);
131 this.floatingAnnotation.IsKeyboardFocusWithinChanged += new DependencyPropertyChangedEventHandler(this.OnFloatingAnnotationIsKeyboardFocusWithinChanged);
132 this.floatingAnnotation.DockButtonClicked += new Action(this.OnDockButtonClicked);
133 this.floatingAnnotation.ModelItem = this.ModelItem;
136 return this.floatingAnnotation;
140 private IDockedAnnotation DockedAnnotation
144 if (this.dockedAnnotation == null)
146 this.dockedAnnotation = this.AnnotationVisualProvider.GetDockedAnnotation();
148 this.dockedAnnotation.IsReadOnly = this.EditingContext.Items.GetValue<ReadOnlyState>().IsReadOnly;
149 this.dockedAnnotation.UndockButtonClicked += new Action(this.OnUndockButtonClicked);
152 return this.dockedAnnotation;
156 private ViewStateService ViewStateService
160 return this.EditingContext.Services.GetService<ViewStateService>();
164 private AnnotationAdorner AnnotationAdorner
168 if (this.annotationAdorner == null)
170 this.annotationAdorner = new AnnotationAdorner(this.workflowViewElement);
171 this.annotationAdorner.Content = this.FloatingAnnotation as UIElement;
174 return this.annotationAdorner;
178 private bool IsAnnotationDocked
182 bool? value = this.ViewStateService.RetrieveViewState(this.ModelItem, Annotation.IsAnnotationDockedViewStateName) as bool?;
195 this.isViewStateChangedInternally = true;
196 this.ViewStateService.StoreViewState(this.ModelItem, Annotation.IsAnnotationDockedViewStateName, value);
197 this.isViewStateChangedInternally = false;
201 private DispatcherTimer TryHideTimer
205 if (this.tryHideTimer == null)
207 this.tryHideTimer = new DispatcherTimer();
208 this.tryHideTimer.Interval = TimeSpan.FromMilliseconds(200);
209 this.tryHideTimer.Tick += this.TryHideAnnotation;
212 return this.tryHideTimer;
216 public void Initialize()
218 if (this.isInitialized)
223 this.ModelItem = this.workflowViewElement.ModelItem;
224 this.EditingContext = this.workflowViewElement.Context;
226 if (!this.CanInitialize())
231 this.EditingContext.Items.Subscribe<ReadOnlyState>(this.OnReadOnlyStateChanged);
232 this.ViewStateService.ViewStateChanged += new ViewStateChangedEventHandler(this.OnViewStateChanged);
233 this.ModelItem.PropertyChanged += new PropertyChangedEventHandler(this.OnModelItemPropertyChanged);
234 this.Indicator.IsMouseOverChanged += new EventHandler(this.OnIndicatorIsMouseOverChanged);
235 this.helpService = this.EditingContext.Services.GetService<IIntegratedHelpService>();
237 this.hasAnnotation = this.ModelItem.Properties[Annotation.AnnotationTextPropertyName].ComputedValue != null;
239 if (this.ModelItem.Properties[Annotation.AnnotationTextPropertyName].ComputedValue == null)
241 this.Indicator.Visibility = Visibility.Collapsed;
242 if (this.dockedAnnotation != null)
244 this.DockedAnnotation.Visibility = Visibility.Collapsed;
249 if (this.IsAnnotationDocked)
251 this.Indicator.Visibility = Visibility.Collapsed;
252 this.DockedAnnotation.Visibility = Visibility.Visible;
253 this.status = AnnotationStatus.Docked;
257 this.Indicator.Visibility = Visibility.Visible;
258 this.DockedAnnotation.Visibility = Visibility.Collapsed;
262 this.isInitialized = true;
265 public void Uninitialize()
267 if (!this.isInitialized)
272 this.EditingContext.Items.Unsubscribe<ReadOnlyState>(this.OnReadOnlyStateChanged);
273 this.ViewStateService.ViewStateChanged -= new ViewStateChangedEventHandler(this.OnViewStateChanged);
274 this.ModelItem.PropertyChanged -= new PropertyChangedEventHandler(this.OnModelItemPropertyChanged);
275 this.Indicator.IsMouseOverChanged -= new EventHandler(this.OnIndicatorIsMouseOverChanged);
277 if (this.dockedAnnotation != null)
279 this.dockedAnnotation.UndockButtonClicked -= new Action(this.OnUndockButtonClicked);
282 if (this.floatingAnnotation != null)
284 this.floatingAnnotation.IsMouseOverChanged -= new EventHandler(this.OnFloatingAnnotationIsMouseOverChanged);
285 this.floatingAnnotation.IsKeyboardFocusWithinChanged -= new DependencyPropertyChangedEventHandler(this.OnFloatingAnnotationIsKeyboardFocusWithinChanged);
286 this.floatingAnnotation.DockButtonClicked -= new Action(this.OnDockButtonClicked);
289 if (this.tryHideTimer != null)
291 this.tryHideTimer.Tick -= this.TryHideAnnotation;
292 if (this.tryHideTimer.IsEnabled)
294 this.tryHideTimer.Stop();
298 this.tryHideTimer = null;
300 this.isInitialized = false;
303 public void OnEditAnnotation()
305 if (!this.isInitialized)
310 if (this.status == AnnotationStatus.Docked)
312 this.DockedAnnotation.FocusOnContent();
316 if (this.status == AnnotationStatus.Hidden)
318 this.ShowAnnotation();
321 this.FloatingAnnotation.FocusOnContent();
324 private void OnReadOnlyStateChanged(ReadOnlyState state)
326 if (this.floatingAnnotation != null)
328 this.floatingAnnotation.IsReadOnly = state.IsReadOnly;
331 if (this.dockedAnnotation != null)
333 this.dockedAnnotation.IsReadOnly = state.IsReadOnly;
337 private void OnViewStateChanged(object sender, ViewStateChangedEventArgs e)
339 if (e.ParentModelItem == this.ModelItem && e.Key == Annotation.IsAnnotationDockedViewStateName && !this.isViewStateChangedInternally)
341 bool? isAnnotationDocked = e.NewValue as bool?;
342 if (isAnnotationDocked.HasValue)
344 if (this.hasAnnotation)
346 if (isAnnotationDocked.Value)
348 this.DockAnnotation();
352 this.HideAnnotation();
359 private void OnModelItemPropertyChanged(object sender, PropertyChangedEventArgs e)
361 if (e.PropertyName == Annotation.AnnotationTextPropertyName)
363 bool previouslyHadAnnotation = this.hasAnnotation;
364 this.hasAnnotation = this.ModelItem.Properties[Annotation.AnnotationTextPropertyName].ComputedValue != null;
366 if (!this.hasAnnotation)
368 //// annotation is removed
370 if (this.status == AnnotationStatus.Floating)
372 this.AnnotationAdornerService.Hide(this.AnnotationAdorner);
375 this.Indicator.Visibility = Visibility.Collapsed;
376 if (this.dockedAnnotation != null)
378 this.dockedAnnotation.Visibility = Visibility.Collapsed;
381 this.status = AnnotationStatus.Hidden;
383 else if (!previouslyHadAnnotation)
385 //// annotation is added
387 if (this.IsAnnotationDocked)
389 this.Indicator.Visibility = Visibility.Collapsed;
390 this.DockedAnnotation.Visibility = Visibility.Visible;
391 this.status = AnnotationStatus.Docked;
395 this.Indicator.Visibility = Visibility.Visible;
401 private void OnUndockButtonClicked()
403 this.ShowAnnotation();
404 this.OnEditAnnotation();
407 private void OnFloatingAnnotationIsMouseOverChanged(object sender, EventArgs e)
409 if (!this.FloatingAnnotation.IsMouseOver)
411 if (this.status == AnnotationStatus.Floating)
413 this.DelayedTryHide();
418 private void OnFloatingAnnotationIsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
420 if (!this.FloatingAnnotation.IsKeyboardFocusWithin)
422 this.TryHideAnnotation(null, null);
423 if (this.helpService != null)
425 this.helpService.RemoveContextAttribute(string.Empty, typeof(Annotation).FullName);
426 this.helpService.AddContextAttribute(string.Empty, WorkflowViewManager.GetF1HelpTypeKeyword(this.ModelItem.ItemType), ComponentModel.Design.HelpKeywordType.F1Keyword);
431 Selection.SelectOnly(this.EditingContext, this.ModelItem);
432 if (this.helpService != null)
434 this.helpService.RemoveContextAttribute(string.Empty, WorkflowViewManager.GetF1HelpTypeKeyword(this.ModelItem.ItemType));
435 this.helpService.AddContextAttribute(string.Empty, typeof(Annotation).FullName, ComponentModel.Design.HelpKeywordType.F1Keyword);
440 private void OnIndicatorIsMouseOverChanged(object sender, EventArgs e)
442 if (this.Indicator.IsMouseOver)
444 if (this.status == AnnotationStatus.Hidden)
446 this.ShowAnnotation();
451 if (this.status == AnnotationStatus.Floating)
453 this.DelayedTryHide();
458 private void OnDockButtonClicked()
460 this.DockAnnotation();
463 private bool CanInitialize()
465 return this.ModelItem != null &&
466 this.EditingContext != null &&
467 this.AnnotationVisualProvider != null &&
468 this.EditingContext.Services.GetService<DesignerConfigurationService>().AnnotationEnabled;
471 private void TryHideAnnotation(object sender, EventArgs e)
473 DispatcherTimer timer = sender as DispatcherTimer;
479 if (this.status == AnnotationStatus.Floating)
481 if (!this.FloatingAnnotation.IsMouseOver &&
482 !this.Indicator.IsMouseOver &&
483 !this.FloatingAnnotation.IsKeyboardFocusWithin)
485 this.HideAnnotation();
490 private void DelayedTryHide()
492 if (this.TryHideTimer.IsEnabled)
494 this.TryHideTimer.Stop();
497 this.TryHideTimer.Start();
500 private void ShowAnnotation()
502 System.Diagnostics.Debug.WriteLine("ShowAnnotation called.");
506 case AnnotationStatus.Floating:
508 case AnnotationStatus.Hidden:
509 this.AnnotationAdornerService.Show(this.AnnotationAdorner);
511 case AnnotationStatus.Docked:
512 if (this.Indicator != null)
514 this.Indicator.Visibility = Visibility.Visible;
517 this.DockedAnnotation.Visibility = Visibility.Collapsed;
519 this.AnnotationAdornerService.Show(this.AnnotationAdorner);
523 this.status = AnnotationStatus.Floating;
524 this.IsAnnotationDocked = false;
527 private void HideAnnotation()
529 System.Diagnostics.Debug.WriteLine("HideAnnotation called.");
531 if (this.status == AnnotationStatus.Hidden)
536 if (this.status == AnnotationStatus.Floating)
538 this.FloatingAnnotation.UpdateModelItem();
539 this.AnnotationAdornerService.Hide(this.AnnotationAdorner);
542 if (this.status == AnnotationStatus.Docked)
544 this.Indicator.Visibility = Visibility.Visible;
546 this.DockedAnnotation.Visibility = Visibility.Collapsed;
549 this.status = AnnotationStatus.Hidden;
550 this.IsAnnotationDocked = false;
553 private void DockAnnotation()
555 System.Diagnostics.Debug.WriteLine("DockAnnotation called.");
557 if (this.status == AnnotationStatus.Docked)
562 if (this.status == AnnotationStatus.Floating)
564 this.AnnotationAdornerService.Hide(this.AnnotationAdorner);
567 this.Indicator.Visibility = Visibility.Collapsed;
568 this.DockedAnnotation.Visibility = Visibility.Visible;
570 this.status = AnnotationStatus.Docked;
571 this.IsAnnotationDocked = true;