File: cdf\src\NetFx40\Tools\System.Activities.Presentation\System\Activities\Presentation\View\VisualBasicEditor.xaml.cs
Project: ndp\System.Data.csproj (System.Data)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.Activities.Presentation.View
{
    using System.Activities.ExpressionParser;
    using System.Activities.Expressions;
    using System.Activities.Presentation.Expressions;
    using System.Activities.Presentation.Hosting;
    using System.Activities.Presentation.Internal.PropertyEditing;
    using System.Activities.Presentation.Model;
    using System.Activities.Presentation.Services;
    using System.Activities.Presentation.Validation;
    using System.Activities.Presentation.Xaml;
    using System.Activities.XamlIntegration;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Linq;
    using System.Runtime;
    using System.Runtime.Versioning;
    using System.Threading;
    using System.Windows;
    using System.Windows.Automation;
    using System.Windows.Automation.Peers;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Threading;
    using Microsoft.VisualBasic.Activities;
    using Microsoft.Activities.Presentation;
 
    //This control is used for expression editing in activity designers.
    //It uses the Activity<T> TypeConverter to convert between a Activity<T> and its string representation.
    //It defines 3 dependency properties - OwnerActivity, ExpressionModelItem and ExpressionType.
    //ActivityModelItem is used to create the parser context required by the TypeConverter.
    //ExpressionType is the type of the expression associated with this text box. This is required by the TypeConverter.
 
    internal sealed partial class VisualBasicEditor : TextualExpressionEditor
    {
        private static readonly Type VariableValueType = typeof(VariableValue<>);
        private static readonly Type VariableReferenceType = typeof(VariableReference<>);
        private static readonly Type LiteralType = typeof(Literal<>);
        private static readonly Type VisualBasicValueType = typeof(VisualBasicValue<>);
        private static readonly Type VisualBasicReferenceType = typeof(VisualBasicReference<>);
 
        internal static string ExpressionLanguageName = (new VisualBasicValue<string>() as ITextExpression).Language;
 
        internal static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(VisualBasicEditor),
                new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnTextChanged), new CoerceValueCallback(OnTextCoerceValue)));
 
        internal static readonly DependencyProperty ValidationStateProperty = DependencyProperty.Register("ValidationState", typeof(ValidationState), typeof(VisualBasicEditor),
                new FrameworkPropertyMetadata(ValidationState.Valid));
 
        internal static readonly DependencyProperty EditingStateProperty = DependencyProperty.Register("EditingState", typeof(EditingState), typeof(VisualBasicEditor),
                new PropertyMetadata(EditingState.Idle));
 
        internal static readonly DependencyProperty HasValidationErrorProperty = DependencyProperty.Register("HasValidationError", typeof(bool), typeof(VisualBasicEditor),
                new PropertyMetadata(false));
 
        internal static readonly DependencyProperty ValidationErrorMessageProperty = DependencyProperty.Register("ValidationErrorMessage", typeof(string), typeof(VisualBasicEditor),
                new PropertyMetadata(null));
 
        internal static readonly DependencyProperty ExpressionTextProperty = DependencyProperty.Register("ExpressionText", typeof(string), typeof(VisualBasicEditor),
                new PropertyMetadata(null));
 
        [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
        public static readonly ICommand CompleteWordCommand = new RoutedCommand("CompleteWordCommand", typeof(VisualBasicEditor));
        [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
        public static readonly ICommand GlobalIntellisenseCommand = new RoutedCommand("GlobalIntellisenseCommand", typeof(VisualBasicEditor));
        [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
        public static readonly ICommand ParameterInfoCommand = new RoutedCommand("ParameterInfoCommand", typeof(VisualBasicEditor));
        [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
        public static readonly ICommand QuickInfoCommand = new RoutedCommand("QuickInfoCommand", typeof(VisualBasicEditor));
        [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
        public static readonly ICommand IncreaseFilterLevelCommand = new RoutedCommand("IncreaseFilterLevelCommand", typeof(VisualBasicEditor));
        [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
        public static readonly ICommand DecreaseFilterLevelCommand = new RoutedCommand("DecreaseFilterLevelCommand", typeof(VisualBasicEditor));
 
        bool internalModelItemChange = false;
        string previousText = null;
        ModelProperty expressionModelProperty;
        TypeConverter expressionConverter;
        bool initialized = false;
        bool isEditorLoaded = false;
 
        IExpressionEditorService expressionEditorService;
        IExpressionEditorInstance expressionEditorInstance;
        TextBox editingTextBox;
 
        Control hostControl;
        string editorName;
        double blockHeight = double.NaN;
        double blockWidth = double.NaN;
        bool isExpressionLoaded = false;
        bool isBeginEditPending = false;
 
        DesignerPerfEventProvider perfProvider;
        ModelItem boundedExpression = null;
        BackgroundWorker validator = null;
        const int ValidationWaitTime = 800;
 
        PropertyChangedEventHandler onExpressionModelItemChangedHandler;
 
        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.InitializeReferenceTypeStaticFieldsInline,
            Justification = "This is recommended way by WPF to override metadata of DependencyProperty in derived class")]
        static VisualBasicEditor()
        {
            ExpressionActivityEditor.HintTextProperty.OverrideMetadata(typeof(VisualBasicEditor), new FrameworkPropertyMetadata(SR.ExpressionDefaultText));
        }
 
        public VisualBasicEditor()
        {
            InitializeComponent();
 
            this.MinHeight = this.FontSize + 4; /* 4 pixels for border*/
 
            this.editorName = null;
 
            this.ContentTemplate = (DataTemplate)FindResource("textblock");
            this.Loaded += this.OnExpressionTextBoxLoaded;
            this.Unloaded += this.OnExpressionTextBoxUnloaded;
        }
 
        PropertyChangedEventHandler OnExpressionModelItemChanged
        {
            get
            {
                if (this.onExpressionModelItemChangedHandler == null)
                {
                    this.onExpressionModelItemChangedHandler = new PropertyChangedEventHandler(this.expressionModelItem_PropertyChanged);
                }
 
                return this.onExpressionModelItemChangedHandler;
            }
        }
 
        protected override void OnContextMenuOpening(ContextMenuEventArgs e)
        {
            e.Handled = true;
        }
 
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            switch (e.Property.Name)
            {
                case "HintText":
                    this.OnHintTextChanged(e);
                    break;
                case "Expression":
                    this.OnExpressionChanged(e);
                    break;
                case "ExpressionType":
                    this.OnExpressionTypeChanged(e);
                    break;
                case "OwnerActivity":
                    this.OnOwnerModelItemChanged(e);
                    break;
                case "UseLocationExpression":
                    this.OnUseLocationExpressionChanged(e);
                    break;
                case "PathToArgument":
                    this.OnPathToArgumentChanged(e);
                    break;
                case "MaxLines":
                case "MinLines":
                    this.OnLinesChanged(e);
                    break;
                case "AcceptsReturn":
                    this.OnAcceptsReturnChanged(e);
                    break;
                case "AcceptsTab":
                    this.OnAcceptsTabChanged(e);
                    break;
                case "IsIndependentExpressionProperty":
                    this.OnIsIndependentExpressionChanged();
                    break;
            }
            base.OnPropertyChanged(e);
        }
 
        protected override void OnPreviewMouseRightButtonDown(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseRightButtonDown(e);
            e.Handled = true;
        }
 
        static object OnTextCoerceValue(DependencyObject dp, object value)
        {
            string tempText = value as string;
            VisualBasicEditor etb = dp as VisualBasicEditor;
            if (etb != null)
            {
                if (tempText != null)
                {
                    tempText = tempText.Trim();
                }
            }
            return tempText;
        }
 
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new VisualBasicEditorAutomationPeer(this);
        }
 
        protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
        {
            base.OnLostKeyboardFocus(e);
 
            if (this.expressionEditorInstance != null &&
            (this.expressionEditorInstance.HasAggregateFocus ||
             (this.hostControl != null && this.hostControl.IsFocused)))
            {
                return;
            }
 
            DoLostFocus();
        }
 
        private void DoLostFocus()
        {
            KillValidator();
 
            ValidateExpression(this);
 
            if (this.Context != null)
            {   // Unselect if this is the currently selected one.
                ExpressionSelection current = this.Context.Items.GetValue<ExpressionSelection>();
                if (current != null && current.ModelItem == this.Expression)
                {
                    ExpressionSelection emptySelection = new ExpressionSelection(null);
                    this.Context.Items.SetValue(emptySelection);
                }
            }
 
            // Generate and validate the expression.
            // Get the text from the snapshot and set it to the Text property
            if (this.expressionEditorInstance != null)
            {
                this.expressionEditorInstance.ClearSelection();
            }
 
            bool committed = false;
            if (!this.ExplicitCommit)
            {
                //commit change and let the commit change code do the revert
                committed = Commit(false);
 
                //reset the error icon if we didn't get to set it in the commit
                if (!committed || this.IsIndependentExpression)
                {
                    this.EditingState = EditingState.Idle;
                    // Switch the control back to a textbox -
                    // but give it the text from the editor (textbox should be bound to the Text property, so should
                    // automatically be filled with the correct text, from when we set the Text property earlier)
                    if (!this.ContentTemplate.Equals((DataTemplate)FindResource("textblock")))
                    {
                        this.ContentTemplate = (DataTemplate)FindResource("textblock");
                    }
                }
            }
 
            //raise EditorLostLogical focus - in case when some clients need to do explicit commit
            this.RaiseEvent(new RoutedEventArgs(ExpressionTextBox.EditorLostLogicalFocusEvent, this));
        }
 
        private void KillValidator()
        {
            if (validator != null)
            {
                this.validator.CancelAsync();
                this.validator.Dispose();
                this.validator = null;
            }
        }
 
        internal static bool ShouldGenerateExpression(string oldText, string newText)
        {
            return newText != null && !string.Equals(newText, oldText) && !(oldText == null && newText.Equals(string.Empty));
        }
 
        public override bool Commit(bool isExplicitCommit)
        {
            bool committed = false;
            //only generate and validate the expression when when we don't require explicit commit change
            //or when the commit is explicit
            if (!this.ExplicitCommit || isExplicitCommit)
            {
                // Generate and validate the expression.
                // Get the text from the snapshot and set it to the Text property
                this.previousText = null;
                // In VS
                if (this.expressionEditorInstance != null)
                {
                    this.previousText = this.Text;
                    this.Text = this.expressionEditorInstance.GetCommittedText();
                }
                // In rehost
                else
                {
                    if (this.Expression != null)
                    {
                        Activity expression = this.Expression.GetCurrentValue() as Activity;
                        // if expression is null, GetExpressionString will return null                           
                        this.previousText = ExpressionHelper.GetExpressionString(expression, this.OwnerActivity);
                    }
                    else
                    {
                        this.previousText = null;
                    }
 
                    if (this.editingTextBox != null)
                    {
                        this.editingTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
                    }
                }
 
                // If the Text is null, or equal to the previous value, or changed from null to empty, don't bother generating the expression
                // We still need to generate the expression when it is changed from other value to EMPTY however - otherwise
                // the case where you had an expression (valid or invalid), then deleted the whole thing will not be evaluated.
                if (ShouldGenerateExpression(this.previousText, this.Text))
                {
                    GenerateExpression();
                    committed = true;
                }
            }
            if (!this.ContentTemplate.Equals((DataTemplate)FindResource("textblock")))
            {
                this.ContentTemplate = (DataTemplate)FindResource("textblock");
            }
            return committed;
        }
 
        protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseLeftButtonDown(e);
 
            if (this.Context != null)
            {
                ExpressionSelection expressionSelection = new ExpressionSelection(this.Expression);
                this.Context.Items.SetValue(expressionSelection);
            }
        }
 
        public override void BeginEdit()
        {
            //am i loaded? is current template a textblock?
            if (this.isExpressionLoaded || null == this.Expression)
            {
                this.isBeginEditPending = false;
                this.IsReadOnly = false;
                if (this.IsLoaded && this.ContentTemplate.Equals(this.FindResource("textblock")))
                {
                    //get control's content presenter
                    ContentPresenter presenter = VisualTreeUtils.GetTemplateChild<ContentPresenter>(this);
                    if (null != presenter)
                    {
                        //and look for the loaded textblock
                        TextBlock tb = (TextBlock)this.ContentTemplate.FindName("expresionTextBlock", presenter);
                        if (null != tb)
                        {
                            //now - give focus to the textblock - it will trigger OnGotTextBlockFocus event, which eventually
                            //swithc ETB into expression editing mode.
                            tb.Focus();
                        }
                    }
                }
            }
            else
            {
                this.isBeginEditPending = true;
            }
        }
 
        internal bool HasAggregateFocus()
        {
            bool result = false;
 
            if (this.IsLoaded)
            {
                if (this.expressionEditorInstance != null)
                {
                    result = (this.hostControl != null && this.hostControl.IsFocused) || this.expressionEditorInstance.HasAggregateFocus;
                }
                else
                {
                    result = !this.IsKeyboardFocused && this.IsKeyboardFocusWithin;
                }
            }
 
            return result;
        }
 
        void OnTextBlockMouseLeftButtonDown(object sender, RoutedEventArgs e)
        {
            if (!this.IsReadOnly)
            {
                TextBlock textBlock = sender as TextBlock;
                if (textBlock != null)
                {
                    Keyboard.Focus(textBlock);
                    e.Handled = true;
                }
            }
        }
 
        void OnGotTextBlockFocus(object sender, RoutedEventArgs e)
        {
            if (this.Context == null)
            {
                return;
            }
 
            DesignerView designerView = this.Context.Services.GetService<DesignerView>();
 
            if (!designerView.IsMultipleSelectionMode)
            {
                TextBlock textBlock = sender as TextBlock;
                bool isInReadOnlyMode = this.IsReadOnly;
                if (this.Context != null)
                {
                    ReadOnlyState readOnlyState = this.Context.Items.GetValue<ReadOnlyState>();
                    isInReadOnlyMode |= readOnlyState.IsReadOnly;
                }
                if (null != textBlock)
                {
                    this.blockHeight = textBlock.ActualHeight;
                    this.blockHeight = Math.Max(this.blockHeight, textBlock.MinHeight);
                    this.blockHeight = Math.Min(this.blockHeight, textBlock.MaxHeight);
                    this.blockWidth = textBlock.ActualWidth;
                    this.blockWidth = Math.Max(this.blockWidth, textBlock.MinWidth);
                    this.blockWidth = Math.Min(this.blockWidth, textBlock.MaxWidth);
 
                    // If it's already an editor, don't need to switch it/reload it (don't create another editor/grid if we don't need to)
                    // Also don't create editor when we are in read only mode
                    if (this.ContentTemplate.Equals((DataTemplate)FindResource("textblock")) && !isInReadOnlyMode)
                    {
                        if (this.Context != null)
                        {
                            // Get the ExpressionEditorService
                            this.expressionEditorService = this.Context.Services.GetService<IExpressionEditorService>();
                        }
 
                        // If the service exists, use the editor template - else switch to the textbox template
                        if (this.expressionEditorService != null)
                        {
                            this.PerfProvider.WorkflowDesignerExpressionEditorLoadStart();
                            this.ContentTemplate = (DataTemplate)FindResource("editor");
                        }
                        else
                        {
                            this.ContentTemplate = (DataTemplate)FindResource("textbox");
                        }
                    }
                }
 
                if (!isInReadOnlyMode)
                {
                    //disable the error icon
                    this.StartValidator();
                    this.EditingState = EditingState.Editing;
                    e.Handled = true;
                }
            }
 
            // Adds or updates focused VisualBasicEditor to the session dictionary
            if (!LocalAppContextSwitches.UseLegacyAccessibilityFeatures && this.Context != null)
            {
                if (this.Context.Services.Contains<Dictionary<string, object>>())
                {
                    Dictionary<string, object> sessionObjects = this.Context.Services.GetService<Dictionary<string, object>>();
 
                    if (null != sessionObjects)
                    {
                        string key = "FocusedVisualBasicEditor";
                        if (!sessionObjects.ContainsKey(key))
                        {
                            sessionObjects.Add(key, this);
                        }
                        else
                        {
                            sessionObjects[key] = this;
                        }
                    }
                }
            }
        }
 
        void OnGotEditingFocus(object sender, RoutedEventArgs e)
        {
            //disable the error icon
            this.EditingState = EditingState.Editing;
            this.StartValidator();
        }
 
        // This method is called when the editor data template is loaded - when the editor data template
        // is loaded, create the editor session and the expression editor
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "CreateExpressionEditor is part of a public API. Propagating exceptions might lead to VS crash.")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
            Justification = "CreateExpressionEditor is part of a public API. Propagating exceptions might lead to VS crash.")]
        void OnEditorLoaded(object sender, RoutedEventArgs e)
        {
            if (!this.isEditorLoaded)
            {
                // If the service exists, create an expression editor and add it to the grid - else switch to the textbox data template
                if (this.expressionEditorService != null)
                {
                    Border border = (Border)sender;
                    // Get the references and variables in scope
                    AssemblyContextControlItem assemblies = (AssemblyContextControlItem)this.Context.Items.GetValue(typeof(AssemblyContextControlItem));
                    List<ModelItem> declaredVariables = VisualBasicEditor.GetVariablesInScope(this.OwnerActivity);
 
                    ImportedNamespaceContextItem importedNamespaces = this.Context.Items.GetValue<ImportedNamespaceContextItem>();
                    importedNamespaces.EnsureInitialized(this.Context);
                    //if the expression text is empty and the expression type is set, then we initialize the text to prompt text
                    if (String.Equals(this.ExpressionText, string.Empty, StringComparison.OrdinalIgnoreCase) && this.ExpressionType != null)
                    {
                        this.Text = TypeToPromptTextConverter.GetPromptText(this.ExpressionType);
                    }
 
                    //this is a hack
                    this.blockWidth = Math.Max(this.ActualWidth - 8, 0);  //8 is the margin
                    if (this.HasErrors)
                    {
                        this.blockWidth = Math.Max(this.blockWidth - 16, 0); //give 16 for error icon
                    }
                    try
                    {
                        if (this.ExpressionType != null)
                        {
                            this.expressionEditorInstance = this.expressionEditorService.CreateExpressionEditor(assemblies, importedNamespaces, declaredVariables, this.Text, this.ExpressionType, new Size(this.blockWidth, this.blockHeight));
                        }
                        else
                        {
                            this.expressionEditorInstance = this.expressionEditorService.CreateExpressionEditor(assemblies, importedNamespaces, declaredVariables, this.Text, new Size(this.blockWidth, this.blockHeight));
                        }
                    }
                    catch (Exception ex)
                    {
                        Trace.WriteLine(ex.Message);
                    }
 
                    if (this.expressionEditorInstance != null)
                    {
                        try
                        {
                            this.expressionEditorInstance.VerticalScrollBarVisibility = this.VerticalScrollBarVisibility;
                            this.expressionEditorInstance.HorizontalScrollBarVisibility = this.HorizontalScrollBarVisibility;
 
                            this.expressionEditorInstance.AcceptsReturn = this.AcceptsReturn;
                            this.expressionEditorInstance.AcceptsTab = this.AcceptsTab;
 
                            // Add the expression editor to the text panel, at column 1
                            this.hostControl = this.expressionEditorInstance.HostControl;
 
                            // Subscribe to this event to change scrollbar visibility on the fly for auto, and to resize the hostable editor
                            // as necessary
                            this.expressionEditorInstance.LostAggregateFocus += new EventHandler(OnEditorLostAggregateFocus);
                            this.expressionEditorInstance.Closing += new EventHandler(OnEditorClosing);
 
                            // Set up Hostable Editor properties
                            this.expressionEditorInstance.MinLines = this.MinLines;
                            this.expressionEditorInstance.MaxLines = this.MaxLines;
 
                            this.expressionEditorInstance.HostControl.Style = (Style)FindResource("editorStyle");
 
                            border.Child = this.hostControl;
                            this.expressionEditorInstance.Focus();
                        }
                        catch (KeyNotFoundException ex)
                        {
                            Debug.Fail("Unable to find editor with the following editor name: " + this.editorName, ex.Message);
                        }
                    }
                }
 
                if (this.expressionEditorInstance == null)
                {
                    this.ContentTemplate = (DataTemplate)FindResource("textbox");
                }
                this.PerfProvider.WorkflowDesignerExpressionEditorLoaded();
 
                this.isEditorLoaded = true;
            }
        }
 
        void OnEditorClosing(object sender, EventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                //these events are expected to be unregistered during lost focus event, but
                //we are unregistering them during unload just in case.  Ideally we want to
                //do this in the CloseExpressionEditor method
                this.expressionEditorInstance.LostAggregateFocus -= new EventHandler(OnEditorLostAggregateFocus);
 
                this.expressionEditorInstance.Closing -= new EventHandler(OnEditorClosing);
                this.expressionEditorInstance = null;
            }
            Border boarder = this.hostControl.Parent as Border;
            if (boarder != null)
            {
                boarder.Child = null;
            }
            this.hostControl = null;
            this.editorName = null;
 
        }
 
        void OnEditorLostAggregateFocus(object sender, EventArgs e)
        {
            this.DoLostFocus();
        }
 
        //void BindEditorProperties()
        //{
        //    this.hostControl.SetBinding(Control.ContextMenuProperty, "ContextMenu");
        //    this.hostControl.SetBinding(Control.FlowDirectionProperty, "FlowDirection");
        //    this.hostControl.SetBinding(Control.FontFamilyProperty, "FontFamily");
        //    this.hostControl.SetBinding(Control.FontSizeProperty, "FontSize");
        //    this.hostControl.SetBinding(Control.FontStretchProperty, "FontStretch");
        //    this.hostControl.SetBinding(Control.FontStyleProperty, "FontStyle");
        //    this.hostControl.SetBinding(Control.FontWeightProperty, "FontWeight");
        //    this.hostControl.SetBinding(Control.HeightProperty, "Height");
        //    this.hostControl.SetBinding(Control.LanguageProperty, "Language");
        //    this.hostControl.SetBinding(Control.SnapsToDevicePixelsProperty, "SnapsToDevicePixels");
        //}
 
        // This method is called when the editor data template is unloaded - when the editor data template
        // is unloaded, close the editor session and set the expression editor and editor session to null
        void OnEditorUnloaded(object sender, RoutedEventArgs e)
        {
            // Blank the editorSession and the expressionEditor so as not to use up memory
            // Destroy both as you can only ever spawn one editor per session
            if (this.expressionEditorInstance != null)
            {
                //if we are unloaded during editing, this means we got here by someone clicking breadcrumb, we should try to commit
                if (this.EditingState == EditingState.Editing)
                {
                    this.Commit(false);
                }
                this.expressionEditorInstance.Close();
            }
            else
            {
                this.editingTextBox = null;
            }
 
            this.isEditorLoaded = false;
        }
 
        // This method is to give focus and set the caret position when the TextBox DataTemplate is loaded
        void OnTextBoxLoaded(object sender, RoutedEventArgs e)
        {
            TextBox textbox = (TextBox)sender;
            this.editingTextBox = textbox;
            textbox.ContextMenu = null;
 
            //to workaround a but in the TextBox layout code
            Binding binding = new Binding();
            binding.Source = this;
            binding.Path = new PropertyPath(VisualBasicEditor.TextProperty);
            binding.Mode = BindingMode.TwoWay;
            binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
 
            textbox.SetBinding(TextBox.TextProperty, binding);
 
            // Set the cursor to correct text position
            int index = GetCharacterIndexFromPoint(textbox);
 
            textbox.SelectionStart = index;
            textbox.SelectionLength = 0;
 
            textbox.Focus();
        }
 
        // This method is to workaround the fact that textbox.GetCharacterIndexFromPoint returns the caret
        // to the left of the character... Thus you can never get the caret after the last character in the
        // expression string.
        int GetCharacterIndexFromPoint(TextBox textbox)
        {
            Point position = Mouse.GetPosition(textbox);
            int index = textbox.GetCharacterIndexFromPoint(position, false);
 
            if (index < 0)
            {
                // May have clicked outside the text area, get the index of nearest char
                index = textbox.GetCharacterIndexFromPoint(position, true);
                if (index < 0)
                {
                    index = 0;
                }
 
                // Adjust the cursor position if we clicked to the right of returned character
                Rect charRect = textbox.GetRectFromCharacterIndex(index, true);
                if (position.X > charRect.Left + charRect.Width / 2)
                {
                    index++;
                }
            }
 
            return index;
        }
 
        static void ValidateExpression(VisualBasicEditor etb)
        {
            string errorMessage;
            if (etb.DoValidation(new ExpressionValidationContext(etb), out errorMessage))
            {
                etb.UpdateValidationError(errorMessage);
            }
        }
 
        [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.ReviewUnusedParameters, Justification = "Existing code")]
        void OnLinesChanged(DependencyPropertyChangedEventArgs e)
        {
            if (this.MinLines > this.MaxLines)
            {
                this.MaxLines = this.MinLines;
            }
        }
 
        static void OnTextChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            VisualBasicEditor textBox = (VisualBasicEditor)dependencyObject;
 
            if (textBox.ExpressionEditorService != null && textBox.expressionEditorInstance != null)
            {
                textBox.expressionEditorInstance.Text = textBox.Text;
            }
 
        }
 
        void OnOwnerModelItemChanged(DependencyPropertyChangedEventArgs e)
        {
            this.InitializeContext(e);
            this.OnPathToArgumentChanged(this.PathToArgument);
        }
 
        public override IExpressionEditorService ExpressionEditorService
        {
            get { return this.expressionEditorService; }
        }
 
        internal string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
 
        internal string ExpressionText
        {
            get { return (string)GetValue(ExpressionTextProperty); }
            set { SetValue(ExpressionTextProperty, value); }
        }
 
        internal ValidationState ValidationState
        {
            get { return (ValidationState)GetValue(VisualBasicEditor.ValidationStateProperty); }
            set { SetValue(VisualBasicEditor.ValidationStateProperty, value); }
        }
 
        internal bool HasErrors
        {
            get
            {
                bool hasErrors = false;
                if (this.EditingState == EditingState.Idle
                    && !this.IsIndependentExpression)
                {
                    if (this.Expression != null && this.ValidationService != null && this.ValidationService.ValidationStateProperty != null)
                    {
                        ValidationState state = this.ValidationService.ValidationStateProperty.Getter(this.Expression);
                        hasErrors = state == ValidationState.Error;
                    }
                }
                else
                {
                    hasErrors = this.HasValidationError;
                }
                return hasErrors;
            }
        }
 
        internal string ErrorMessage
        {
            get
            {
                string errorMessage = string.Empty;
 
                if (this.EditingState == EditingState.Idle && !this.IsIndependentExpression)
                {
                    if (this.Expression != null && this.ValidationService != null && this.ValidationService.ValidationStateProperty != null)
                    {
                        errorMessage = this.ValidationService.ValidationMessageProperty.Getter(this.Expression);
                    }
                }
                else
                {
                    errorMessage = this.ValidationErrorMessage;
                }
                return errorMessage;
            }
        }
 
        internal EditingState EditingState
        {
            get { return (EditingState)GetValue(EditingStateProperty); }
            set { SetValue(EditingStateProperty, value); }
        }
 
        internal bool HasValidationError
        {
            get { return (bool)GetValue(HasValidationErrorProperty); }
            set { SetValue(HasValidationErrorProperty, value); }
        }
 
        internal string ValidationErrorMessage
        {
            get { return (string)GetValue(ValidationErrorMessageProperty); }
            set { SetValue(ValidationErrorMessageProperty, value); }
        }
 
        DesignerPerfEventProvider PerfProvider
        {
            get
            {
                if (this.perfProvider == null && this.Context != null)
                {
                    perfProvider = this.Context.Services.GetService<DesignerPerfEventProvider>();
                }
                return this.perfProvider;
            }
        }
 
        ValidationService ValidationService
        {
            get
            {
                if (this.Context != null)
                {
                    return this.Context.Services.GetService<ValidationService>();
                }
                else
                {
                    return null;
                }
            }
        }
 
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
            Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
        internal void GenerateExpression()
        {
            Activity valueExpression = null;
 
            // If the text is null we don't need to bother generating the expression (this would be the case the
            // first time you enter an ETB. We still need to generate the expression when it is EMPTY however - otherwise
            // the case where you had an expression (valid or invalid), then deleted the whole thing will not be evaluated.
            if (this.Text != null)
            {
                using (ModelEditingScope scope = this.OwnerActivity.BeginEdit(SR.PropertyChangeEditingScopeDescription))
                {
                    this.EditingState = EditingState.Validating;
                    // we set the expression to null
                    // a) when the expressionText is empty AND it's a reference expression or
                    // b) when the expressionText is empty AND the DefaultValue property is null
                    if (this.Text.Length == 0 &&
                        (this.UseLocationExpression || (this.DefaultValue == null)))
                    {
                        valueExpression = null;
                    }
                    else
                    {
                        if (this.Text.Length == 0)
                        {
                            this.Text = this.DefaultValue;
                        }
                        valueExpression = CreateVBExpression();
                    }
                    CreateExpressionModelItem(valueExpression);
                    scope.Complete();
                }
            }
        }
 
        void OnValidationCompleted(object sender, EventArgs e)
        {
            if (this.EditingState != EditingState.Editing)
            {
                if (this.Expression != null && this.ValidationService != null && this.ValidationService.ValidationStateProperty != null)
                {
                    this.ValidationState = this.ValidationService.ValidationStateProperty.Getter(this.Expression);
                }
 
                this.EditingState = EditingState.Idle;
            }
        }
 
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
            Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
        private void CreateExpressionModelItem(object valueExpression)
        {
            // try to wrap the droppedObject in  a ModelItem.
            ModelItem expressionModelItem = null;
            if (valueExpression != null)
            {
                ModelServiceImpl modelService = (ModelServiceImpl)this.Context.Services.GetService<ModelService>();
                expressionModelItem = modelService.WrapAsModelItem(valueExpression);
                expressionModelItem.PropertyChanged += this.OnExpressionModelItemChanged;
                this.boundedExpression = expressionModelItem;
            }
            try
            {
                this.internalModelItemChange = true;
                this.EditingState = EditingState.Validating;
                SetValue(ExpressionProperty, expressionModelItem);
            }
            catch (Exception err)
            {
                Trace.WriteLine(string.Format(CultureInfo.CurrentUICulture, "{0}\r\n{1}", err.Message, err.StackTrace));
                this.internalModelItemChange = false;
            }
        }
 
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
            Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
        private Activity CreateVBExpression()
        {
            Activity valueExpression = null;
            if (this.OwnerActivity != null)
            {
                ExpressionValidationContext validationContext = new ExpressionValidationContext(this);
 
                Type expReturnType = null;
                string newExpressionText = null;
                SourceExpressionException compileErrorMessages;
 
                try
                {
                    VisualBasicSettings settings = null;
                    valueExpression = CreateVBExpression(validationContext, out newExpressionText, out expReturnType, out compileErrorMessages, out settings);
 
                    if (settings != null)
                    {
                        Fx.Assert(this.Context != null, "editing context cannot be null");
                        //merge with import designer
                        foreach (VisualBasicImportReference reference in settings.ImportReferences)
                        {
                            ImportDesigner.AddImport(reference.Import, this.Context);
                        }
                    }
 
                    if (!string.IsNullOrEmpty(newExpressionText))
                    {
                        this.previousText = this.Text;
                        this.Text = newExpressionText;
                    }
                }
                catch (Exception err)
                {
                    //if the VisualBasicDesignerHelper were able to resolve the type we use that
                    if (expReturnType == null)
                    {
                        //if not we try to use the expression type
                        expReturnType = this.ExpressionType;
                    }
 
                    //if expression type is also null, the we use object
                    if (expReturnType == null)
                    {
                        expReturnType = typeof(object);
                    }
 
                    valueExpression = VisualBasicEditor.CreateExpressionFromString(expReturnType, this.Text, UseLocationExpression, validationContext.ParserContext);
 
                    Trace.WriteLine(string.Format(CultureInfo.CurrentUICulture, "{0}\r\n{1}", err.Message, err.StackTrace));
                }
                this.ExpressionText = this.Text;
            }
            else
            {
                // If the OwnerActivity is null, do not try to compile the expression otherwise VS will crash
                // Inform the user that OwnerActivity is null (i.e. there is a error in their code)
                Trace.WriteLine("ExpressionTextBox OwnerActivity is null.");
            }
            return valueExpression;
        }
 
        internal static ActivityWithResult CreateExpressionFromString(string expressionText, bool isLocation, Type type)
        {
            return VisualBasicEditor.CreateExpressionFromString(type, expressionText, isLocation, new ParserContext());
        }
 
        internal static ActivityWithResult CreateExpressionFromString(Type type, string expressionText, bool isLocation, ParserContext context)
        {
            ActivityWithResult newExpression;
 
            if (!isLocation)
            {
                newExpression = ExpressionHelper.TryCreateLiteral(type, expressionText, context);
 
                if (newExpression != null)
                {
                    return newExpression;
                }
            }
 
            Type targetExpressionType = null;
            if (isLocation)
            {
                targetExpressionType = typeof(VisualBasicReference<>).MakeGenericType(type);
            }
            else
            {
                targetExpressionType = typeof(VisualBasicValue<>).MakeGenericType(type);
            }
 
            //create new visual basic value and pass expression text into it
            newExpression = (ActivityWithResult)Activator.CreateInstance(targetExpressionType, expressionText);
            //targetExpressionType.GetProperty("Settings").SetValue(newExpression, settings, null);
            //this code below is never executed - it is placed here only to enable compilation support whenver VisualBasicValue constructor
            //changes its parameter list.
            if (null == newExpression)
            {
                //if this gives compilation error, please update CreateInstance parameter list above as well!
                newExpression = new VisualBasicValue<string>(expressionText);
            }
 
            return newExpression;
        }
 
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
            Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
        private static Activity CreateVBExpression(ExpressionValidationContext context, out string newExpressionText, out Type expReturnType, out SourceExpressionException compileErrorMessages, out VisualBasicSettings vbSettings)
        {
            expReturnType = null;
            newExpressionText = null;
            compileErrorMessages = null;
            vbSettings = null;
 
            //try easy way first - look if there is a type converter which supports conversion between expression type and string
            ActivityWithResult literal = null;
            try
            {
                if (!context.UseLocationExpression)
                {
                    literal = ExpressionHelper.TryCreateLiteral(context.ExpressionType, context.ExpressionText, context.ParserContext);
                }
 
                if (literal != null)
                {
                    //need to get new expression text - converter might have changed its format, and we want it to be up to date
                    IValueSerializableExpression serializableExpression = literal as IValueSerializableExpression;
                    Fx.Assert(serializableExpression != null, "the expression has to be a Literal<>, which should be IValueSerializableExpression");
                    if (serializableExpression.CanConvertToString(context.ParserContext))
                    {
                        bool shouldBeQuoted = typeof(string) == context.ExpressionType || typeof(Uri) == context.ExpressionType;
 
                        //whether string begins and ends with quotes '"'. also, if there are
                        //more quotes within than those begining and ending ones, do not bother with literal - assume this is an expression.
                        bool isQuotedString = shouldBeQuoted &&
                                context.ExpressionText.StartsWith("\"", StringComparison.CurrentCulture) &&
                                context.ExpressionText.EndsWith("\"", StringComparison.CurrentCulture) &&
                                context.ExpressionText.IndexOf("\"", 1, StringComparison.CurrentCulture) == context.ExpressionText.Length - 1;
                        var formatString = isQuotedString ? "\"{0}\"" : "{0}";
                        newExpressionText = string.Format(CultureInfo.InvariantCulture, formatString, serializableExpression.ConvertToString(context.ParserContext));
                    }
                }
            }
            //conversion failed - do nothing, let VB compiler take care of the expression
            catch
            {
            }
 
            Activity valueExpression = literal;
 
            if (null == valueExpression)
            {
                if (!context.UseLocationExpression)
                {
                    //Compile for validation.
                    valueExpression = VisualBasicDesignerHelper.CreatePrecompiledVisualBasicValue(context.ExpressionType, context.ExpressionText, context.ParserContext.Namespaces, context.ReferencedAssemblies, context.ParserContext, out expReturnType, out compileErrorMessages, out vbSettings);
                }
                else
                {
                    //Compile for validation.
                    valueExpression = VisualBasicDesignerHelper.CreatePrecompiledVisualBasicReference(context.ExpressionType, context.ExpressionText, context.ParserContext.Namespaces, context.ReferencedAssemblies, context.ParserContext, out expReturnType, out compileErrorMessages, out vbSettings);
                }
 
                ////It's possible the inferred type of expression is a dynamic type (e.g. delegate type), in this case it will cause serialization failure.
                ////To prevent this, we'll always convert the expression type to be object if the inferred type is in dynamic assembly and user doesn't specify any ExpressionType property
                if ((expReturnType.Assembly.IsDynamic) && (context.ExpressionType == null))
                {
                    ActivityWithResult originalExpression = valueExpression as ActivityWithResult;
                    ActivityWithResult morphedExpression;
                    if (ExpressionHelper.TryMorphExpression(originalExpression, ExpressionHelper.IsGenericLocationExpressionType(originalExpression), typeof(object), context.EditingContext, out morphedExpression))
                    {
                        valueExpression = morphedExpression;
                    }
                }
            }
 
            return valueExpression;
        }
 
        [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.ReviewUnusedParameters, Justification = "Existing code")]
        void OnExpressionTypeChanged(DependencyPropertyChangedEventArgs e)
        {
            //for independent expressions, when the type changes, we need to validate the expressions
            if (this.initialized
                && this.IsIndependentExpression
                && this.EditingState == EditingState.Idle)
            {
                ValidateExpression(this);
            }
        }
 
        [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.ReviewUnusedParameters, Justification = "Existing code")]
        void OnUseLocationExpressionChanged(DependencyPropertyChangedEventArgs e)
        {
            //for independent expressions, when the type changes, we need to validate the expressions
            if (this.initialized
                && this.IsIndependentExpression
                && this.EditingState == EditingState.Idle
                && this.OwnerActivity != null)
            {
                ValidateExpression(this);
            }
        }
 
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "The entered expression might be invalid and may throw on deserialization. Propagating exception might lead to VS crash")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
            Justification = "The entered expression might be invalid and may throw on deserialization. Propagating exception might lead to VS crash")]
        void OnExpressionChanged(DependencyPropertyChangedEventArgs e)
        {
            ModelItem oldExpression = e.OldValue as ModelItem;
            if (oldExpression != null)
            {
                oldExpression.PropertyChanged -= this.OnExpressionModelItemChanged;
            }
            ModelItem expression = e.NewValue as ModelItem;
            if (expression != null && expression != this.boundedExpression)
            {
                expression.PropertyChanged += this.OnExpressionModelItemChanged;
            }
 
            try
            {
                this.boundedExpression = expression;
 
                this.OnExpressionChanged();
            }
            catch (Exception err)
            {
                //if context is set - use error reporting
                if (null != this.Context)
                {
                    this.Context.Items.SetValue(new ErrorItem() { Message = err.Message, Details = err.ToString() });
                }
                //otherwise - fallback to message box
                else
                {
                    MessageBox.Show(err.ToString(), err.Message);
                }
            }
 
        }
 
        void expressionModelItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            ModelItem item = sender as ModelItem;
            if (item != null)
            {
                if (e.PropertyName.Equals("ExpressionText", StringComparison.Ordinal))
                {
                    this.OnExpressionChanged();
                }
            }
        }
 
        void OnPathToArgumentChanged(DependencyPropertyChangedEventArgs e)
        {
            this.OnPathToArgumentChanged((string)e.NewValue);
        }
 
        void OnIsIndependentExpressionChanged()
        {
            //if this is an independent expression, we need to initialize the validation error because validation service will not validate it
            if (this.initialized
                && this.IsIndependentExpression
                && this.EditingState == EditingState.Idle)
            {
                ValidateExpression(this);
            }
        }
 
        void UpdateValidationState()
        {
            if (this.Expression != null && this.ValidationService != null && this.ValidationService.ValidationStateProperty != null)
            {
                this.ValidationState = this.ValidationService.ValidationStateProperty.Getter(this.Expression);
            }
            else
            {
                this.ValidationState = ValidationState.Valid;
            }
        }
 
        //We need to react to OnExpressionChanged, since there might be multiple ExpressionTextBoxes(ETB) associated to a single Expression.
        //All the ETBs should be updated if the value in any of the ETBs is changed.
        void OnExpressionChanged()
        {
            if (this.HintText == SR.UnsupportedExpressionHintText)
            {
                this.HintText = SR.ExpressionDefaultText;
                this.InitializeHintText();
            }
 
            if (!this.internalModelItemChange)
            {
                if (this.Expression == null)
                {
                    //new expression is null - there is no text, no previous text, erros should be clear as well as error message
                    this.Text = string.Empty;
                    this.previousText = this.Text;
                    this.ExpressionText = null;
                    this.ValidationState = ValidationState.Valid;
                }
                else
                {
                    this.UpdateValidationState();
 
                    object expressionObject = this.Expression.GetCurrentValue();
                    ActivityWithResult expression = expressionObject as ActivityWithResult;
                    if (VisualBasicEditor.IsSupportedExpressionType(expression))
                    {
                        String expressionString = null;
                        //create parser context - do not pass ownerActivity - it might be null at this time
                        ParserContext context = new ParserContext();
                        expressionString = ExpressionHelper.GetExpressionString(expression, context);
 
                        this.Text = expressionString;
                        this.ExpressionText = expressionString;
                        this.previousText = this.Text;
                        this.IsSupportedExpression = true;
                    }
                    else
                    {
                        this.Text = string.Empty;
                        this.IsSupportedExpression = false;
                        this.HintText = SR.UnsupportedExpressionHintText;
                    }
 
                    this.isExpressionLoaded = true;
                    if (this.isBeginEditPending)
                    {
                        this.BeginEdit();
                    }
                }
            }
            internalModelItemChange = false;
        }
 
        private static bool IsSupportedExpressionType(object expressionObject)
        {
            ActivityWithResult expression = expressionObject as ActivityWithResult;
            bool isSupported = false;
            if (expression != null)
            {
                Type expressionType = expression.GetType();
                Type genericExpressionType = null;
                if (expressionType.IsGenericType)
                {
                    genericExpressionType = expressionType.GetGenericTypeDefinition();
                }
 
                if (genericExpressionType == VisualBasicValueType ||
                    genericExpressionType == VisualBasicReferenceType ||
                    genericExpressionType == VariableReferenceType ||
                    genericExpressionType == VariableValueType ||
                    (genericExpressionType == LiteralType && ExpressionHelper.CanTypeBeSerializedAsLiteral(expression.ResultType)))
                {
                    isSupported = true;
                }
            }
 
            return isSupported;
        }
 
        void OnPathToArgumentChanged(string pathAsString)
        {
            this.expressionModelProperty = null;
            this.expressionConverter = null;
            if (!string.IsNullOrEmpty(pathAsString) && null != this.OwnerActivity)
            {
                string[] path = pathAsString.Split('.');
                if (path.Length > 0)
                {
                    this.expressionModelProperty = this.OwnerActivity.Properties[path[0]];
                    for (int i = 1; i < path.Length; ++i)
                    {
                        if (null != this.expressionModelProperty && null != this.expressionModelProperty.Value)
                        {
                            this.expressionModelProperty = this.expressionModelProperty.Value.Properties[path[i]];
                        }
                        else
                        {
                            this.expressionModelProperty = null;
                            break;
                        }
                    }
                }
            }
            if (null != this.expressionModelProperty)
            {
                this.expressionConverter = ((ModelPropertyImpl)this.expressionModelProperty).PropertyDescriptor.Converter;
            }
            this.InitializeHintText();
        }
 
        void InitializeHintText()
        {
            DescriptionAttribute customHint = null;
            if (this.expressionModelProperty != null && this.expressionModelProperty.Attributes.Count != 0)
            {
                customHint = this.expressionModelProperty.Attributes
                    .OfType<DescriptionAttribute>()
                    .FirstOrDefault();
            }
            this.HintText = (null == customHint || string.IsNullOrEmpty(customHint.Description) ?
                (string.Equals(this.HintText, SR.ExpressionDefaultText) ? SR.ExpressionDefaultText : this.HintText) : customHint.Description);
 
            string hint = null;
            if (this.HintText != null)
            {
                hint = this.HintText.Trim(new char[] { '<', '>' });
                this.SetValue(AutomationProperties.HelpTextProperty, hint);
            }
        }
 
        void InitializeContext(DependencyPropertyChangedEventArgs e)
        {
            if (e.OldValue != null)
            {
                // remove the OnValidationCompleted event handler on the old value
                ModelItem modelItem = (ModelItem)e.OldValue;
                if (modelItem != null)
                {
                    EditingContext context = modelItem.GetEditingContext();
                    ValidationService validationService = context.Services.GetService<ValidationService>();
                    if (validationService != null)
                    {
                        validationService.ValidationCompleted -= this.OnValidationCompleted;
                    }
                }
            }
 
 
            if (null != this.OwnerActivity)
            {
                if (this.ValidationService != null)
                {
                    this.ValidationService.ValidationCompleted += this.OnValidationCompleted;
                    this.UpdateValidationState();
                }
            }
        }
 
        #region Command Handlers
 
        public override bool CanCommit()
        {
            string currentText = this.Text;
            if (this.expressionEditorInstance != null)
            {
                currentText = this.expressionEditorInstance.Text ?? this.expressionEditorInstance.Text.Trim();
            }
            else if (this.editingTextBox != null)
            {
                currentText = this.editingTextBox.Text ?? this.editingTextBox.Text.Trim();
            }
 
            //we dont need to commit change if currentText and previousText is the same
            //null and empty should be considered equal in this context
 
            return !string.Equals(currentText, this.previousText) &&
                   !(string.IsNullOrEmpty(currentText) && string.IsNullOrEmpty(this.previousText));
        }
 
        void OnExpressionTextBoxLoaded(object sender, RoutedEventArgs e)
        {
            this.InitializeHintText();
 
            //if this is an independent expression, we need to initialize the validation error because validation service will not validate it
            if (this.IsIndependentExpression)
            {
                ValidateExpression(this);
            }
 
            this.initialized = true;
        }
 
        void OnExpressionTextBoxUnloaded(object sender, RoutedEventArgs e)
        {
            if (this.ValidationService != null)
            {
                this.ValidationService.ValidationCompleted -= this.OnValidationCompleted;
            }
            KillValidator();
 
            if (this.boundedExpression != null)
            {
                this.boundedExpression.PropertyChanged -= this.OnExpressionModelItemChanged;
            }
        }
 
        public override void OnCompleteWordCommandCanExecute(CanExecuteRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
 
                e.CanExecute = this.expressionEditorInstance.CanCompleteWord();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        public override void OnGlobalIntellisenseCommandCanExecute(CanExecuteRoutedEventArgs e)
        {
 
            if (this.expressionEditorInstance != null)
            {
                e.CanExecute = this.expressionEditorInstance.CanGlobalIntellisense();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        public override void OnParameterInfoCommandCanExecute(CanExecuteRoutedEventArgs e)
        {
 
            if (this.expressionEditorInstance != null)
            {
                e.CanExecute = this.expressionEditorInstance.CanParameterInfo();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        public override void OnQuickInfoCommandCanExecute(CanExecuteRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.CanExecute = this.expressionEditorInstance.CanQuickInfo();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        public override void OnIncreaseFilterLevelCommandCanExecute(CanExecuteRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.CanExecute = this.expressionEditorInstance.CanIncreaseFilterLevel();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        public override void OnDecreaseFilterLevelCommandCanExecute(CanExecuteRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.CanExecute = this.expressionEditorInstance.CanDecreaseFilterLevel();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        void OnCutCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.CanExecute = this.expressionEditorInstance.CanCut();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        public override void OnCompleteWordCommandExecute(ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.Handled = this.expressionEditorInstance.CompleteWord();
            }
            else
            {
                e.Handled = false;
            }
 
        }
 
        public override void OnGlobalIntellisenseCommandExecute(ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.Handled = this.expressionEditorInstance.GlobalIntellisense();
            }
            else
            {
                e.Handled = false;
            }
 
        }
 
        public override void OnParameterInfoCommandExecute(ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.Handled = this.expressionEditorInstance.ParameterInfo();
            }
            else
            {
                e.Handled = false;
            }
 
        }
 
        public override void OnQuickInfoCommandExecute(ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.Handled = this.expressionEditorInstance.QuickInfo();
            }
            else
            {
                e.Handled = false;
            }
 
        }
 
        public override void OnDecreaseFilterLevelCommandExecute(ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.Handled = this.expressionEditorInstance.DecreaseFilterLevel();
            }
            else
            {
                e.Handled = false;
            }
 
        }
 
        public override void OnIncreaseFilterLevelCommandExecute(ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.Handled = this.expressionEditorInstance.IncreaseFilterLevel();
            }
            else
            {
                e.Handled = false;
            }
 
        }
 
        void OnCutCommandExecute(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.Handled = this.expressionEditorInstance.Cut();
            }
            else
            {
                e.Handled = false;
            }
        }
 
        void OnCopyCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.CanExecute = this.expressionEditorInstance.CanCopy();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        void OnCopyCommandExecute(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.Handled = this.expressionEditorInstance.Copy();
            }
            else
            {
                e.Handled = false;
            }
        }
 
        void OnPasteCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.CanExecute = this.expressionEditorInstance.CanPaste();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        void OnPasteCommandExecute(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.Handled = this.expressionEditorInstance.Paste();
            }
            else
            {
                e.Handled = false;
            }
        }
 
        void OnUndoCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.CanExecute = this.expressionEditorInstance.CanUndo();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "Catch all execeptions to prevent crash.")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
            Justification = "Catch all execeptions to prevent crash.")]
        void OnUndoCommandExecute(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                try
                {
                    e.Handled = this.expressionEditorInstance.Undo();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else
            {
                e.Handled = false;
            }
        }
 
        void OnRedoCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.CanExecute = this.expressionEditorInstance.CanRedo();
                e.Handled = true;
            }
            else
            {
                e.Handled = false;
            }
        }
 
        void OnRedoCommandExecute(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                e.Handled = this.expressionEditorInstance.Redo();
            }
            else
            {
                e.Handled = false;
            }
        }
 
        void OnHelpExecute(object sender, ExecutedRoutedEventArgs e)
        {
            IIntegratedHelpService help = this.Context.Services.GetService<IIntegratedHelpService>();
            if (help != null)
            {
                help.ShowHelpFromKeyword(HelpKeywords.ExpressionEditorPage);
            }
            else
            {
                System.Diagnostics.Process.Start(SR.DefaultHelpUrl);
            }
        }
 
        #endregion
 
        void OnHintTextChanged(DependencyPropertyChangedEventArgs e)
        {
            if (!string.Equals(SR.ExpressionDefaultText, e.NewValue) && !string.Equals(e.OldValue, e.NewValue))
            {
                this.InitializeHintText();
            }
        }
 
        void OnAcceptsReturnChanged(DependencyPropertyChangedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                this.expressionEditorInstance.AcceptsReturn = (bool)e.NewValue;
            }
        }
 
        void OnAcceptsTabChanged(DependencyPropertyChangedEventArgs e)
        {
            if (this.expressionEditorInstance != null)
            {
                this.expressionEditorInstance.AcceptsTab = (bool)e.NewValue;
            }
        }
 
        void StartValidator()
        {
            if (this.validator == null)
            {
                this.validator = new BackgroundWorker();
                this.validator.WorkerReportsProgress = true;
                this.validator.WorkerSupportsCancellation = true;
 
                this.validator.DoWork += delegate(object obj, DoWorkEventArgs args)
                {
                    BackgroundWorker worker = obj as BackgroundWorker;
                    if (worker.CancellationPending)
                    {
                        args.Cancel = true;
                        return;
                    }
                    ExpressionValidationContext validationContext = args.Argument as ExpressionValidationContext;
                    if (validationContext != null)
                    {
                        string errorMessage;
                        if (DoValidation(validationContext, out errorMessage))
                        {
                            worker.ReportProgress(0, errorMessage);
                        }
 
                        //sleep
                        if (worker.CancellationPending)
                        {
                            args.Cancel = true;
                            return;
                        }
 
                        Thread.Sleep(ValidationWaitTime);
                        args.Result = validationContext;
                    }
 
                };
 
                this.validator.RunWorkerCompleted += delegate(object obj, RunWorkerCompletedEventArgs args)
                {
                    if (!args.Cancelled)
                    {
                        ExpressionValidationContext validationContext = args.Result as ExpressionValidationContext;
                        if (validationContext != null)
                        {
                            Dispatcher.BeginInvoke(new Action<ExpressionValidationContext>((target) =>
                            {
                                //validator could be null by the time we try to validate again or
                                //if it's already busy
                                if (this.validator != null && !this.validator.IsBusy)
                                {
                                    target.Update(this);
                                    this.validator.RunWorkerAsync(target);
                                }
                            }), validationContext);
                        }
                    }
                };
 
                this.validator.ProgressChanged += delegate(object obj, ProgressChangedEventArgs args)
                {
                    string error = args.UserState as string;
                    Dispatcher.BeginInvoke(new Action<string>(UpdateValidationError), error);
                };
 
                this.validator.RunWorkerAsync(new ExpressionValidationContext(this));
            }
        }
 
        //perform one validation synchronously
        //return value indicates whether errorMessage is updated.
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "The entered expression might be invalid and may throw on deserialization. Propagating exception might lead to VS crash")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
            Justification = "The entered expression might be invalid and may throw on deserialization. Propagating exception might lead to VS crash")]
        bool DoValidation(ExpressionValidationContext validationContext, out string errorMessage)
        {
            Fx.Assert(validationContext != null, "only work when context is not null");
            errorMessage = null;
 
            //validate
            //if the text is empty we clear the error message
            if (string.IsNullOrEmpty(validationContext.ExpressionText))
            {
                errorMessage = null;
                return true;
            }
            // if the expression text is different from the last time we run the validation we run the validation
            else if (!string.Equals(validationContext.ExpressionText, validationContext.ValidatedExpressionText))
            {
                Type expReturnType = null;
                string newExpressionText = null;
                SourceExpressionException compileErrorMessages = null;
                VisualBasicSettings settings = null;
                try
                {
                    CreateVBExpression(validationContext, out newExpressionText, out expReturnType, out compileErrorMessages, out settings);
                    if (compileErrorMessages != null)
                    {
                        errorMessage = compileErrorMessages.Message;
                    }
                }
                catch (Exception err)
                {
                    errorMessage = err.Message;
                }
 
                return true;
            }
 
            return false;
        }
 
        void UpdateValidationError(string errorMessage)
        {
            if (!string.IsNullOrEmpty(errorMessage))
            {
                //report error
                this.HasValidationError = true;
                this.ValidationErrorMessage = errorMessage;
            }
            else
            {
                this.HasValidationError = false;
                this.ValidationErrorMessage = null;
            }
        }
 
        private class ExpressionValidationContext
        {
            internal ParserContext ParserContext { get; set; }
            internal Type ExpressionType { get; set; }
            internal String ExpressionText { get; set; }
            internal EditingContext EditingContext { get; set; }
            internal String ValidatedExpressionText { get; set; }
            internal bool UseLocationExpression { get; set; }
 
            internal ExpressionValidationContext(VisualBasicEditor etb)
            {
                Update(etb);
            }
 
            internal void Update(VisualBasicEditor etb)
            {
                Fx.Assert(etb.OwnerActivity != null, "Owner Activity is null");
                this.EditingContext = etb.OwnerActivity.GetEditingContext();
 
                //setup ParserContext
                this.ParserContext = new ParserContext(etb.OwnerActivity)
                {
                    //callee is a ExpressionTextBox
                    Instance = etb,
                    //pass property descriptor belonging to epression's model property (if one exists)
                    PropertyDescriptor = (null != etb.expressionModelProperty ? ((ModelPropertyImpl)etb.expressionModelProperty).PropertyDescriptor : null),
                };
 
                this.ExpressionType = etb.ExpressionType;
                this.ValidatedExpressionText = this.ExpressionText;
                if (etb.expressionEditorInstance != null)
                {
                    this.ExpressionText = etb.expressionEditorInstance.Text;
                }
                else if (etb.editingTextBox != null)
                {
                    this.ExpressionText = etb.editingTextBox.Text;
                }
                else
                {
                    this.ExpressionText = etb.Text;
                }
                this.UseLocationExpression = etb.UseLocationExpression;
            }
 
            internal IEnumerable<string> ReferencedAssemblies
            {
                get
                {
                    Fx.Assert(this.EditingContext != null, "ModelItem.Context = null");
                    AssemblyContextControlItem assemblyContext = this.EditingContext.Items.GetValue<AssemblyContextControlItem>();
                    if (assemblyContext != null)
                    {
                        return assemblyContext.AllAssemblyNamesInContext;
                    }
                    return null;
                }
            }
        }
 
        private static List<ModelItem> GetVariablesInScopeWithShadowing(ModelItem ownerActivity, bool includeArguments)
        {
            List<ModelItem> variablesInScope = new List<ModelItem>();
            if (ownerActivity != null)
            {
                HashSet<string> variableNames = new HashSet<string>();
                ModelItem currentItem = ownerActivity;
                Func<ModelItem, bool> filterDelegate = new Func<ModelItem, bool>((variable) =>
                    {
                        string variableName = (string)variable.Properties["Name"].ComputedValue;
                        if (variableName == null)
                        {
                            return false;
                        }
                        else
                        {
                            return !variableNames.Contains(variableName.ToUpperInvariant());
                        }
                    });
 
                while (currentItem != null)
                {
                    List<ModelItem> variables = new List<ModelItem>();
                    ModelItemCollection variablesCollection = currentItem.GetVariableCollection();
                    if (variablesCollection != null)
                    {
                        variables.AddRange(variablesCollection);
                    }
                    variables.AddRange(currentItem.FindActivityDelegateArguments());
 
                    // For the variables defined at the same level, shadowing doesn't apply. If there're multiple variables defined at the same level
                    // have duplicate names when case is ignored, all of these variables should bee added as variables in scope and let validation reports
                    // ambiguous reference error. So that we need to scan all variables defined at the same level first and then add names to the HashSet.                                        
                    IEnumerable<ModelItem> filteredVariables = variables.Where<ModelItem>(filterDelegate);
                    variablesInScope.AddRange(filteredVariables);
                    foreach (ModelItem variable in filteredVariables)
                    {
                        variableNames.Add(((string)variable.Properties["Name"].ComputedValue).ToUpperInvariant());
                    }
 
                    currentItem = currentItem.Parent;
                }
 
                if (includeArguments)
                {
                    List<ModelItem> arguments = VisualBasicEditor.GetVariablesForArguments(ownerActivity.Root);
                    variablesInScope.AddRange(arguments.Where<ModelItem>(filterDelegate));
                }
            }
 
            return variablesInScope;
        }
 
        private static List<ModelItem> GetVariablesForArguments(ModelItem modelItem)
        {
            List<ModelItem> arguments = new List<ModelItem>();
            //if expression editor is loaded in the WF which is hosted within ActivityBuilder, there is a need to pickup defined arguments
            //and feed them as variables, so intellisense can include them
            if (null != modelItem && ActivityBuilderHelper.IsActivityBuilderType(modelItem))
            {
                ModelTreeManager treeManager = ((IModelTreeItem)modelItem).ModelTreeManager;
                //call ActivityBuilderHelper.GetVariables - it will create a collection of Variable - each variable corresponds to a specific argument
                arguments.AddRange(
                    ActivityBuilderHelper.GetVariables(modelItem)
                    //create a fake model item implementation - there is no need to store that model item anywhere in the model tree, it is required
                    //of the expression editor interface to pass instances of model items wrapping variables, rather than actual variables
                    .Select<Variable, ModelItem>(entry => new FakeModelItemImpl(treeManager, typeof(Variable), entry, null)));
            }
 
            return arguments;
        }
 
        internal static List<ModelItem> GetVariablesInScope(ModelItem ownerActivity)
        {
            List<ModelItem> declaredVariables = new List<ModelItem>();
            if (ownerActivity != null)
            {
                bool includeArguments = !(ownerActivity.GetCurrentValue() is ActivityBuilder);
                FrameworkName targetFramework = WorkflowDesigner.GetTargetFramework(ownerActivity.GetEditingContext());
                if ((targetFramework != null) && (targetFramework.IsLessThan45()))
                {
                    declaredVariables.AddRange(VariableHelper.FindVariablesInScope(ownerActivity));
                    declaredVariables.AddRange(VariableHelper.FindActivityDelegateArgumentsInScope(ownerActivity));
                    if (includeArguments)
                    {
                        declaredVariables.AddRange(VisualBasicEditor.GetVariablesForArguments(ownerActivity.Root));
                    }
                }
                else
                {
                    declaredVariables.AddRange(VisualBasicEditor.GetVariablesInScopeWithShadowing(ownerActivity, includeArguments));
                }
            }
 
            return declaredVariables;
        }
    }
 
    internal sealed class LineToHeightConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            double convertedValue = Double.NaN;
            bool isDefault = true;
 
            // Calculate the height for the textblock as ExpressionTextBox exposes lines properties,
            // and TextBlock doesn't have lines properties.
            FontFamily fontFamily = values.OfType<FontFamily>().FirstOrDefault();
            int lines = values.OfType<int>().FirstOrDefault();
            double[] doubleArray = values.OfType<double>().ToArray<double>();
 
            if (doubleArray.Length == 2)
            {
                double height = doubleArray[0]; // The first element of the array is going to be the height
                double fontSize = doubleArray[1]; // The seconed element of the array is going to be the fontSize
 
                // 0.0 is default for MinHeight, PositiveInfinity is default for MaxHeight
                if (string.Equals(parameter as string, "MinHeight"))
                {
                    isDefault = (height == 0.0);
                }
                else if (string.Equals(parameter as string, "MaxHeight"))
                {
                    isDefault = (double.IsPositiveInfinity(height));
                }
 
                // If the height value we are evaluating is default, use Lines for sizing...
                // If no heights (height or lines) have been explicitly specified, we would rather default the height
                // as if the Line was 1 - so use the line heights, rather than 0.0 and/or PositiveInfinity.
                if (isDefault)
                {
                    double lineHeight = fontSize * fontFamily.LineSpacing;
 
                    if (fontFamily != null)
                    {
                        convertedValue = lineHeight * (double)lines + 4;
                    }
                }
                else
                {
                    convertedValue = height;
                }
            }
 
            return convertedValue;
        }
 
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw FxTrace.Exception.AsError(new NotSupportedException());
        }
    }
 
    internal sealed class ValidationStateToErrorConverter : IMultiValueConverter
    {
 
        #region IMultiValueConverter Members
 
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            VisualBasicEditor etb = values[0] as VisualBasicEditor;
            if (values[0] == DependencyProperty.UnsetValue || etb == null)
            {
                return false;
            }
            return etb.HasErrors;
        }
 
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw FxTrace.Exception.AsError(new NotImplementedException());
        }
 
        #endregion
    }
 
    internal sealed class ValidationErrorMessageConverter : IMultiValueConverter
    {
        #region IMultiValueConverter Members
 
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            VisualBasicEditor etb = values[0] as VisualBasicEditor;
            if (values[0] == DependencyProperty.UnsetValue || etb == null)
            {
                return false;
            }
            return etb.ErrorMessage;
        }
 
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw FxTrace.Exception.AsError(new NotImplementedException());
        }
 
        #endregion
    }
 
    internal sealed class TypeToPromptTextConverter : IValueConverter
    {
        #region IValueConverter Members
 
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return TypeToPromptTextConverter.GetPromptText(value);
        }
 
        internal static string GetPromptText(object value)
        {
            Type expressionType = value as Type;
            if (value == DependencyProperty.UnsetValue || expressionType == null || !expressionType.IsValueType)
            {
                return "Nothing";
            }
            else
            {
                return Activator.CreateInstance(expressionType).ToString();
            }
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw FxTrace.Exception.AsError(new NotSupportedException());
        }
 
        #endregion
    }
 
 
    public enum EditingState
    {
        Editing,
        Validating,
        Idle
    }
}