File: System\Activities\Core\Presentation\FlowSwitchDesigner.xaml.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.Activities.Presentation;
    using System.Activities.Presentation.Annotations;
    using System.Activities.Presentation.FreeFormEditing;
    using System.Activities.Presentation.Internal.PropertyEditing;
    using System.Activities.Presentation.Metadata;
    using System.Activities.Presentation.Model;
    using System.Activities.Presentation.PropertyEditing;
    using System.Activities.Presentation.View;
    using System.Activities.Presentation.View.OutlineView;
    using System.ComponentModel;
    using System.Runtime;
    using System.Windows;
    using System.Windows.Automation.Peers;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using Microsoft.Activities.Presentation;
 
    partial class FlowSwitchDesigner
    {
        public static readonly DependencyProperty ExpressionButtonVisibilityProperty =
            DependencyProperty.Register("ExpressionButtonVisibility", typeof(Visibility), typeof(FlowSwitchDesigner));
 
        public static readonly DependencyProperty ExpressionButtonColorProperty =
            DependencyProperty.Register("ExpressionButtonColor", typeof(Brush), typeof(FlowSwitchDesigner));
 
        static readonly DependencyProperty ShowAllConditionsProperty =
            DependencyProperty.Register("ShowAllConditions", typeof(bool), typeof(FlowSwitchDesigner),
            new UIPropertyMetadata(new PropertyChangedCallback(OnShowAllConditionsChanged)));
 
        bool isPinned;
        bool expressionShown = false;
 
        private AnnotationManager annotationManager;
 
        public FlowSwitchDesigner()
        {
            InitializeComponent();
            this.Loaded += (sender, e) =>
            {
                //UnRegistering because of 137896: Inside tab control multiple Loaded events happen without an Unloaded event.
                this.ModelItem.PropertyChanged -= OnModelItemPropertyChanged;
                this.ModelItem.PropertyChanged += OnModelItemPropertyChanged;
                OnModelItemPropertyChanged(this.ModelItem, new PropertyChangedEventArgs("Expression"));
 
                SetupBinding();
 
                if (this.Context.Services.GetService<DesignerConfigurationService>().TargetFrameworkName.IsLessThan45())
                {
                    this.displayNameTextBox.IsReadOnly = true;
                }
 
                this.annotationManager.Initialize();
            };
            this.Unloaded += (sender, e) =>
            {
                this.ModelItem.PropertyChanged -= OnModelItemPropertyChanged;
                this.annotationManager.Uninitialize();
            };
            this.MouseEnter += (sender, e) =>
            {
                Update();
            };
            this.MouseLeave += (sender, e) =>
            {
                Update();
            };
 
            this.InitializeAnnotation();
        }
 
        private void InitializeAnnotation()
        {
            this.annotationManager = new AnnotationManager(this);
            this.annotationManager.AnnotationVisualProvider = new FlowSwitchDesignerAnnotationVisualProvider(this);
        }
 
        void SetupBinding()
        {
            Binding showAllConditionsBinding = new Binding();
            showAllConditionsBinding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(FlowchartDesigner), 1);
            showAllConditionsBinding.Path = new PropertyPath(FlowchartDesigner.ShowAllConditionsProperty);
            showAllConditionsBinding.Mode = BindingMode.OneWay;
 
            BindingOperations.SetBinding(this, FlowSwitchDesigner.ShowAllConditionsProperty, showAllConditionsBinding);
        }
 
        public Visibility ExpressionButtonVisibility
        {
            get { return (Visibility)GetValue(ExpressionButtonVisibilityProperty); }
            set { SetValue(ExpressionButtonVisibilityProperty, value); }
        }
 
        public Brush ExpressionButtonColor
        {
            get { return (Brush)GetValue(ExpressionButtonColorProperty); }
            set { SetValue(ExpressionButtonColorProperty, value); }
        }
 
        public bool ExpressionShown
        {
            get { return this.expressionShown; }
        }
 
        public static void RegisterMetadata(AttributeTableBuilder builder)
        {
            Type type = typeof(System.Activities.Statements.FlowSwitch<>);
 
            builder.AddCustomAttributes(type, new DesignerAttribute(typeof(FlowSwitchDesigner)));
            builder.AddCustomAttributes(type, type.GetProperty("Default"), BrowsableAttribute.No);
            builder.AddCustomAttributes(type, new ActivityDesignerOptionsAttribute
            {
                AllowDrillIn = false,
                OutlineViewIconProvider = (modelItem) =>
                {
                    if (modelItem != null)
                    {
                        ResourceDictionary icons = EditorResources.GetIcons();
                        if (icons.Contains("FlowSwitchIcon") && icons["FlowSwitchIcon"] is DrawingBrush)
                        {
                            return (DrawingBrush)icons["FlowSwitchIcon"];
                        }
                    }
 
                    return null;
                }
            });
            builder.AddCustomAttributes(type, new FeatureAttribute(typeof(FlowSwitchLabelFeature)));
            builder.AddCustomAttributes(type, new FeatureAttribute(typeof(FlowSwitchDefaultLinkFeature)));
 
            builder.AddCustomAttributes(type, type.GetProperty("Cases"), new ShowPropertyInOutlineViewAttribute() { CurrentPropertyVisible = false, ChildNodePrefix = "Case : " });
            builder.AddCustomAttributes(type, type.GetProperty("Expression"), new HidePropertyInOutlineViewAttribute());
 
            Type flowSwitchLinkType = typeof(FlowSwitchCaseLink<>);
            builder.AddCustomAttributes(flowSwitchLinkType, "Case", PropertyValueEditor.CreateEditorAttribute(typeof(FlowSwitchLinkCasePropertyEditor)), new EditorReuseAttribute(false));
        }
 
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new FlowchartExpressionAutomationPeer(this, base.OnCreateAutomationPeer());
        }
 
        void OnExpressionButtonClicked(object sender, RoutedEventArgs e)
        {
            this.isPinned = !this.isPinned;
        }
 
        void OnModelItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Expression")
            {
                Update();
            }
            else if (e.PropertyName == "DefaultCaseDisplayName")
            {
                // To fix 218600 without losing PropertyGrid focus (Bug 210326), the only workaround is to
                // update the connector label manually, because FlowSwitchLink.ModelItem["DefaultCaseDisplayName"]
                // is a FakeModelPropertyImpl, and would not generate a Undo unit 
                // (FakeModelNotifyPropertyChange.GetInverse() returns null).
                // However, there is a known issue with PropertyGrid bound to a fake ModelItem.  The workaround is 
                // to shift the focus to the FlowchartDesigner IF the keyboard focus is on the connector when the user
                // calls Undo/Redo, to avoid the problem of PropertyGrid not refreshable.
                FlowchartDesigner flowchartDesigner = VisualTreeUtils.FindVisualAncestor<FlowchartDesigner>(this);
                Fx.Assert(null != flowchartDesigner, "flowchart designer cannot be null because FlowswitchDesigner must exist within the same visual tree ofthe parent Flowchart.");
 
                if (null != flowchartDesigner &&
                    null != this.ModelItem.Properties["Default"].Value &&
                    this.Context.Services.GetService<UndoEngine>().IsUndoRedoInProgress)
                {
                    // the designer is available
                    Connector connector = flowchartDesigner.GetLinkOnCanvas(this.ModelItem, this.ModelItem.Properties["Default"].Value, "Default");
                    Fx.Assert(null != connector, "Connector should not be null.");
                    ModelItem linkModelItem = FlowchartDesigner.GetLinkModelItem(connector);
                    Fx.Assert(linkModelItem is FakeModelItemImpl, "ModelItem of FlowSwitch link is fake.");
                    IFlowSwitchDefaultLink link = (IFlowSwitchDefaultLink)linkModelItem.GetCurrentValue();
                    string defaultDisplayName =
                        (string)this.ModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].Value.GetCurrentValue();
 
                    if (link.DefaultCaseDisplayName != defaultDisplayName)
                    {
                        // the purpose of re-setting the link value during Undo/Redo is to update the FlowSwitch label
                        using (ModelEditingScope scope = this.ModelItem.BeginEdit(SR.FlowSwitchDefaultCaseDisplayNameEditingScopeDesc))
                        {
                            linkModelItem.Properties[FlowSwitchLabelFeature.DefaultCaseDisplayNamePropertyName].SetValue(defaultDisplayName);
                            link.DefaultCaseDisplayName = defaultDisplayName;
                            scope.Complete();
                        }
 
                        if (Selection.IsSelection(linkModelItem))
                        {
                            // cause the connector to lose focus, because the PropertyGrid would not have focus.
                            // this scenario only happens if the user explicitly selects the FlowSwitch link after
                            // editing the DefaultDisplayName.  This behavior is only a workaround due to the fact
                            // that PropertyGrid does not receive update from change in a FakeModelPropertyImpl 
                            // (i.e. FlowSwitchLink).
                            Keyboard.ClearFocus();
                            Selection.SelectOnly(this.Context, this.ModelItem);
                            linkModelItem.Highlight();
                        }
                    }
                }
            }
        }
 
        void Update()
        {
            Activity expressionActivity = this.ModelItem.Properties["Expression"].ComputedValue as Activity;
            string expressionString = ExpressionHelper.GetExpressionString(expressionActivity, this.ModelItem);
            bool expressionSpecified = !string.IsNullOrEmpty(expressionString);
            if (!expressionSpecified)
            {
                this.isPinned = false;
            }
 
            this.ExpressionButtonVisibility = expressionSpecified ? Visibility.Visible : Visibility.Collapsed;
 
            if (this.isPinned)
            {
                this.ExpressionButtonColor = WorkflowDesignerColors.FlowchartExpressionButtonPressedBrush;
            }
            else if (this.IsMouseOver)
            {
                this.ExpressionButtonColor = WorkflowDesignerColors.FlowchartExpressionButtonMouseOverBrush;
            }
            else
            {
                this.ExpressionButtonColor = WorkflowDesignerColors.FlowchartExpressionButtonBrush;
            }
            expressionShown = false;
            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
            if (adornerLayer != null)
            {
                Adorner[] adorners = adornerLayer.GetAdorners(this);
                if (adorners != null)
                {
                    foreach (Adorner adorner in adorners)
                    {
                        if (adorner is FlowchartExpressionAdorner)
                        {
                            adornerLayer.Remove(adorner);
                        }
                    }
                }
                if ((this.IsMouseOver && expressionSpecified) || this.isPinned)
                {
                    expressionShown = true;
                    adornerLayer.Add(new FlowchartExpressionAdorner(this));
                }
            }
        }
 
        static void OnShowAllConditionsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != DependencyProperty.UnsetValue)
            {
                FlowSwitchDesigner designer = obj as FlowSwitchDesigner;
                designer.OnShowAllConditionsChanged((bool)e.NewValue);
            }
        }
 
        void OnShowAllConditionsChanged(bool isOpen)
        {
            this.isPinned = isOpen;
            Update();
        }
 
        protected internal override void OnEditAnnotation()
        {
            this.annotationManager.OnEditAnnotation();
        }
 
        private class FlowSwitchDesignerAnnotationVisualProvider : IAnnotationVisualProvider
        {
            private FlowSwitchDesigner designer;
            private IAnnotationIndicator indicator;
            private IFloatingAnnotation floatingAnnotation;
            private IDockedAnnotation dockedAnnotation;
 
            public FlowSwitchDesignerAnnotationVisualProvider(FlowSwitchDesigner designer)
            {
                this.designer = designer;
            }
 
            public IAnnotationIndicator GetAnnotationIndicator()
            {
                if (this.indicator == null)
                {
                    this.indicator = new UIElementToAnnotationIndicatorAdapter(this.designer.defaultAnnotationIndicator);
                }
 
                return this.indicator;
            }
 
            public IFloatingAnnotation GetFloatingAnnotation()
            {
                if (this.floatingAnnotation == null)
                {
                    this.floatingAnnotation = new FloatingAnnotationView();
                }
 
                return this.floatingAnnotation;
            }
 
            public IDockedAnnotation GetDockedAnnotation()
            {
                if (this.dockedAnnotation == null)
                {
                    DockedAnnotationView view = new DockedAnnotationView();
                    Binding binding = new Binding("ModelItem.AnnotationText");
                    view.SetBinding(DockedAnnotationView.AnnotationTextProperty, binding);
                    view.Visibility = Visibility.Collapsed;
                    Grid.SetRow(view, 0);
 
                    this.dockedAnnotation = view;
                    this.designer.rootGrid.Children.Insert(0, view);
                }
 
                return this.dockedAnnotation;
            }
        }
    }
}