static ConnectionPoint ConnectionPointHitTest(UIElement element, Point hitPoint) { FreeFormPanel panel = VisualTreeUtils.FindVisualAncestor <FreeFormPanel>(element); List <ConnectionPoint> connectionPoints = StateContainerEditor.GetConnectionPoints(element); return(FreeFormPanel.ConnectionPointHitTest(hitPoint, connectionPoints, panel)); }
private void AddNewTransition(string stateName) { ModelItem stateMachineModelItem = StateContainerEditor.GetStateMachineModelItem(this.parentStateModelItem); ModelItem toStateModelItem = null; foreach (ModelItem stateModelItem in stateMachineModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection) { if (string.Equals(stateName, stateModelItem.Properties[StateDesigner.DisplayNamePropertyName].ComputedValue as string, StringComparison.Ordinal)) { toStateModelItem = stateModelItem; } } if (null == toStateModelItem) { return; } Fx.Assert(toStateModelItem != null, "To state cannot be null."); using (EditingScope editingScope = (EditingScope)this.ModelItem.BeginEdit(SR.CreateTransition)) { ModelItem triggerModelItem = this.ModelItem.Properties[TriggerPropertyName].Value; State toState = toStateModelItem.GetCurrentValue() as State; ModelItem newTransitionItem = this.parentStateModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(new Transition() { Trigger = null == triggerModelItem ? null : triggerModelItem.GetCurrentValue() as Activity, DisplayName = StateContainerEditor.GenerateTransitionName(stateMachineModelItem), To = toState }); this.ViewStateService.StoreViewState(newTransitionItem, ExpandViewStateKey, true); if (null == triggerModelItem) { PointCollection thisPointCollection = this.ViewStateService.RetrieveViewState(this.ModelItem, StateContainerEditor.ConnectorLocationViewStateKey) as PointCollection; if (null != thisPointCollection && thisPointCollection.Any()) { PointCollection newTransitionViewState = new PointCollection { thisPointCollection[0] // start point }; if (toState == this.parentStateModelItem.GetCurrentValue()) { // add an invalid destination point for self-transition, to force a reroute of the connection point newTransitionViewState.Add(new Point(0, 0)); } this.ViewStateService.StoreViewState(newTransitionItem, StateContainerEditor.ConnectorLocationViewStateKey, newTransitionViewState); } } editingScope.Complete(); } this.UpdateTransitionsSharingTrigger(); }
void StoreConnectorLocationViewState(Connector connector, bool isUndoableViewState) { //This method will be called whenever the FreeFormPanel raises a location changed event on a connector. //Such location changed events are a result of changes already committed in the UI. Hence we do not want to react to such view state changes. //Using internalViewStateChange flag for that purpose. this.internalViewStateChange = true; this.StoreConnectorLocationViewState(StateContainerEditor.GetConnectorModelItem(connector), connector.Points, isUndoableViewState); this.internalViewStateChange = false; }
private void OnSourceStateClicked(object sender, RoutedEventArgs e) { ModelItem sourceState = StateContainerEditor.GetParentStateModelItemForTransition(this.ModelItem); if (sourceState != null) { this.Designer.MakeRootDesigner(sourceState); } }
void OnSetAsInitialCanExecute(object sender, CanExecuteRoutedEventArgs e) { ModelItem stateMachineModelItem = StateContainerEditor.GetStateMachineModelItem(this.ModelItem); e.CanExecute = (!this.IsReadOnly && stateMachineModelItem != null && this.ModelItem != stateMachineModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].Value && !this.IsFinalState() && !this.IsRootDesigner && StateContainerEditor.GetEmptyConnectionPoints(this).Count > 0); e.Handled = true; }
// referenceConnector is used when we are re-linking the connector. internal ConnectorCreationResult CreateConnectorGesture(ConnectionPoint sourceConnectionPoint, ConnectionPoint destConnectionPoint, Connector referenceConnector, bool isConnectorStartMoved) { Fx.Assert(sourceConnectionPoint != null, "sourceConnectionPoint is null."); Fx.Assert(destConnectionPoint != null, "destConnectionPoint is null."); ConnectorCreationResult result = ConnectorCreationResult.OtherFailure; if (destConnectionPoint.PointType != ConnectionPointKind.Outgoing && sourceConnectionPoint.PointType != ConnectionPointKind.Incoming) { if (sourceConnectionPoint.ParentDesigner is VirtualizedContainerService.VirtualizingContainer) { //bool sameDestination = false; ModelItem refTransitionModelItem = null; if (referenceConnector != null) { refTransitionModelItem = StateContainerEditor.GetConnectorModelItem(referenceConnector); } using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.CreateTransition)) { if (refTransitionModelItem != null) { this.CreateTransition(sourceConnectionPoint, destConnectionPoint, refTransitionModelItem, isConnectorStartMoved); } else { this.CreateTransition(sourceConnectionPoint, destConnectionPoint, null, false); } result = ConnectorCreationResult.Success; es.Complete(); } } else if (sourceConnectionPoint.ParentDesigner is StartSymbol) { ModelItem stateModelItem = ((VirtualizedContainerService.VirtualizingContainer)destConnectionPoint.ParentDesigner).ModelItem; if (IsFinalState(stateModelItem)) { result = ConnectorCreationResult.CannotSetFinalStateAsInitialState; } else { using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.SetInitialState)) { this.StateMachineModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(stateModelItem); PointCollection connectorViewState = new PointCollection(ConnectorRouter.Route(this.panel, sourceConnectionPoint, destConnectionPoint)); this.StoreConnectorLocationViewState(this.StateMachineModelItem, connectorViewState, true); result = ConnectorCreationResult.Success; es.Complete(); } } } } return(result); }
internal static List <ConnectionPoint> GetEmptyConnectionPoints(UIElement designer) { List <ConnectionPoint> connectionPoints = StateContainerEditor.GetConnectionPoints(designer); if (connectionPoints != null) { return(new List <ConnectionPoint>(connectionPoints.Where <ConnectionPoint>( (p) => { return p.AttachedConnectors == null || p.AttachedConnectors.Count == 0; }))); } return(new List <ConnectionPoint>()); }
void OnSetAsInitialExecute(object sender, ExecutedRoutedEventArgs e) { ModelItem stateMachineModelItem = StateContainerEditor.GetStateMachineModelItem(this.ModelItem); using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.SetInitialState)) { this.ViewStateService.RemoveViewState(stateMachineModelItem, StateContainerEditor.ConnectorLocationViewStateKey); stateMachineModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(this.ModelItem.GetCurrentValue()); es.Complete(); } e.Handled = true; }
static ConnectionPoint GetConnectionPoint(UIElement element, Point location) { List <ConnectionPoint> connectionPoints = StateContainerEditor.GetConnectionPoints(element); foreach (ConnectionPoint connectionPoint in connectionPoints) { if (DesignerGeometryHelper.ManhattanDistanceBetweenPoints(location, connectionPoint.Location) <= ConnectorRouter.EndPointTolerance) { return(connectionPoint); } } return(null); }
private IEnumerable <ModelItem> GetAvailableStates() { List <ModelItem> availableStates = new List <ModelItem>(); ModelItem stateMachineModelItem = StateContainerEditor.GetStateMachineModelItem(this.parentStateModelItem); Fx.Assert(null != stateMachineModelItem, "StateMachine must be the ancestor."); Dictionary <ModelItem, int> stateToConnectionMap = new Dictionary <ModelItem, int>(); foreach (ModelItem stateModelItem in stateMachineModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection) { if (!stateToConnectionMap.ContainsKey(stateModelItem)) { stateToConnectionMap[stateModelItem] = 0; } foreach (ModelItem transitionModelItem in stateModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection) { // to simplify the model, count a source connection as one, regardless of whether it is shared Trigger or not. stateToConnectionMap[stateModelItem]++; ModelItem toStateModelItem = transitionModelItem.Properties[TransitionDesigner.ToPropertyName].Value; Fx.Assert(toStateModelItem != null, "To state of a transition cannot be null."); if (stateToConnectionMap.ContainsKey(toStateModelItem)) { stateToConnectionMap[toStateModelItem]++; } else { stateToConnectionMap[toStateModelItem] = 1; } } } foreach (ModelItem stateModelItem in stateToConnectionMap.Keys) { if (stateToConnectionMap[stateModelItem] < TotalFreeConnectionPointNum) { // only allow connection to state that have available connection points availableStates.Add(stateModelItem); } } return(availableStates.OrderBy(modelItem => modelItem.Properties[StateDesigner.DisplayNamePropertyName].Value == null ? SR.EmptyName : modelItem.Properties[StateDesigner.DisplayNamePropertyName].Value.GetCurrentValue())); }
internal int DeleteConnectorModelItem(Connector connector, bool rerouting = false) { ModelItem connectorModelItem = StateContainerEditor.GetConnectorModelItem(connector); if (!rerouting) { if (connector is ConnectorWithStartDot) { connector.StartDot.MouseDown -= new MouseButtonEventHandler(OnConnectorStartDotMouseDown); connector.StartDot.MouseUp -= new MouseButtonEventHandler(OnConnectorStartDotMouseUp); } connector.GotKeyboardFocus -= new KeyboardFocusChangedEventHandler(OnConnectorGotKeyboardFocus); connector.RequestBringIntoView -= new RequestBringIntoViewEventHandler(OnConnectorRequestBringIntoView); connector.GotFocus -= new RoutedEventHandler(OnConnectorGotFocus); connector.MouseDoubleClick -= new MouseButtonEventHandler(OnConnectorMouseDoubleClick); connector.MouseDown -= new MouseButtonEventHandler(OnConnectorMouseDown); connector.KeyDown -= new KeyEventHandler(OnConnectorKeyDown); connector.ContextMenuOpening -= new ContextMenuEventHandler(OnConnectorContextMenuOpening); connector.Unloaded -= new RoutedEventHandler(OnConnectorUnloaded); } int removedIndex = InvalidIndex; if (connectorModelItem.ItemType == typeof(Transition)) { ModelItemCollection transitions = StateContainerEditor.GetParentStateModelItemForTransition(connectorModelItem).Properties[StateDesigner.TransitionsPropertyName].Collection; removedIndex = transitions.IndexOf(connectorModelItem); Fx.Assert(removedIndex >= 0, "can't find the connector ModelItem in collection"); transitions.Remove(connectorModelItem); } // Connector from initial node else if (connectorModelItem.ItemType == typeof(StateMachine)) { using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(SR.ClearInitialState)) { connectorModelItem.Properties[StateMachineDesigner.InitialStatePropertyName].SetValue(null); if (!rerouting) { this.ViewStateService.StoreViewStateWithUndo(connectorModelItem, ConnectorLocationViewStateKey, null); } es.Complete(); } } return(removedIndex); }
public static void RegisterMetadata(AttributeTableBuilder builder) { Type stateType = typeof(State); builder.AddCustomAttributes(stateType, new DesignerAttribute(typeof(StateDesigner))); builder.AddCustomAttributes(stateType, stateType.GetProperty(StateDesigner.EntryPropertyName), BrowsableAttribute.No); builder.AddCustomAttributes(stateType, stateType.GetProperty(StateDesigner.ExitPropertyName), BrowsableAttribute.No); builder.AddCustomAttributes(stateType, stateType.GetProperty(StateDesigner.TransitionsPropertyName), BrowsableAttribute.No); builder.AddCustomAttributes(stateType, stateType.GetProperty(StateDesigner.IsFinalPropertyName), BrowsableAttribute.No); builder.AddCustomAttributes(stateType, stateType.GetProperty(StateDesigner.VariablesPropertyName), BrowsableAttribute.No); builder.AddCustomAttributes(stateType, new ShowInOutlineViewAttribute()); builder.AddCustomAttributes(stateType, new AllowBreakpointAttribute()); builder.AddCustomAttributes(stateType, stateType.GetProperty(StateDesigner.TransitionsPropertyName), new ShowPropertyInOutlineViewAttribute() { CurrentPropertyVisible = false }); builder.AddCustomAttributes(stateType, new ActivityDesignerOptionsAttribute { OutlineViewIconProvider = (modelItem) => { ResourceDictionary icons = EditorResources.GetIcons(); if (modelItem != null) { object icon = null; if (StateContainerEditor.IsFinalState(modelItem) && icons.Contains("FinalStateIcon")) { icon = icons["FinalStateIcon"]; } else if (icons.Contains("StateIcon")) { icon = icons["StateIcon"]; } if (icon != null && icon is DrawingBrush) { return((DrawingBrush)icon); } } return(null); } }); }
static ConnectionPoint GetSrcConnectionPointForSharedTrigger(UIElement sourceDesigner, ModelItem connectorModelItem) { ConnectionPoint sourceConnectionPoint = null; List <Connector> connectors = StateContainerEditor.GetOutgoingConnectors(sourceDesigner); foreach (Connector connector in connectors) { ModelItem modelItem = StateContainerEditor.GetConnectorModelItem(connector); if (modelItem != null && modelItem.ItemType == typeof(Transition)) { if (modelItem.Properties[TransitionDesigner.TriggerPropertyName].Value == connectorModelItem.Properties[TransitionDesigner.TriggerPropertyName].Value) { sourceConnectionPoint = FreeFormPanel.GetSourceConnectionPoint(connector); } } } return(sourceConnectionPoint); }
protected override void OnMouseMove(MouseEventArgs args) { base.OnMouseMove(args); if (args != null && !this.Disabled) { if (args.LeftButton == MouseButtonState.Pressed && this.IsMouseCaptured && this.scope != null) { StateContainerEditor stateContainerEditor = this.ParentStateContainerEditor; FreeFormPanel panel = stateContainerEditor.Panel; Grid stateContainerGrid = stateContainerEditor.stateContainerGrid; Point currentPosition = Mouse.GetPosition(stateContainerGrid); currentPosition.Offset(this.offset.X, this.offset.Y); stateContainerEditor.StateContainerWidth = Math.Min(Math.Max(panel.RequiredWidth, currentPosition.X), stateContainerGrid.MaxWidth); stateContainerEditor.StateContainerHeight = Math.Min(Math.Max(panel.RequiredHeight, currentPosition.Y), stateContainerGrid.MaxHeight); args.Handled = true; } } }
private void StateDesignerToolTipOpening(object sender, ToolTipEventArgs e) { StateContainerEditor stateContainerEditor = (StateContainerEditor)sender; if (StateContainerEditor.CopiedTransitionDestinationState != null) { WorkflowViewElement view = VisualTreeUtils.FindVisualAncestor <WorkflowViewElement>(stateContainerEditor); if (view != null) { StateContainerEditor container = (StateContainerEditor)DragDropHelper.GetCompositeView(view); string errorMessage; if (container != null && container.CanPasteTransition(StateContainerEditor.CopiedTransitionDestinationState, out errorMessage, view.ModelItem)) { stateContainerEditor.ToolTip = SR.EditStateToolTip + Environment.NewLine + SR.PasteTransitionToolTip; return; } } } stateContainerEditor.ToolTip = SR.EditStateToolTip; }
public object OnItemsCopied(List <ModelItem> itemsToCopy) { itemsToCopy.Remove(this.initialModelItem); // If the item copied is Transition, save its destination state guid to find the destination state when pasting. if (itemsToCopy.Count == 1) { ModelItem item = itemsToCopy.First(); if (item != null && item.ItemType == typeof(Transition)) { ModelItem destinationState = item.Properties[TransitionDesigner.ToPropertyName].Value; if (!modelItemToGuid.ContainsKey(destinationState)) { modelItemToGuid.Add(destinationState, Guid.NewGuid().ToString()); } CopiedTransitionDestinationState = destinationState; return(modelItemToGuid[destinationState]); } } itemsToCopy.RemoveAll(item => item.ItemType == typeof(Transition)); // Save the locations of copied items relative to the statemachine editor to the metadata. // The metadata will be used to translate the location view states of pasted items to the pasting target. PointCollection metaData = new PointCollection(); foreach (ModelItem modelItem in itemsToCopy) { object viewState = this.ViewStateService.RetrieveViewState(modelItem, ShapeLocationViewStateKey); Point location = (Point)viewState; StateContainerEditor parentDesigner = VisualTreeUtils.FindVisualAncestor <StateContainerEditor>(GetStateView(modelItem)); location = parentDesigner.panel.GetLocationRelativeToOutmostPanel(location); metaData.Add(location); } CopiedTransitionDestinationState = null; return(metaData); }
public TransitionDesigner() { InitializeComponent(); this.TransitionsSharingTrigger = new ObservableCollection <ExpandableItemWrapper>(); this.Loaded += (sender, e) => { if (!this.isPopulated) { this.isPopulated = true; this.TransitionsSharingTrigger.CollectionChanged += OnTransitionsCollectionChanged; this.ModelItem.PropertyChanged += OnModelItemPropertyChanged; this.parentStateModelItem = StateContainerEditor.GetParentStateModelItemForTransition(this.ModelItem); this.parentStateModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.CollectionChanged += OnTransitionsModelItemCollectionChanged; ExpandableItemWrapper selectedItem = this.UpdateTransitionsSharingTrigger(); if (null != selectedItem) { this.SelectedTransition = selectedItem; } } }; this.Unloaded += (sender, e) => { if (this.isPopulated) { this.isPopulated = false; this.TransitionsSharingTrigger.Clear(); this.TransitionsSharingTrigger.CollectionChanged -= OnTransitionsCollectionChanged; this.ModelItem.PropertyChanged -= OnModelItemPropertyChanged; this.parentStateModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.CollectionChanged -= OnTransitionsModelItemCollectionChanged; this.SelectedTransition = null; this.parentStateModelItem = null; } }; }
// referenceTransitionModelItem is used when a connector is re-linked. void CreateTransition(ConnectionPoint sourceConnPoint, ConnectionPoint destConnPoint, ModelItem referenceTransitionModelItem, bool isSourceMoved) { VirtualizedContainerService.VirtualizingContainer srcDesigner = sourceConnPoint.ParentDesigner as VirtualizedContainerService.VirtualizingContainer; Fx.Assert(srcDesigner != null, "srcDesigner should not be null."); VirtualizedContainerService.VirtualizingContainer destDesigner = destConnPoint.ParentDesigner as VirtualizedContainerService.VirtualizingContainer; Fx.Assert(destDesigner != null, "destDesigner should not be null."); ModelItem srcModelItem = srcDesigner.ModelItem; ModelItem destModelItem = destDesigner.ModelItem; ModelItem transitionModelItem = null; // We are moving the connector. if (referenceTransitionModelItem != null && referenceTransitionModelItem.ItemType == typeof(Transition)) { transitionModelItem = referenceTransitionModelItem; // We are moving the start of the connector. We only preserve the trigger if it is not shared. if (isSourceMoved) { Transition referenceTransition = referenceTransitionModelItem.GetCurrentValue() as Transition; ModelItem stateModelItem = GetParentStateModelItemForTransition(referenceTransitionModelItem); State state = stateModelItem.GetCurrentValue() as State; bool isTriggerShared = false; foreach (Transition transition in state.Transitions) { if (transition != referenceTransition && transition.Trigger == referenceTransition.Trigger) { isTriggerShared = true; break; } } if (isTriggerShared) { transitionModelItem.Properties[TransitionDesigner.TriggerPropertyName].SetValue(null); } } transitionModelItem.Properties[TransitionDesigner.ToPropertyName].SetValue(destModelItem); srcModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(transitionModelItem); } // We are creating a new connector. else { ModelItem stateMachineModelItem = GetStateMachineModelItem(srcModelItem); Transition newTransition = new Transition() { DisplayName = StateContainerEditor.GenerateTransitionName(stateMachineModelItem) }; newTransition.To = destModelItem.GetCurrentValue() as State; // Assign the shared trigger. if (sourceConnPoint.AttachedConnectors.Count > 0) { Connector connector = sourceConnPoint.AttachedConnectors[0]; Transition existingTransition = StateContainerEditor.GetConnectorModelItem(connector).GetCurrentValue() as Transition; newTransition.Trigger = existingTransition.Trigger; } transitionModelItem = srcModelItem.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(newTransition); } if (transitionModelItem != null) { // if the transition connection is re-routed, the SrcConnPointIndex needs to be updated. PointCollection connectorViewState = new PointCollection(ConnectorRouter.Route(this.panel, sourceConnPoint, destConnPoint)); int srcConnectionPointIndex = StateContainerEditor.GetConnectionPoints(sourceConnPoint.ParentDesigner).IndexOf(sourceConnPoint); int destConnectionPointIndex = StateContainerEditor.GetConnectionPoints(destConnPoint.ParentDesigner).IndexOf(destConnPoint); this.StoreConnectorLocationViewState(transitionModelItem, connectorViewState, true); this.ViewStateService.StoreViewStateWithUndo(transitionModelItem, SrcConnectionPointIndexStateKey, srcConnectionPointIndex); this.ViewStateService.StoreViewStateWithUndo(transitionModelItem, DestConnectionPointIndexStateKey, destConnectionPointIndex); } }
//This returns the closest non-incoming connectionPoint on source. Return value will be different than destConnectionPoint. static ConnectionPoint GetClosestSrcConnectionPoint(UIElement src, ConnectionPoint destConnectionPoint) { ConnectionPoint srcConnectionPoint = null; if (destConnectionPoint.PointType != ConnectionPointKind.Outgoing) { srcConnectionPoint = GetClosestConnectionPointNotOfType(destConnectionPoint, StateContainerEditor.GetConnectionPoints(src), ConnectionPointKind.Incoming); } return(srcConnectionPoint); }
void UpdateLocationViewStatesByMetaData(List <ModelItem> itemsPasted, List <object> metaData, StateContainerEditor container) { Fx.Assert(container != null, "The view states must be calculated related to a parent StateContainerEditor."); // If the states are not copied from state machine view (e.g., when the State designer is the breadcrumb root), // there is no meta data if (metaData != null && metaData.Count > 0) { int ii = 0; foreach (object data in metaData) { PointCollection points = (PointCollection)data; foreach (Point point in points) { // translate location view states to be in the coordinate system of the pasting target this.ViewStateService.StoreViewState(itemsPasted[ii], ShapeLocationViewStateKey, container.panel.TranslatePoint(point, container.panel)); ++ii; } } Fx.Assert(itemsPasted.Count == ii, "itemsCopied does not match the metaData."); } }
//This returns the closest non-outgoing connectionPoint on dest. Return value will be different than sourceConnectionPoint. static ConnectionPoint GetClosestDestConnectionPoint(ConnectionPoint sourceConnectionPoint, UIElement dest) { ConnectionPoint destConnectionPoint = null; if (sourceConnectionPoint.PointType != ConnectionPointKind.Incoming) { destConnectionPoint = GetClosestConnectionPointNotOfType(sourceConnectionPoint, StateContainerEditor.GetConnectionPoints(dest), ConnectionPointKind.Outgoing); } return(destConnectionPoint); }
void Cleanup() { this.panel.Children.Clear(); // Cleaning up the designers as they might be re-used. foreach (UIElement element in this.modelItemToUIElement.Values) { element.MouseEnter -= new MouseEventHandler(OnChildElementMouseEnter); element.MouseLeave -= new MouseEventHandler(OnChildElementMouseLeave); ((FrameworkElement)element).SizeChanged -= new SizeChangedEventHandler(OnChildElementSizeChanged); } this.modelItemToUIElement.Clear(); this.panel.LocationChanged -= new LocationChangedEventHandler(OnFreeFormPanelLocationChanged); this.panel.ConnectorMoved -= new ConnectorMovedEventHandler(OnFreeFormPanelConnectorMoved); this.panel.LayoutUpdated -= new EventHandler(OnFreeFormPanelLayoutUpdated); this.panel.RequiredSizeChanged -= new RequiredSizeChangedEventHandler(OnFreeFormPanelRequiredSizeChanged); this.ViewStateService.ViewStateChanged -= new ViewStateChangedEventHandler(OnViewStateChanged); if (this.ModelItem.ItemType == typeof(StateMachine)) { // Only StateMachine supports "States" collection this.ModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection.CollectionChanged -= new NotifyCollectionChangedEventHandler(OnStateCollectionChanged); this.ModelItem.PropertyChanged -= new PropertyChangedEventHandler(this.OnModelPropertyChanged); ModelTreeManager modelTreeManager = this.Context.Services.GetService<ModelTreeManager>(); modelTreeManager.EditingScopeCompleted -= new EventHandler<EditingScopeEventArgs>(this.OnEditingScopeCompleted); foreach (ModelItem modelItem in this.ModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection) { if (modelItem.ItemType == typeof(State)) { ModelItemCollection transitions = modelItem.Properties[StateDesigner.TransitionsPropertyName].Collection; if (this.listenedTransitionCollections.Contains(transitions)) { transitions.CollectionChanged -= new NotifyCollectionChangedEventHandler(this.OnTransitionCollectionChanged); this.listenedTransitionCollections.Remove(transitions); } } } } // stateMachineContainerEditor will be null when dropping a State into a WorkflowItemPresenter. if (this.ModelItem.ItemType == typeof(State) && this.stateMachineContainerEditor != null) { this.stateMachineContainerEditor = null; } }
void Populate() { // Keep track of the outmost editor, which may not be accessible by traversing the visual tree when the designer is deleted. this.stateMachineContainerEditor = this.GetStateMachineContainerEditor(); this.panel.LocationChanged += new LocationChangedEventHandler(OnFreeFormPanelLocationChanged); this.panel.ConnectorMoved += new ConnectorMovedEventHandler(OnFreeFormPanelConnectorMoved); this.panel.LayoutUpdated += new EventHandler(OnFreeFormPanelLayoutUpdated); this.panel.RequiredSizeChanged += new RequiredSizeChangedEventHandler(OnFreeFormPanelRequiredSizeChanged); this.ViewStateService.ViewStateChanged += new ViewStateChangedEventHandler(OnViewStateChanged); if (this.ModelItem.ItemType == typeof(StateMachine)) { // Only StateMachine supports "States" collection IsStateMachineContainer = true; this.ModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection.CollectionChanged += new NotifyCollectionChangedEventHandler(OnStateCollectionChanged); this.ModelItem.PropertyChanged += new PropertyChangedEventHandler(this.OnModelPropertyChanged); ModelTreeManager modelTreeManager = this.Context.Services.GetService<ModelTreeManager>(); modelTreeManager.EditingScopeCompleted += new EventHandler<EditingScopeEventArgs>(this.OnEditingScopeCompleted); foreach (ModelItem modelItem in this.ModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection) { if (modelItem.ItemType == typeof(State)) { ModelItemCollection transitions = modelItem.Properties[StateDesigner.TransitionsPropertyName].Collection; if (!this.listenedTransitionCollections.Contains(transitions)) { transitions.CollectionChanged += new NotifyCollectionChangedEventHandler(this.OnTransitionCollectionChanged); this.listenedTransitionCollections.Add(transitions); } } } } object widthViewState = this.ViewStateService.RetrieveViewState(this.ModelItem, StateContainerWidthViewStateKey); if (widthViewState != null) { this.StateContainerWidth = (double)widthViewState; } object heightViewState = this.ViewStateService.RetrieveViewState(this.ModelItem, StateContainerHeightViewStateKey); if (heightViewState != null) { this.StateContainerHeight = (double)heightViewState; } this.panel.Children.Clear(); this.modelItemToUIElement.Clear(); this.shapeLocations.Clear(); if (this.ModelItem.ItemType == typeof(StateMachine)) { this.AddInitialNode(); this.AddStateVisuals(this.ModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection); } }
public void OnItemsPasted(List <object> itemsToPaste, List <object> metaData, Point pastePoint, WorkflowViewElement pastePointReference) { if (this.ModelItem.ItemType == typeof(State)) { WorkflowViewElement view = VisualTreeUtils.FindVisualAncestor <WorkflowViewElement>(this); if (view != null) { StateContainerEditor container = (StateContainerEditor)DragDropHelper.GetCompositeView(view); container.OnItemsPasted(itemsToPaste, metaData, pastePoint, pastePointReference); } return; } if (itemsToPaste.Count == 1 && itemsToPaste.First() is Transition) { if (metaData == null || metaData.Count != 1 || !(metaData.First() is string)) { ShowMessageBox(SR.PasteTransitionWithoutDestinationState); return; } ModelItem destinationState = FindState(metaData.First() as string); if (destinationState == null) { ShowMessageBox(SR.PasteTransitionWithoutDestinationState); return; } this.PopulateVirtualizingContainer(destinationState); ModelItem[] selectedItems = this.Context.Items.GetValue <Selection>().SelectedObjects.ToArray(); string errorMessage; if (!CanPasteTransition(destinationState, out errorMessage, selectedItems)) { ShowMessageBox(errorMessage); return; } Transition pastedTransition = itemsToPaste.First() as Transition; Fx.Assert(pastedTransition != null, "Copied Transition should not be null."); using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit(System.Activities.Presentation.SR.PropertyChangeEditingScopeDescription)) { string displayName = pastedTransition.DisplayName; bool isFirst = true; foreach (ModelItem selectedItem in selectedItems) { if (!isFirst) { StringReader reader = new StringReader(XamlServices.Save(pastedTransition)); pastedTransition = (Transition)XamlServices.Load(reader); } ModelItem transitionModelItem = this.Context.Services.GetRequiredService <ModelTreeManager>().WrapAsModelItem(pastedTransition); ModelItem sourceState = selectedItem; sourceState.Properties[StateDesigner.TransitionsPropertyName].Collection.Add(transitionModelItem); transitionModelItem.Properties[TransitionDesigner.ToPropertyName].SetValue(destinationState); if (isFirst) { this.ViewStateService.RemoveViewState(transitionModelItem, ConnectorLocationViewStateKey); this.ViewStateService.RemoveViewState(transitionModelItem, SrcConnectionPointIndexStateKey); this.ViewStateService.RemoveViewState(transitionModelItem, DestConnectionPointIndexStateKey); isFirst = false; } } es.Complete(); } } else { List <ModelItem> modelItemsPasted = new List <ModelItem>(); List <State> states = new List <State>(); foreach (object obj in itemsToPaste) { State state; if (obj is FinalState) { state = new State() { DisplayName = DefaultFinalStateDisplayName, IsFinal = true }; } else { state = (State)obj; if (state.DisplayName == null) { state.DisplayName = DefaultStateDisplayName; } } states.Add(state); } RemoveDanglingTransitions(states); using (EditingScope es = (EditingScope)this.ModelItem.BeginEdit( System.Activities.Presentation.SR.CollectionAddEditingScopeDescription)) { // Fix 157591 by storing the height and width of the container "before" the new states are added to the // panel, and group the insertion inside one editing scope - such that Undo will also restore the // size of the StateMachineContainer to pre-insert size. StoreShapeSizeWithUndoRecursively(this.ModelItem); foreach (State state in states) { ModelItem stateModelItem = (this.ModelItem.ItemType == typeof(StateMachine)) ? this.ModelItem.Properties[StateMachineDesigner.StatesPropertyName].Collection.Add(state) : GetStateMachineModelItem(this.ModelItem).Properties[StateMachineDesigner.StatesPropertyName].Collection.Add(state); modelItemsPasted.Add(stateModelItem); } es.Complete(); } if (modelItemsPasted.Count > 0) { // translate location view states to be in the coordinate system of the pasting target Fx.Assert(this.ModelItem.ItemType == typeof(StateMachine), "Only StateMachine contain the StateContainerEditor."); this.UpdateLocationViewStatesByMetaData(modelItemsPasted, metaData, this); if (pastePoint.X > 0 && pastePoint.Y > 0) { if (pastePointReference != null) { pastePoint = pastePointReference.TranslatePoint(pastePoint, this.panel); pastePoint.X = pastePoint.X < 0 ? 0 : pastePoint.X; pastePoint.Y = pastePoint.Y < 0 ? 0 : pastePoint.Y; } this.UpdateLocationViewStatesByPoint(modelItemsPasted, pastePoint); } // If paste point is not available, paste the items to the top left corner. else { this.UpdateLocationViewStatesToAvoidOverlap(modelItemsPasted); } } this.Dispatcher.BeginInvoke(() => { if (modelItemsPasted.Count > 0 && modelItemsPasted[0] != null) { Keyboard.Focus(modelItemsPasted[0].View as IInputElement); } this.Context.Items.SetValue(new Selection(modelItemsPasted)); }, DispatcherPriority.ApplicationIdle ); } }
void OnStateContainerUnloaded(object sender, RoutedEventArgs e) { this.stateContainerEditor = null; }
internal bool IsFinalState() { return(StateContainerEditor.IsFinalState(this.ModelItem)); }
void UpdateLocationViewStatesToAvoidOverlap(List <ModelItem> itemsPasted) { int offset = 0; if (itemsPasted.Count > 0) { //Check to see if the first element in the input list needs offset. Generalize that information for all ModelItems in the input list. object location = this.ViewStateService.RetrieveViewState(itemsPasted[0], ShapeLocationViewStateKey); HashSet <Point> targetOccupiedLocations = null; if (this.ModelItem.ItemType == typeof(StateMachine)) { targetOccupiedLocations = this.shapeLocations; } else { ModelItem stateMachineModelItem = StateContainerEditor.GetStateMachineModelItem(this.ModelItem); StateMachineDesigner designer = stateMachineModelItem.View as StateMachineDesigner; if (designer != null) { targetOccupiedLocations = designer.StateContainerEditor.shapeLocations; } } if (location != null && targetOccupiedLocations != null) { Point locationOfShape = (Point)location; bool isOverlapped; do { isOverlapped = false; // need to check for each point on the canvas foreach (var point in targetOccupiedLocations) { // When the pasting occurs, the pasted point may not be exactly the same // as the copied point (with a slight margin of offset). Therefore, // we need to detect if the pasted point is within the boundary of the copied // object. If so, offset the pasted position such that the overlap is not observable. if ((locationOfShape.X < point.X + FreeFormPanel.GridSize && locationOfShape.X > point.X - FreeFormPanel.GridSize) && (locationOfShape.Y < point.Y + FreeFormPanel.GridSize && locationOfShape.Y > point.Y - FreeFormPanel.GridSize)) { offset++; locationOfShape.Offset(FreeFormPanel.GridSize, FreeFormPanel.GridSize); isOverlapped = true; break; } } } while (isOverlapped); } } //Update ViewState according to calculated offset. if (offset > 0) { double offsetValue = FreeFormPanel.GridSize * offset; OffsetLocationViewStates(new Vector(offsetValue, offsetValue), itemsPasted, GetTransitionModelItems(itemsPasted), false); } }
void OnStateContainerLoaded(object sender, RoutedEventArgs e) { this.stateContainerEditor = sender as StateContainerEditor; }
void UpdateLocationViewStatesByMetaData(List<ModelItem> itemsPasted, List<object> metaData, StateContainerEditor container) { Fx.Assert(container != null, "The view states must be calculated related to a parent StateContainerEditor."); // If the states are not copied from state machine view (e.g., when the State designer is the breadcrumb root), // there is no meta data if (metaData != null && metaData.Count > 0) { int ii = 0; foreach (object data in metaData) { PointCollection points = (PointCollection)data; foreach (Point point in points) { // translate location view states to be in the coordinate system of the pasting target this.ViewStateService.StoreViewState(itemsPasted[ii], ShapeLocationViewStateKey, container.panel.TranslatePoint(point, container.panel)); ++ii; } } Fx.Assert(itemsPasted.Count == ii, "itemsCopied does not match the metaData."); } }
void DoDeleteItems(List <ModelItem> itemsToDelete, bool removeIncomingConnectors) { itemsToDelete.Remove(this.initialModelItem); if (itemsToDelete.Count == 1 && itemsToDelete.First().ItemType == typeof(Transition)) { this.DeleteConnectorModelItem(this.selectedConnector); return; } itemsToDelete.RemoveAll(item => item.ItemType == typeof(Transition)); HashSet <Connector> connectorsToDelete = new HashSet <Connector>(); List <ModelItem> allStateModelItemsToDelete = new List <ModelItem>(); IEnumerable <ModelItem> selectedStateModelItems = this.Context.Items.GetValue <Selection>().SelectedObjects .Where <ModelItem>((p) => { return(p.ItemType == typeof(State)); }); foreach (ModelItem stateModelItem in itemsToDelete) { allStateModelItemsToDelete.Add(stateModelItem); } foreach (ModelItem modelItem in allStateModelItemsToDelete) { // We only need to delete incoming connectors to the states to be deleted; outgoing connectors will be deleted // automatically when the containing state is deleted. List <Connector> incomingConnectors = StateContainerEditor.GetIncomingConnectors(GetStateView(modelItem)); foreach (Connector connector in incomingConnectors) { ModelItem transitionModelItem = StateContainerEditor.GetConnectorModelItem(connector); // If the transition is contained by the states to delete, we don't bother to delete it separately. if (!StateContainerEditor.IsTransitionModelItemContainedByStateModelItems(transitionModelItem, selectedStateModelItems)) { connectorsToDelete.Add(connector); } } } // If we don't need to remove incoming connectors, we still remove the transitions but then add them back later. // This is in order to create an undo unit that contains the change notifications needed to make undo/redo work correctly. foreach (Connector connector in connectorsToDelete) { ModelItem connectorModelItem = StateContainerEditor.GetConnectorModelItem(connector); if (removeIncomingConnectors || connectorModelItem.ItemType == typeof(Transition)) { this.DeleteConnectorModelItem(connector); } } if (!removeIncomingConnectors) { foreach (Connector connector in connectorsToDelete) { ModelItem connectorModelItem = StateContainerEditor.GetConnectorModelItem(connector); if (connectorModelItem.ItemType == typeof(Transition)) { StateContainerEditor.GetParentStateModelItemForTransition(connectorModelItem).Properties[StateDesigner.TransitionsPropertyName].Collection.Add(connectorModelItem); } } } if (null != itemsToDelete) { itemsToDelete.ForEach(p => this.DeleteState(p, removeIncomingConnectors)); } }