File: System\Activities\Core\Presentation\FlowSwitchLink.cs
Project: ndp\cdf\src\NetFx40\Tools\System.Activities.Core.Presentation\System.Activities.Core.Presentation.csproj (System.Activities.Core.Presentation)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.Activities.Core.Presentation
{
    using System;
    using System.Activities.Presentation;
    using System.Activities.Presentation.Model;
    using System.Activities.Presentation.View;
    using System.Activities.Statements;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Data;
 
    abstract class FlowSwitchLink<T> : DependencyObject, IFlowSwitchLink
    {
        static DependencyProperty caseProperty = DependencyProperty.Register("Case", typeof(T), typeof(FlowSwitchLink<T>), new FrameworkPropertyMetadata(new PropertyChangedCallback(FlowSwitchLink<T>.OnCasePropertyChanged)));
        static DependencyProperty isDefaultCaseProperty = DependencyProperty.Register("IsDefault", typeof(bool), typeof(FlowSwitchLink<T>), new FrameworkPropertyMetadata(new PropertyChangedCallback(FlowSwitchLink<T>.OnIsDefaultCasePropertyChanged)));
 
        private FlowSwitch<T> parentFlowSwitch;
        protected bool internalChange = false;
        protected ModelItem flowSwitchModelItem;
        const string DefaultConnectorViewStateKey = "Default";
        const string CaseViewStateKeyAppendString = "Connector";
        bool internalDefaultCaseChange = false;
 
        public FlowSwitchLink(ModelItem flowSwitchMI, T caseValue, bool isDefault)
        {
            this.flowSwitchModelItem = flowSwitchMI;
            object flowSwitch = this.flowSwitchModelItem.GetCurrentValue();
            this.parentFlowSwitch = (FlowSwitch<T>)this.flowSwitchModelItem.GetCurrentValue();
            this.internalChange = true;
            this.internalDefaultCaseChange = true;
            if (!isDefault)
            {
                this.CaseObject = caseValue;
            }
            this.IsDefaultCase = isDefault;
            this.internalDefaultCaseChange = false;
            this.internalChange = false;
        }
 
        [BrowsableAttribute(false)]
        public ModelItem ModelItem
        { get; set; }
 
        public CaseKeyValidationCallbackDelegate ValidateCaseKey
        {
            get
            {
                return (object obj, out string reason) =>
                {
                    return GenericFlowSwitchHelper.ValidateCaseKey(obj,
                        this.flowSwitchModelItem.Properties["Cases"],
                        typeof(T),
                        out reason);
                };
            }
        }
 
        [BrowsableAttribute(false)]
        public FlowNode ParentFlowSwitch
        {
            get
            {
                return this.parentFlowSwitch;
            }
            set
            {
                this.parentFlowSwitch = value as FlowSwitch<T>;
            }
        }
 
        public bool IsDefaultCase
        {
            get
            {
                return (bool)GetValue(FlowSwitchLink<T>.isDefaultCaseProperty);
            }
            set
            {
                SetValue(FlowSwitchLink<T>.isDefaultCaseProperty, value);
            }
        }
 
        [Browsable(false)]
        public string CaseName
        {
            get
            {
                object value = GetValue(FlowSwitchLink<T>.caseProperty);
                return GenericFlowSwitchHelper.GetString((T)value, typeof(T));
            }
        }
 
        [Browsable(false)]
        public object CaseObject
        {
            get
            {
                return GetValue(FlowSwitchLink<T>.caseProperty);
            }
            set
            {
                SetValue(FlowSwitchLink<T>.caseProperty, value);
            }
        }
        
        [BrowsableAttribute(false)]
        public T Case
        {
            get
            {
                return (T)GetValue(FlowSwitchLink<T>.caseProperty);
            }
            set
            {
                SetValue(FlowSwitchLink<T>.caseProperty, value);
            }
        }
 
        DependencyProperty CaseProperty
        {
            get
            {
                return caseProperty;
            }
        }
 
        DependencyProperty IsDefaultCaseProperty
        {
            get
            {
                return isDefaultCaseProperty;
            }
        }
 
        [Browsable(false)]
        public Type GenericType
        {
            get
            {
                return typeof(T);
            }
        }
 
        bool ContainsKey(object key)
        {
            return this.parentFlowSwitch.Cases.ContainsKey((T)key);
        }
 
        void OnIsDefaultPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            bool isUndoRedoInProgress = this.IsUndoRedoInProgress();
 
            if (!this.internalDefaultCaseChange && !isUndoRedoInProgress)
            {
                bool value = (bool)e.NewValue;
                bool oldValue = (bool)e.OldValue;
 
                if (value)
                {
                    if (object.Equals(this.flowSwitchModelItem.Properties["Default"].Value, null))
                    {
                        using (EditingScope es = (EditingScope)this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchCaseRenameEditingScopeDesc))
                        {
                            ModelItem flowNodeMI = GenericFlowSwitchHelper.GetCaseModelItem(this.flowSwitchModelItem.Properties["Cases"], this.CaseObject);
                            GenericFlowSwitchHelper.RemoveCase(this.flowSwitchModelItem.Properties["Cases"], this.CaseObject);
                            this.flowSwitchModelItem.Properties["Default"].SetValue(flowNodeMI);
                            this.UpdateViewState(this.CaseName + CaseViewStateKeyAppendString, DefaultConnectorViewStateKey);
                            this.internalChange = true;
                            es.Complete();
                        }
                    }
                    else
                    {
                        this.internalDefaultCaseChange = true;
                        this.IsDefaultCase = oldValue;
                        throw FxTrace.Exception.AsError(new InvalidOperationException(SR.DefaultCaseExists));
                    }
                }
                else
                {
                    if (oldValue)
                    {
                        using (EditingScope es = (EditingScope)this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchCaseRenameEditingScopeDesc))
                        {
                            ModelItem defaultCase = this.flowSwitchModelItem.Properties["Default"].Value;
                            object uniqueCase = null;
                            string errorMessage = string.Empty;
                            Type typeArgument = typeof(T);
                            if (GenericFlowSwitchHelper.CanBeGeneratedUniquely(typeArgument))
                            {
                                string caseName = GenericFlowSwitchHelper.GetCaseName(this.flowSwitchModelItem.Properties["Cases"], typeArgument, out errorMessage);
                                if (!string.IsNullOrEmpty(errorMessage))
                                {
                                    this.internalDefaultCaseChange = true;
                                    this.IsDefaultCase = oldValue;
                                    throw FxTrace.Exception.AsError(new InvalidOperationException(errorMessage));
                                }
                                uniqueCase = GenericFlowSwitchHelper.GetObject(caseName, typeArgument);
 
                            }
                            else
                            {
                                FlowSwitchCaseEditorDialog editor = new FlowSwitchCaseEditorDialog(this.flowSwitchModelItem, ((WorkflowViewElement)this.flowSwitchModelItem.View).Context, this.flowSwitchModelItem.View, SR.ChangeCaseValue, this.flowSwitchModelItem.ItemType.GetGenericArguments()[0]);
                                editor.WindowSizeToContent = SizeToContent.WidthAndHeight;
 
                                if (!editor.ShowOkCancel())
                                {
                                    this.internalDefaultCaseChange = true;
                                    this.IsDefaultCase = oldValue;
                                    return;
                                }
                                uniqueCase = editor.Case;
                                if (GenericFlowSwitchHelper.ContainsCaseKey(this.flowSwitchModelItem.Properties["Cases"], uniqueCase))
                                {
                                    this.internalDefaultCaseChange = true;
                                    this.IsDefaultCase = oldValue;
                                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidFlowSwitchCaseMessage));
                                }
                            }
 
                            this.flowSwitchModelItem.Properties["Default"].SetValue(null);
                            this.flowSwitchModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].SetValue(FlowSwitchLabelFeature.DefaultCaseDisplayNameDefaultValue);
                            
                            this.internalChange = true;
                            if (typeof(string) != typeof(T))
                            {
                                this.ModelItem.Properties["Case"].SetValue(uniqueCase);
                                GenericFlowSwitchHelper.AddCase(this.flowSwitchModelItem.Properties["Cases"], uniqueCase, defaultCase.GetCurrentValue());
                            }
                            else
                            {
                                this.ModelItem.Properties["Case"].SetValue(uniqueCase);
                                GenericFlowSwitchHelper.AddCase(this.flowSwitchModelItem.Properties["Cases"], uniqueCase, defaultCase.GetCurrentValue());
                            }
                            this.UpdateViewState(DefaultConnectorViewStateKey, GenericFlowSwitchHelper.GetString(uniqueCase, typeof(T)) + CaseViewStateKeyAppendString);
                            es.Complete();
                            this.internalChange = false;
                        }
                        this.internalDefaultCaseChange = false;
                    }
                }
            }
            this.internalDefaultCaseChange = false;
        }
 
        protected bool IsUndoRedoInProgress()
        {
            bool isUndoRedoInProgress;
            WorkflowViewElement designer = (WorkflowViewElement)this.flowSwitchModelItem.View;
            if (designer == null)
            {
                isUndoRedoInProgress = false;
            }
            else
            {
                isUndoRedoInProgress = designer.Context.Services.GetService<UndoEngine>().IsUndoRedoInProgress;
            }
            return isUndoRedoInProgress;
        }
 
        void OnCasePropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            bool isUndoRedoInProgress = this.IsUndoRedoInProgress();
 
            if (!this.internalChange && !isUndoRedoInProgress)
            {
                T oldValue = (T)e.OldValue;
                T newValue = (T)e.NewValue;
 
                if (newValue is string && newValue != null)
                {
                    newValue = (T)((object)((string)((object)newValue)).Trim());
                }
 
                string oldViewStateKey = string.Empty;
                if (!this.ContainsKey(newValue))
                {
                    using (EditingScope es = (EditingScope)this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchCaseRenameEditingScopeDesc))
                    {
                        ModelItem flowElementMI = null;
 
                        flowElementMI = GenericFlowSwitchHelper.GetCaseModelItem(this.flowSwitchModelItem.Properties["Cases"], oldValue);
                        GenericFlowSwitchHelper.RemoveCase(this.flowSwitchModelItem.Properties["Cases"], oldValue);
                        oldViewStateKey = GenericFlowSwitchHelper.GetString(oldValue, typeof(T)) + CaseViewStateKeyAppendString;
                        //Add the new value
                        GenericFlowSwitchHelper.AddCase(this.flowSwitchModelItem.Properties["Cases"], newValue, flowElementMI.GetCurrentValue());
                        //Update the viewstate for the flowswitch.
                        this.UpdateViewState(oldViewStateKey, GenericFlowSwitchHelper.GetString(newValue, typeof(T)) + CaseViewStateKeyAppendString);
                        //Making sure the value for Case is always trimmed.
                        this.internalChange = true;
                        this.ModelItem.Properties["Case"].SetValue(newValue);
                        es.Complete();
                    }
                }
                else
                {
                    this.internalChange = true;
                    this.CaseObject = oldValue;
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidFlowSwitchCaseMessage));
                }
            }
            this.internalChange = false;
        }
 
        void UpdateViewState(string oldValue, string newValue)
        {
            EditingContext context = this.flowSwitchModelItem.GetEditingContext();
            ViewStateService viewStateService = (ViewStateService)context.Services.GetService(typeof(ViewStateService));
            if (viewStateService != null)
            {
                object viewState = viewStateService.RetrieveViewState(this.flowSwitchModelItem, oldValue);
                if (viewState != null)
                {
                    viewStateService.StoreViewStateWithUndo(this.flowSwitchModelItem, oldValue, null);
                    viewStateService.StoreViewStateWithUndo(this.flowSwitchModelItem, newValue, viewState);
                }
            }
        }
 
        static void OnCasePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            FlowSwitchLink<T> link = (FlowSwitchLink<T>)dependencyObject;
            link.OnCasePropertyChanged(e);
        }
 
        static void OnIsDefaultCasePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            FlowSwitchLink<T> link = (FlowSwitchLink<T>)dependencyObject;
            link.OnIsDefaultPropertyChanged(e);
        }
 
        public virtual MultiBinding CreateConnectorLabelTextBinding()
        {
            return new MultiBinding
            {
                Converter = new FlowSwitchLinkMultiValueConverter(),
                ConverterParameter = this.CaseProperty.PropertyType,
                Bindings = 
                {
                    new Binding { Source = this, Mode = BindingMode.OneWay, Path = new PropertyPath(this.CaseProperty) },
                    new Binding { Source = this, Mode = BindingMode.OneWay, Path = new PropertyPath(this.IsDefaultCaseProperty) },
                },
            };
        }
    }
 
    class FlowSwitchDefaultLink<T> : FlowSwitchLink<T>, IFlowSwitchDefaultLink
    {
        static DependencyProperty defaultCaseDisplayNameProperty = DependencyProperty.Register(FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName, typeof(string), typeof(FlowSwitchDefaultLink<T>), new FrameworkPropertyMetadata(new PropertyChangedCallback(FlowSwitchDefaultLink<T>.OnDefaultCaseDisplayNamePropertyChanged)));
 
        public FlowSwitchDefaultLink(ModelItem flowSwitchMI, T caseValue, bool isDefault)
            : base(flowSwitchMI, caseValue, isDefault)
        {
            this.internalChange = true;
            this.DefaultCaseDisplayName = (string)this.flowSwitchModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].Value.GetCurrentValue();
            this.internalChange = false;
        }
 
        public string DefaultCaseDisplayName
        {
            get
            {
                return (string)GetValue(FlowSwitchDefaultLink<T>.defaultCaseDisplayNameProperty);
            }
            set
            {
                SetValue(FlowSwitchDefaultLink<T>.defaultCaseDisplayNameProperty, value);
            }
        }
 
        DependencyProperty DefaultCaseDisplayNameProperty
        {
            get
            {
                return defaultCaseDisplayNameProperty;
            }
        }
 
        void OnDefaultCaseDisplayNamePropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            bool isUndoRedoInProgress = this.IsUndoRedoInProgress();
            if (!this.internalChange && !isUndoRedoInProgress)
            {
                string newValue = (string)e.NewValue;
                this.internalChange = true;
                using (ModelEditingScope scope = this.flowSwitchModelItem.BeginEdit(SR.FlowSwitchDefaultCaseDisplayNameEditingScopeDesc))
                {
                    this.flowSwitchModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].SetValue(newValue);
                    scope.Complete();
                }
                this.internalChange = false;
            }
        }
 
        static void OnDefaultCaseDisplayNamePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            FlowSwitchDefaultLink<T> link = (FlowSwitchDefaultLink<T>)dependencyObject;
            link.OnDefaultCaseDisplayNamePropertyChanged(e);
        }
 
        public override MultiBinding CreateConnectorLabelTextBinding()
        {
            MultiBinding result = base.CreateConnectorLabelTextBinding();
            result.Bindings.Add(new Binding { Source = this, Mode = BindingMode.OneWay, Path = new PropertyPath(this.DefaultCaseDisplayNameProperty) });
            return result;
        }
    }
 
    class FlowSwitchCaseLink<T> : FlowSwitchLink<T>
    {
        public FlowSwitchCaseLink(ModelItem flowSwitchMI, T caseValue, bool isDefault)
            : base(flowSwitchMI, caseValue, isDefault)
        {
        }
 
        [BrowsableAttribute(true)]
        public new T Case
        {
            get { return base.Case; }
            set { base.Case = value; }
        }
    }
}