//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.Activities.Presentation.View
{
using System.Activities.Presentation.View;
using System.Activities.Presentation.Model;
using System.Activities.Presentation.Services;
using System.Activities.Presentation.Xaml;
using System.Activities.Presentation.Hosting;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Packaging;
using System.Printing;
using System.Reflection;
using System.Runtime;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Windows.Xps;
using System.Windows.Xps.Packaging;
using System.Linq;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Activities.Presentation.Validation;
using System.Activities.Presentation.Internal.PropertyEditing;
using System.ServiceModel.Activities;
using Microsoft.Tools.Common;
using System.Activities.Presentation.Sqm;
//
// Interaction logic for DesignerView.xaml
//
[Fx.Tag.XamlVisible(false)]
public partial class DesignerView : UserControl
{
public static readonly DependencyProperty RootDesignerProperty =
DependencyProperty.Register("RootDesigner", typeof(UIElement), typeof(DesignerView), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(DesignerView.OnRootDesignerChanged)));
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(DesignerView), new UIPropertyMetadata(OnIsReadOnlyChanged));
static readonly DependencyPropertyKey ActivitySchemaPropertyKey =
DependencyProperty.RegisterReadOnly("ActivitySchema", typeof(ModelItem), typeof(DesignerView), new UIPropertyMetadata(OnActivitySchemaChanged));
public static readonly DependencyProperty ActivitySchemaProperty = ActivitySchemaPropertyKey.DependencyProperty;
static readonly DependencyPropertyKey FocusedViewElementPropertyKey =
DependencyProperty.RegisterReadOnly("FocusedViewElement", typeof(WorkflowViewElement), typeof(DesignerView), new UIPropertyMetadata(null));
public static readonly DependencyProperty InPanModeProperty =
DependencyProperty.Register("InPanMode", typeof(bool), typeof(DesignerView), new UIPropertyMetadata(OnInPanModeChanged));
public static readonly DependencyProperty FocusedViewElementProperty = FocusedViewElementPropertyKey.DependencyProperty;
internal static DependencyProperty ShouldExpandAllProperty = DependencyProperty.Register("ShouldExpandAll", typeof(bool), typeof(DesignerView), new PropertyMetadata(false, new PropertyChangedCallback(OnExpandAllCollapseAllChanged)));
internal static DependencyProperty ShouldCollapseAllProperty = DependencyProperty.Register("ShouldCollapseAll", typeof(bool), typeof(DesignerView), new PropertyMetadata(false, new PropertyChangedCallback(OnExpandAllCollapseAllChanged)));
const double scrollDeltaDivider = 100.0;
GridLength bottomPaneHeight;
EditingContext context;
DragDropHelper.ViewElementDragShadow viewElementDragShadow;
ZoomToTicksConverter zoomToTicksConverter;
ShellBarItemVisibility shellBarItemVisibility = ShellBarItemVisibility.Variables | ShellBarItemVisibility.Arguments | ShellBarItemVisibility.Imports;
ShellHeaderItemsVisibility shellHeaderItemsVisibility = ShellHeaderItemsVisibility.Breadcrumb | ShellHeaderItemsVisibility.ExpandAll | ShellHeaderItemsVisibility.CollapseAll;
Dictionary selectionMap = new Dictionary();
private bool isInErrorState = false;
const string breadCrumbRootKey = "BreadCrumbRoot";
const string selectionKey = "Selection";
const string zoomFactorKey = "ZoomFactor";
internal WorkflowViewElement lastClickedDesigner;
IVSSqmService sqmService;
ScrollViewerPanner scrollViewerPanner;
RubberBandSelector rubberBandSelector;
private DesignerViewProxy proxy;
private DesignerView()
{
}
internal DesignerView(EditingContext context)
{
this.proxy = new DesignerViewProxy(this);
this.context = context;
InitializeComponent();
this.InitializeMenuActions();
foreach (UIElement element in this.designerExtensionSurface.Children)
{
element.IsEnabled = false;
}
this.buttonArguments1.IsChecked = false;
UpdateArgumentsButtonVisibility(false);
this.zoomToTicksConverter = new ZoomToTicksConverter(this, this.zoomSlider, this.zoomPicker);
this.zoomSlider.ValueChanged += new RoutedPropertyChangedEventHandler(OnZoomSliderValueChanged);
HideBottomPane();
this.variables1.VariableCollectionChanged += this.OnVariablesCollectionChanged;
this.arguments1.ArgumentCollectionChanged += this.OnArgumentsCollectionChanged;
Dispatcher.UnhandledException += this.proxy.OnDispatcherUnhandledException;
this.ShouldIgnoreDataGridAutoCommit = false;
this.sqmService = this.Context.Services.GetService();
this.buttonPanMode.Visibility = this.IsPanModeEnabled ? Visibility.Visible : Visibility.Collapsed;
this.rubberBandSelector = this.IsRubberBandSelectionEnabled ? new RubberBandSelector(this.context) : null;
}
void OnReadOnlyStateChanged(ReadOnlyState state)
{
this.IsReadOnly = state.IsReadOnly;
}
void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
if (!e.Handled)
{
if (!isInErrorState)
{
isInErrorState = true;
//try to prun the visual tree and collapse all the workflow view elements that are too deep
//this is due to the limitation of WPF has a visual tree depth limit.
if (e.Exception is InvalidOperationException)
{
ICollection deepElements = VisualTreeUtils.PrunVisualTree(this.RootDesigner);
foreach (WorkflowViewElement viewElement in deepElements)
{
viewElement.ForceCollapse();
}
}
Exception ex = e.Exception.InnerException ?? e.Exception;
ErrorReporting.ShowErrorMessage(ex);
isInErrorState = false;
}
e.Handled = true;
}
}
public bool IsMultipleSelectionMode
{
get;
private set;
}
void OnDesignerViewLoaded(object sender, RoutedEventArgs e)
{
ViewStateService viewStateService = this.Context.Services.GetService();
ModelTreeManager modelTreeManager = this.context.Services.GetService();
//Initialize ShouldExpandAll if it exists in ViewState.
object expandAllState = viewStateService.RetrieveViewState(modelTreeManager.Root, DesignerView.ShouldExpandAllProperty.Name);
if (expandAllState != null)
{
this.ShouldExpandAll = (bool)expandAllState;
}
if (!this.ShouldExpandAll)
{
object collapseAllState = viewStateService.RetrieveViewState(modelTreeManager.Root, DesignerView.ShouldCollapseAllProperty.Name);
if (collapseAllState != null)
{
this.ShouldCollapseAll = (bool)collapseAllState;
}
}
// SQM: Open Minimap through designer surface
this.buttonMinimap.Checked += new RoutedEventHandler(SqmOpenMinimap);
this.expandAllButton.Click += new RoutedEventHandler(SqmExpandAll);
this.collapseAllButton.Click += new RoutedEventHandler(SqmCollapseAll);
if (this.IsPanModeEnabled)
{
this.scrollViewerPanner = new ScrollViewerPanner(this.ScrollViewer);
this.scrollViewerPanner.Hand = (Cursor)this.Resources["ReadyToPanCursor"];
this.scrollViewerPanner.DraggingHand = (Cursor)this.Resources["PanningCursor"];
}
}
void OnDesignerViewUnloaded(object sender, RoutedEventArgs e)
{
if (this.scrollViewerPanner != null)
{
this.scrollViewerPanner.ScrollViewer = null;
this.scrollViewerPanner = null;
}
}
void SqmCollapseAll(object sender, RoutedEventArgs e)
{
if (this.collapseAllButton.IsChecked == true)
{
FeatureUsageCounter.ReportUsage(sqmService, WorkflowDesignerFeatureId.CollapseAll);
}
else
{
FeatureUsageCounter.ReportUsage(sqmService, WorkflowDesignerFeatureId.Restore);
}
}
void SqmExpandAll(object sender, RoutedEventArgs e)
{
if (this.expandAllButton.IsChecked == true)
{
FeatureUsageCounter.ReportUsage(sqmService, WorkflowDesignerFeatureId.ExpandAll);
}
else
{
FeatureUsageCounter.ReportUsage(sqmService, WorkflowDesignerFeatureId.Restore);
}
}
void SqmOpenMinimap(object sender, RoutedEventArgs e)
{
FeatureUsageCounter.ReportUsage(sqmService, WorkflowDesignerFeatureId.Minimap);
}
static void OnExpandAllCollapseAllChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((DesignerView)o).OnExpandAllCollapseAllChanged(e);
}
void OnExpandAllCollapseAllChanged(DependencyPropertyChangedEventArgs e)
{
ViewStateService viewStateService = this.Context.Services.GetService();
ModelTreeManager modelTreeManager = this.context.Services.GetService();
{
viewStateService.StoreViewState(modelTreeManager.Root, e.Property.Name, e.NewValue);
}
}
protected override void OnInitialized(EventArgs e)
{
this.AddHandler(UIElement.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(this.OnWorkflowElementGotKeyboardFocus), true);
this.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.OnDesignerSurfaceMouseLeftButtonDown), true);
this.scrollViewer.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.OnScrollViewerMouseLeftButtonDown), true);
base.OnInitialized(e);
this.Foreground = new SolidColorBrush(SystemColors.ControlTextColor);
this.Loaded += this.OnDesignerViewLoaded;
this.Unloaded += this.OnDesignerViewUnloaded;
this.IsKeyboardFocusWithinChanged += this.OnDesignerKeyboardFocusWithinChanged;
this.MenuItemStyle = (Style)this.FindResource("menuItemStyle");
Fx.Assert(this.MenuItemStyle != null, "menuItemStyle resource not found");
this.MenuSeparatorStyle = (Style)this.FindResource("separatorStyle");
Fx.Assert(this.MenuSeparatorStyle != null, "separatorStyle resource not found");
ReadOnlyState state = this.Context.Items.GetValue();
this.IsReadOnly = state.IsReadOnly;
this.Context.Items.Subscribe(OnReadOnlyStateChanged);
}
public ModelItem ActivitySchema
{
get { return (ModelItem)GetValue(ActivitySchemaProperty); }
private set { SetValue(ActivitySchemaPropertyKey, value); }
}
public EditingContext Context
{
get { return this.context; }
}
public UIElement RootDesigner
{
get { return (UIElement)GetValue(RootDesignerProperty); }
set { SetValue(RootDesignerProperty, value); }
}
public bool ShouldExpandAll
{
get { return (bool)GetValue(ShouldExpandAllProperty); }
set { SetValue(ShouldExpandAllProperty, value); }
}
public bool ShouldCollapseAll
{
get { return (bool)GetValue(ShouldCollapseAllProperty); }
set { SetValue(ShouldCollapseAllProperty, value); }
}
public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
public WorkflowViewElement FocusedViewElement
{
get { return (WorkflowViewElement)GetValue(FocusedViewElementProperty); }
private set { SetValue(FocusedViewElementPropertyKey, value); }
}
public double ZoomFactor
{
get
{
return this.zoomToTicksConverter.ZoomFactor;
}
}
internal ScrollViewer ScrollViewer
{
get
{
return this.scrollViewer;
}
}
internal UIElement ScrollableContent
{
get
{
return this.scrollableContent;
}
}
internal bool SuppressSelectionOnMouseUp
{
get
{
if (this.rubberBandSelector == null)
{
return false;
}
return this.rubberBandSelector.IsSelected;
}
}
internal bool ShouldIgnoreDataGridAutoCommit
{
get;
set;
}
internal bool ShouldStillAllowRubberBandEvenIfMouseLeftButtonDownIsHandled
{
get;
set;
}
internal bool InPanMode
{
get { return (bool)GetValue(InPanModeProperty); }
set { SetValue(InPanModeProperty, value); }
}
private bool IsPanModeEnabled
{
get
{
DesignerConfigurationService configurationService = this.Context.Services.GetService();
if (configurationService != null)
{
return configurationService.PanModeEnabled;
}
return true;
}
}
private bool IsRubberBandSelectionEnabled
{
get
{
DesignerConfigurationService configurationService = this.Context.Services.GetService();
if (configurationService != null)
{
return configurationService.RubberBandSelectionEnabled;
}
return true;
}
}
public ShellBarItemVisibility WorkflowShellBarItemVisibility
{
get { return this.shellBarItemVisibility; }
set { this.ApplyShellBarItemVisibility(value); }
}
public ShellHeaderItemsVisibility WorkflowShellHeaderItemsVisibility
{
get { return this.shellHeaderItemsVisibility; }
set { this.ApplyShellHeaderItemsVisibility(value); }
}
public void MakeRootDesigner(ModelItem modelItem)
{
bool checkIfCanBeMadeRoot = true;
if (modelItem == modelItem.Root)
{
checkIfCanBeMadeRoot = false;
}
MakeRootDesigner(modelItem, /* setAsSelection = */ true, checkIfCanBeMadeRoot);
}
internal void MakeRootDesigner(ModelItem modelItem, bool setAsSelection)
{
MakeRootDesigner(modelItem, setAsSelection, true);
}
internal void ForceMakeRootDesigner(ModelItem modelItem)
{
MakeRootDesigner(modelItem, /* setAsSelection = */ true, false);
}
void SelectAll()
{
WorkflowViewElement root = this.RootDesigner as WorkflowViewElement;
ModelItem rootModelItem = null;
if (root != null)
{
rootModelItem = root.ModelItem;
}
if (rootModelItem != null)
{
ModelTreeManager modelTreeManager = this.Context.Services.GetService();
IEnumerable items = ModelTreeManager.Find(rootModelItem, delegate(ModelItem current)
{
WorkflowViewService viewService = this.Context.Services.GetService() as WorkflowViewService;
return (typeof(WorkflowViewElement).IsAssignableFrom(viewService.GetDesignerType(current.ItemType)));
}, true);
IEnumerable itemsToSelect = items
// ModelItemKeyValuePair is associated with CaseDesigner.
// So ModelItemKeyValuePair will be returned even if they are not really Cases.
// Those ModelItemKeyValuePairs need to be excluded.
.Where(item => !ModelUtilities.IsModelItemKeyValuePair(item.ItemType) || ModelUtilities.IsSwitchCase(item))
.Except(new ModelItem[] { rootModelItem });
Selection selection = new Selection(itemsToSelect);
this.Context.Items.SetValue(selection);
}
}
internal void BeginDragShadowTracking(DragDropHelper.ViewElementDragShadow dragShadow)
{
// Returns the first adorner layer in the visual tree above a specified Visual.
AdornerLayer layer = this.GetAdornerLayerForDragShadow();
if (null != layer)
{
layer.Add(dragShadow);
this.viewElementDragShadow = dragShadow;
//register for window messages notification
this.Context.Services.GetService().RegisterWindowMessageHandler(new WindowMessage(OnMessage));
}
}
internal void EndDragShadowTracking(DragDropHelper.ViewElementDragShadow dragShadow)
{
AdornerLayer layer = this.GetAdornerLayerForDragShadow();
if (null != layer)
{
//unregister from window message notification
this.Context.Services.GetService().UnregisterWindowMessageHandler(new WindowMessage(OnMessage));
layer.Remove(dragShadow);
this.viewElementDragShadow = null;
}
}
static void UpdateAncestorFlag(ModelItem oldRoot, ModelItem newRoot)
{
// Walk up the tree and update the flags from the new root. If we hit the old root in the process, we are done.
// Otherwise, continue to update the flags from the old root until we hit the new root.
if (oldRoot == newRoot)
{
return;
}
bool hitOldRoot = false;
if (newRoot != null)
{
WorkflowViewElement viewElement = newRoot.View as WorkflowViewElement;
if (viewElement != null)
{
viewElement.IsAncestorOfRootDesigner = false;
}
ModelItem parent = newRoot.Parent;
while (parent != null)
{
WorkflowViewElement view = parent.View as WorkflowViewElement;
if (view != null)
{
view.IsAncestorOfRootDesigner = true;
}
if (parent == oldRoot)
{
hitOldRoot = true;
}
parent = parent.Parent;
}
}
if (oldRoot != null && !hitOldRoot)
{
ModelItem parent = oldRoot.Parent;
while (parent != null && parent != newRoot)
{
WorkflowViewElement view = parent.View as WorkflowViewElement;
if (view != null)
{
view.IsAncestorOfRootDesigner = false;
}
parent = parent.Parent;
}
}
}
internal void MakeRootDesigner(ModelItem modelItem, bool setAsSelection, bool checkIfCanBeMadeRoot)
{
ModelItem currentRootModelItem = (this.RootDesigner != null) ? ((WorkflowViewElement)this.RootDesigner).ModelItem : null;
if (modelItem == currentRootModelItem)
{
return;
}
if (typeof(ActivityBuilder).IsAssignableFrom(modelItem.ItemType))
{
this.ActivitySchema = modelItem;
}
WorkflowViewService viewService = this.Context.Services.GetService() as WorkflowViewService;
//try get designer for given model item
Type designerType = viewService.GetDesignerType(modelItem.ItemType);
//if one doesn't exist - check its parent tree, perhaps there will be one
while (null == designerType && null != modelItem.Parent)
{
modelItem = modelItem.Parent;
designerType = viewService.GetDesignerType(modelItem.ItemType);
}
if (viewService.ShouldAppearOnBreadCrumb(modelItem, checkIfCanBeMadeRoot))
{
UpdateAncestorFlag(currentRootModelItem, modelItem);
Dictionary newSelectionMap = new Dictionary();
ModelItem newRootModelItem = modelItem;
ObservableCollection