[corlib] Update ValueTuple implementation
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / View / VisualBasicEditor.xaml.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.Activities.Presentation.View
6 {
7     using System.Activities.ExpressionParser;
8     using System.Activities.Expressions;
9     using System.Activities.Presentation.Expressions;
10     using System.Activities.Presentation.Hosting;
11     using System.Activities.Presentation.Internal.PropertyEditing;
12     using System.Activities.Presentation.Model;
13     using System.Activities.Presentation.Services;
14     using System.Activities.Presentation.Validation;
15     using System.Activities.Presentation.Xaml;
16     using System.Activities.XamlIntegration;
17     using System.Collections.Generic;
18     using System.ComponentModel;
19     using System.Diagnostics;
20     using System.Diagnostics.CodeAnalysis;
21     using System.Globalization;
22     using System.Linq;
23     using System.Runtime;
24     using System.Runtime.Versioning;
25     using System.Threading;
26     using System.Windows;
27     using System.Windows.Automation;
28     using System.Windows.Automation.Peers;
29     using System.Windows.Controls;
30     using System.Windows.Data;
31     using System.Windows.Input;
32     using System.Windows.Media;
33     using System.Windows.Threading;
34     using Microsoft.VisualBasic.Activities;
35     using Microsoft.Activities.Presentation;
36
37     //This control is used for expression editing in activity designers.
38     //It uses the Activity<T> TypeConverter to convert between a Activity<T> and its string representation.
39     //It defines 3 dependency properties - OwnerActivity, ExpressionModelItem and ExpressionType.
40     //ActivityModelItem is used to create the parser context required by the TypeConverter.
41     //ExpressionType is the type of the expression associated with this text box. This is required by the TypeConverter.
42
43     internal sealed partial class VisualBasicEditor : TextualExpressionEditor
44     {
45         private static readonly Type VariableValueType = typeof(VariableValue<>);
46         private static readonly Type VariableReferenceType = typeof(VariableReference<>);
47         private static readonly Type LiteralType = typeof(Literal<>);
48         private static readonly Type VisualBasicValueType = typeof(VisualBasicValue<>);
49         private static readonly Type VisualBasicReferenceType = typeof(VisualBasicReference<>);
50
51         internal static string ExpressionLanguageName = (new VisualBasicValue<string>() as ITextExpression).Language;
52
53         internal static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(VisualBasicEditor),
54                 new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnTextChanged), new CoerceValueCallback(OnTextCoerceValue)));
55
56         internal static readonly DependencyProperty ValidationStateProperty = DependencyProperty.Register("ValidationState", typeof(ValidationState), typeof(VisualBasicEditor),
57                 new FrameworkPropertyMetadata(ValidationState.Valid));
58
59         internal static readonly DependencyProperty EditingStateProperty = DependencyProperty.Register("EditingState", typeof(EditingState), typeof(VisualBasicEditor),
60                 new PropertyMetadata(EditingState.Idle));
61
62         internal static readonly DependencyProperty HasValidationErrorProperty = DependencyProperty.Register("HasValidationError", typeof(bool), typeof(VisualBasicEditor),
63                 new PropertyMetadata(false));
64
65         internal static readonly DependencyProperty ValidationErrorMessageProperty = DependencyProperty.Register("ValidationErrorMessage", typeof(string), typeof(VisualBasicEditor),
66                 new PropertyMetadata(null));
67
68         internal static readonly DependencyProperty ExpressionTextProperty = DependencyProperty.Register("ExpressionText", typeof(string), typeof(VisualBasicEditor),
69                 new PropertyMetadata(null));
70
71         [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
72         public static readonly ICommand CompleteWordCommand = new RoutedCommand("CompleteWordCommand", typeof(VisualBasicEditor));
73         [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
74         public static readonly ICommand GlobalIntellisenseCommand = new RoutedCommand("GlobalIntellisenseCommand", typeof(VisualBasicEditor));
75         [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
76         public static readonly ICommand ParameterInfoCommand = new RoutedCommand("ParameterInfoCommand", typeof(VisualBasicEditor));
77         [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
78         public static readonly ICommand QuickInfoCommand = new RoutedCommand("QuickInfoCommand", typeof(VisualBasicEditor));
79         [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
80         public static readonly ICommand IncreaseFilterLevelCommand = new RoutedCommand("IncreaseFilterLevelCommand", typeof(VisualBasicEditor));
81         [SuppressMessage(FxCop.Category.Security, FxCop.Rule.DoNotDeclareReadOnlyMutableReferenceTypes)]
82         public static readonly ICommand DecreaseFilterLevelCommand = new RoutedCommand("DecreaseFilterLevelCommand", typeof(VisualBasicEditor));
83
84         bool internalModelItemChange = false;
85         string previousText = null;
86         ModelProperty expressionModelProperty;
87         TypeConverter expressionConverter;
88         bool initialized = false;
89         bool isEditorLoaded = false;
90
91         IExpressionEditorService expressionEditorService;
92         IExpressionEditorInstance expressionEditorInstance;
93         TextBox editingTextBox;
94
95         Control hostControl;
96         string editorName;
97         double blockHeight = double.NaN;
98         double blockWidth = double.NaN;
99         bool isExpressionLoaded = false;
100         bool isBeginEditPending = false;
101
102         DesignerPerfEventProvider perfProvider;
103         ModelItem boundedExpression = null;
104         BackgroundWorker validator = null;
105         const int ValidationWaitTime = 800;
106
107         PropertyChangedEventHandler onExpressionModelItemChangedHandler;
108
109         [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.InitializeReferenceTypeStaticFieldsInline,
110             Justification = "This is recommended way by WPF to override metadata of DependencyProperty in derived class")]
111         static VisualBasicEditor()
112         {
113             ExpressionActivityEditor.HintTextProperty.OverrideMetadata(typeof(VisualBasicEditor), new FrameworkPropertyMetadata(SR.ExpressionDefaultText));
114         }
115
116         public VisualBasicEditor()
117         {
118             InitializeComponent();
119
120             this.MinHeight = this.FontSize + 4; /* 4 pixels for border*/
121
122             this.editorName = null;
123
124             this.ContentTemplate = (DataTemplate)FindResource("textblock");
125             this.Loaded += this.OnExpressionTextBoxLoaded;
126             this.Unloaded += this.OnExpressionTextBoxUnloaded;
127         }
128
129         PropertyChangedEventHandler OnExpressionModelItemChanged
130         {
131             get
132             {
133                 if (this.onExpressionModelItemChangedHandler == null)
134                 {
135                     this.onExpressionModelItemChangedHandler = new PropertyChangedEventHandler(this.expressionModelItem_PropertyChanged);
136                 }
137
138                 return this.onExpressionModelItemChangedHandler;
139             }
140         }
141
142         protected override void OnContextMenuOpening(ContextMenuEventArgs e)
143         {
144             e.Handled = true;
145         }
146
147         protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
148         {
149             switch (e.Property.Name)
150             {
151                 case "HintText":
152                     this.OnHintTextChanged(e);
153                     break;
154                 case "Expression":
155                     this.OnExpressionChanged(e);
156                     break;
157                 case "ExpressionType":
158                     this.OnExpressionTypeChanged(e);
159                     break;
160                 case "OwnerActivity":
161                     this.OnOwnerModelItemChanged(e);
162                     break;
163                 case "UseLocationExpression":
164                     this.OnUseLocationExpressionChanged(e);
165                     break;
166                 case "PathToArgument":
167                     this.OnPathToArgumentChanged(e);
168                     break;
169                 case "MaxLines":
170                 case "MinLines":
171                     this.OnLinesChanged(e);
172                     break;
173                 case "AcceptsReturn":
174                     this.OnAcceptsReturnChanged(e);
175                     break;
176                 case "AcceptsTab":
177                     this.OnAcceptsTabChanged(e);
178                     break;
179                 case "IsIndependentExpressionProperty":
180                     this.OnIsIndependentExpressionChanged();
181                     break;
182             }
183             base.OnPropertyChanged(e);
184         }
185
186         protected override void OnPreviewMouseRightButtonDown(MouseButtonEventArgs e)
187         {
188             base.OnPreviewMouseRightButtonDown(e);
189             e.Handled = true;
190         }
191
192         static object OnTextCoerceValue(DependencyObject dp, object value)
193         {
194             string tempText = value as string;
195             VisualBasicEditor etb = dp as VisualBasicEditor;
196             if (etb != null)
197             {
198                 if (tempText != null)
199                 {
200                     tempText = tempText.Trim();
201                 }
202             }
203             return tempText;
204         }
205
206         protected override AutomationPeer OnCreateAutomationPeer()
207         {
208             return new VisualBasicEditorAutomationPeer(this);
209         }
210
211         protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
212         {
213             base.OnLostKeyboardFocus(e);
214
215             if (this.expressionEditorInstance != null &&
216             (this.expressionEditorInstance.HasAggregateFocus ||
217              (this.hostControl != null && this.hostControl.IsFocused)))
218             {
219                 return;
220             }
221
222             DoLostFocus();
223         }
224
225         private void DoLostFocus()
226         {
227             KillValidator();
228
229             ValidateExpression(this);
230
231             if (this.Context != null)
232             {   // Unselect if this is the currently selected one.
233                 ExpressionSelection current = this.Context.Items.GetValue<ExpressionSelection>();
234                 if (current != null && current.ModelItem == this.Expression)
235                 {
236                     ExpressionSelection emptySelection = new ExpressionSelection(null);
237                     this.Context.Items.SetValue(emptySelection);
238                 }
239             }
240
241             // Generate and validate the expression.
242             // Get the text from the snapshot and set it to the Text property
243             if (this.expressionEditorInstance != null)
244             {
245                 this.expressionEditorInstance.ClearSelection();
246             }
247
248             bool committed = false;
249             if (!this.ExplicitCommit)
250             {
251                 //commit change and let the commit change code do the revert
252                 committed = Commit(false);
253
254                 //reset the error icon if we didn't get to set it in the commit
255                 if (!committed || this.IsIndependentExpression)
256                 {
257                     this.EditingState = EditingState.Idle;
258                     // Switch the control back to a textbox -
259                     // but give it the text from the editor (textbox should be bound to the Text property, so should
260                     // automatically be filled with the correct text, from when we set the Text property earlier)
261                     if (!this.ContentTemplate.Equals((DataTemplate)FindResource("textblock")))
262                     {
263                         this.ContentTemplate = (DataTemplate)FindResource("textblock");
264                     }
265                 }
266             }
267
268             //raise EditorLostLogical focus - in case when some clients need to do explicit commit
269             this.RaiseEvent(new RoutedEventArgs(ExpressionTextBox.EditorLostLogicalFocusEvent, this));
270         }
271
272         private void KillValidator()
273         {
274             if (validator != null)
275             {
276                 this.validator.CancelAsync();
277                 this.validator.Dispose();
278                 this.validator = null;
279             }
280         }
281
282         internal static bool ShouldGenerateExpression(string oldText, string newText)
283         {
284             return newText != null && !string.Equals(newText, oldText) && !(oldText == null && newText.Equals(string.Empty));
285         }
286
287         public override bool Commit(bool isExplicitCommit)
288         {
289             bool committed = false;
290             //only generate and validate the expression when when we don't require explicit commit change
291             //or when the commit is explicit
292             if (!this.ExplicitCommit || isExplicitCommit)
293             {
294                 // Generate and validate the expression.
295                 // Get the text from the snapshot and set it to the Text property
296                 this.previousText = null;
297                 // In VS
298                 if (this.expressionEditorInstance != null)
299                 {
300                     this.previousText = this.Text;
301                     this.Text = this.expressionEditorInstance.GetCommittedText();
302                 }
303                 // In rehost
304                 else
305                 {
306                     if (this.Expression != null)
307                     {
308                         Activity expression = this.Expression.GetCurrentValue() as Activity;
309                         // if expression is null, GetExpressionString will return null                           
310                         this.previousText = ExpressionHelper.GetExpressionString(expression, this.OwnerActivity);
311                     }
312                     else
313                     {
314                         this.previousText = null;
315                     }
316
317                     if (this.editingTextBox != null)
318                     {
319                         this.editingTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
320                     }
321                 }
322
323                 // If the Text is null, or equal to the previous value, or changed from null to empty, don't bother generating the expression
324                 // We still need to generate the expression when it is changed from other value to EMPTY however - otherwise
325                 // the case where you had an expression (valid or invalid), then deleted the whole thing will not be evaluated.
326                 if (ShouldGenerateExpression(this.previousText, this.Text))
327                 {
328                     GenerateExpression();
329                     committed = true;
330                 }
331             }
332             if (!this.ContentTemplate.Equals((DataTemplate)FindResource("textblock")))
333             {
334                 this.ContentTemplate = (DataTemplate)FindResource("textblock");
335             }
336             return committed;
337         }
338
339         protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
340         {
341             base.OnPreviewMouseLeftButtonDown(e);
342
343             if (this.Context != null)
344             {
345                 ExpressionSelection expressionSelection = new ExpressionSelection(this.Expression);
346                 this.Context.Items.SetValue(expressionSelection);
347             }
348         }
349
350         public override void BeginEdit()
351         {
352             //am i loaded? is current template a textblock?
353             if (this.isExpressionLoaded || null == this.Expression)
354             {
355                 this.isBeginEditPending = false;
356                 this.IsReadOnly = false;
357                 if (this.IsLoaded && this.ContentTemplate.Equals(this.FindResource("textblock")))
358                 {
359                     //get control's content presenter
360                     ContentPresenter presenter = VisualTreeUtils.GetTemplateChild<ContentPresenter>(this);
361                     if (null != presenter)
362                     {
363                         //and look for the loaded textblock
364                         TextBlock tb = (TextBlock)this.ContentTemplate.FindName("expresionTextBlock", presenter);
365                         if (null != tb)
366                         {
367                             //now - give focus to the textblock - it will trigger OnGotTextBlockFocus event, which eventually
368                             //swithc ETB into expression editing mode.
369                             tb.Focus();
370                         }
371                     }
372                 }
373             }
374             else
375             {
376                 this.isBeginEditPending = true;
377             }
378         }
379
380         internal bool HasAggregateFocus()
381         {
382             bool result = false;
383
384             if (this.IsLoaded)
385             {
386                 if (this.expressionEditorInstance != null)
387                 {
388                     result = (this.hostControl != null && this.hostControl.IsFocused) || this.expressionEditorInstance.HasAggregateFocus;
389                 }
390                 else
391                 {
392                     result = !this.IsKeyboardFocused && this.IsKeyboardFocusWithin;
393                 }
394             }
395
396             return result;
397         }
398
399         void OnTextBlockMouseLeftButtonDown(object sender, RoutedEventArgs e)
400         {
401             if (!this.IsReadOnly)
402             {
403                 TextBlock textBlock = sender as TextBlock;
404                 if (textBlock != null)
405                 {
406                     Keyboard.Focus(textBlock);
407                     e.Handled = true;
408                 }
409             }
410         }
411
412         void OnGotTextBlockFocus(object sender, RoutedEventArgs e)
413         {
414             if (this.Context == null)
415             {
416                 return;
417             }
418
419             DesignerView designerView = this.Context.Services.GetService<DesignerView>();
420
421             if (!designerView.IsMultipleSelectionMode)
422             {
423                 TextBlock textBlock = sender as TextBlock;
424                 bool isInReadOnlyMode = this.IsReadOnly;
425                 if (this.Context != null)
426                 {
427                     ReadOnlyState readOnlyState = this.Context.Items.GetValue<ReadOnlyState>();
428                     isInReadOnlyMode |= readOnlyState.IsReadOnly;
429                 }
430                 if (null != textBlock)
431                 {
432                     this.blockHeight = textBlock.ActualHeight;
433                     this.blockHeight = Math.Max(this.blockHeight, textBlock.MinHeight);
434                     this.blockHeight = Math.Min(this.blockHeight, textBlock.MaxHeight);
435                     this.blockWidth = textBlock.ActualWidth;
436                     this.blockWidth = Math.Max(this.blockWidth, textBlock.MinWidth);
437                     this.blockWidth = Math.Min(this.blockWidth, textBlock.MaxWidth);
438
439                     // 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)
440                     // Also don't create editor when we are in read only mode
441                     if (this.ContentTemplate.Equals((DataTemplate)FindResource("textblock")) && !isInReadOnlyMode)
442                     {
443                         if (this.Context != null)
444                         {
445                             // Get the ExpressionEditorService
446                             this.expressionEditorService = this.Context.Services.GetService<IExpressionEditorService>();
447                         }
448
449                         // If the service exists, use the editor template - else switch to the textbox template
450                         if (this.expressionEditorService != null)
451                         {
452                             this.PerfProvider.WorkflowDesignerExpressionEditorLoadStart();
453                             this.ContentTemplate = (DataTemplate)FindResource("editor");
454                         }
455                         else
456                         {
457                             this.ContentTemplate = (DataTemplate)FindResource("textbox");
458                         }
459                     }
460                 }
461
462                 if (!isInReadOnlyMode)
463                 {
464                     //disable the error icon
465                     this.StartValidator();
466                     this.EditingState = EditingState.Editing;
467                     e.Handled = true;
468                 }
469             }
470         }
471
472         void OnGotEditingFocus(object sender, RoutedEventArgs e)
473         {
474             //disable the error icon
475             this.EditingState = EditingState.Editing;
476             this.StartValidator();
477         }
478
479         // This method is called when the editor data template is loaded - when the editor data template
480         // is loaded, create the editor session and the expression editor
481         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
482             Justification = "CreateExpressionEditor is part of a public API. Propagating exceptions might lead to VS crash.")]
483         [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
484             Justification = "CreateExpressionEditor is part of a public API. Propagating exceptions might lead to VS crash.")]
485         void OnEditorLoaded(object sender, RoutedEventArgs e)
486         {
487             if (!this.isEditorLoaded)
488             {
489                 // If the service exists, create an expression editor and add it to the grid - else switch to the textbox data template
490                 if (this.expressionEditorService != null)
491                 {
492                     Border border = (Border)sender;
493                     // Get the references and variables in scope
494                     AssemblyContextControlItem assemblies = (AssemblyContextControlItem)this.Context.Items.GetValue(typeof(AssemblyContextControlItem));
495                     List<ModelItem> declaredVariables = VisualBasicEditor.GetVariablesInScope(this.OwnerActivity);
496
497                     ImportedNamespaceContextItem importedNamespaces = this.Context.Items.GetValue<ImportedNamespaceContextItem>();
498                     importedNamespaces.EnsureInitialized(this.Context);
499                     //if the expression text is empty and the expression type is set, then we initialize the text to prompt text
500                     if (String.Equals(this.ExpressionText, string.Empty, StringComparison.OrdinalIgnoreCase) && this.ExpressionType != null)
501                     {
502                         this.Text = TypeToPromptTextConverter.GetPromptText(this.ExpressionType);
503                     }
504
505                     //this is a hack
506                     this.blockWidth = Math.Max(this.ActualWidth - 8, 0);  //8 is the margin
507                     if (this.HasErrors)
508                     {
509                         this.blockWidth = Math.Max(this.blockWidth - 16, 0); //give 16 for error icon
510                     }
511                     try
512                     {
513                         if (this.ExpressionType != null)
514                         {
515                             this.expressionEditorInstance = this.expressionEditorService.CreateExpressionEditor(assemblies, importedNamespaces, declaredVariables, this.Text, this.ExpressionType, new Size(this.blockWidth, this.blockHeight));
516                         }
517                         else
518                         {
519                             this.expressionEditorInstance = this.expressionEditorService.CreateExpressionEditor(assemblies, importedNamespaces, declaredVariables, this.Text, new Size(this.blockWidth, this.blockHeight));
520                         }
521                     }
522                     catch (Exception ex)
523                     {
524                         Trace.WriteLine(ex.Message);
525                     }
526
527                     if (this.expressionEditorInstance != null)
528                     {
529                         try
530                         {
531                             this.expressionEditorInstance.VerticalScrollBarVisibility = this.VerticalScrollBarVisibility;
532                             this.expressionEditorInstance.HorizontalScrollBarVisibility = this.HorizontalScrollBarVisibility;
533
534                             this.expressionEditorInstance.AcceptsReturn = this.AcceptsReturn;
535                             this.expressionEditorInstance.AcceptsTab = this.AcceptsTab;
536
537                             // Add the expression editor to the text panel, at column 1
538                             this.hostControl = this.expressionEditorInstance.HostControl;
539
540                             // Subscribe to this event to change scrollbar visibility on the fly for auto, and to resize the hostable editor
541                             // as necessary
542                             this.expressionEditorInstance.LostAggregateFocus += new EventHandler(OnEditorLostAggregateFocus);
543                             this.expressionEditorInstance.Closing += new EventHandler(OnEditorClosing);
544
545                             // Set up Hostable Editor properties
546                             this.expressionEditorInstance.MinLines = this.MinLines;
547                             this.expressionEditorInstance.MaxLines = this.MaxLines;
548
549                             this.expressionEditorInstance.HostControl.Style = (Style)FindResource("editorStyle");
550
551                             border.Child = this.hostControl;
552                             this.expressionEditorInstance.Focus();
553                         }
554                         catch (KeyNotFoundException ex)
555                         {
556                             Debug.Fail("Unable to find editor with the following editor name: " + this.editorName, ex.Message);
557                         }
558                     }
559                 }
560
561                 if (this.expressionEditorInstance == null)
562                 {
563                     this.ContentTemplate = (DataTemplate)FindResource("textbox");
564                 }
565                 this.PerfProvider.WorkflowDesignerExpressionEditorLoaded();
566
567                 this.isEditorLoaded = true;
568             }
569         }
570
571         void OnEditorClosing(object sender, EventArgs e)
572         {
573             if (this.expressionEditorInstance != null)
574             {
575                 //these events are expected to be unregistered during lost focus event, but
576                 //we are unregistering them during unload just in case.  Ideally we want to
577                 //do this in the CloseExpressionEditor method
578                 this.expressionEditorInstance.LostAggregateFocus -= new EventHandler(OnEditorLostAggregateFocus);
579
580                 this.expressionEditorInstance.Closing -= new EventHandler(OnEditorClosing);
581                 this.expressionEditorInstance = null;
582             }
583             Border boarder = this.hostControl.Parent as Border;
584             if (boarder != null)
585             {
586                 boarder.Child = null;
587             }
588             this.hostControl = null;
589             this.editorName = null;
590
591         }
592
593         void OnEditorLostAggregateFocus(object sender, EventArgs e)
594         {
595             this.DoLostFocus();
596         }
597
598         //void BindEditorProperties()
599         //{
600         //    this.hostControl.SetBinding(Control.ContextMenuProperty, "ContextMenu");
601         //    this.hostControl.SetBinding(Control.FlowDirectionProperty, "FlowDirection");
602         //    this.hostControl.SetBinding(Control.FontFamilyProperty, "FontFamily");
603         //    this.hostControl.SetBinding(Control.FontSizeProperty, "FontSize");
604         //    this.hostControl.SetBinding(Control.FontStretchProperty, "FontStretch");
605         //    this.hostControl.SetBinding(Control.FontStyleProperty, "FontStyle");
606         //    this.hostControl.SetBinding(Control.FontWeightProperty, "FontWeight");
607         //    this.hostControl.SetBinding(Control.HeightProperty, "Height");
608         //    this.hostControl.SetBinding(Control.LanguageProperty, "Language");
609         //    this.hostControl.SetBinding(Control.SnapsToDevicePixelsProperty, "SnapsToDevicePixels");
610         //}
611
612         // This method is called when the editor data template is unloaded - when the editor data template
613         // is unloaded, close the editor session and set the expression editor and editor session to null
614         void OnEditorUnloaded(object sender, RoutedEventArgs e)
615         {
616             // Blank the editorSession and the expressionEditor so as not to use up memory
617             // Destroy both as you can only ever spawn one editor per session
618             if (this.expressionEditorInstance != null)
619             {
620                 //if we are unloaded during editing, this means we got here by someone clicking breadcrumb, we should try to commit
621                 if (this.EditingState == EditingState.Editing)
622                 {
623                     this.Commit(false);
624                 }
625                 this.expressionEditorInstance.Close();
626             }
627             else
628             {
629                 this.editingTextBox = null;
630             }
631
632             this.isEditorLoaded = false;
633         }
634
635         // This method is to give focus and set the caret position when the TextBox DataTemplate is loaded
636         void OnTextBoxLoaded(object sender, RoutedEventArgs e)
637         {
638             TextBox textbox = (TextBox)sender;
639             this.editingTextBox = textbox;
640             textbox.ContextMenu = null;
641
642             //to workaround a but in the TextBox layout code
643             Binding binding = new Binding();
644             binding.Source = this;
645             binding.Path = new PropertyPath(VisualBasicEditor.TextProperty);
646             binding.Mode = BindingMode.TwoWay;
647             binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
648
649             textbox.SetBinding(TextBox.TextProperty, binding);
650
651             // Set the cursor to correct text position
652             int index = GetCharacterIndexFromPoint(textbox);
653
654             textbox.SelectionStart = index;
655             textbox.SelectionLength = 0;
656
657             textbox.Focus();
658         }
659
660         // This method is to workaround the fact that textbox.GetCharacterIndexFromPoint returns the caret
661         // to the left of the character... Thus you can never get the caret after the last character in the
662         // expression string.
663         int GetCharacterIndexFromPoint(TextBox textbox)
664         {
665             Point position = Mouse.GetPosition(textbox);
666             int index = textbox.GetCharacterIndexFromPoint(position, false);
667
668             if (index < 0)
669             {
670                 // May have clicked outside the text area, get the index of nearest char
671                 index = textbox.GetCharacterIndexFromPoint(position, true);
672                 if (index < 0)
673                 {
674                     index = 0;
675                 }
676
677                 // Adjust the cursor position if we clicked to the right of returned character
678                 Rect charRect = textbox.GetRectFromCharacterIndex(index, true);
679                 if (position.X > charRect.Left + charRect.Width / 2)
680                 {
681                     index++;
682                 }
683             }
684
685             return index;
686         }
687
688         static void ValidateExpression(VisualBasicEditor etb)
689         {
690             string errorMessage;
691             if (etb.DoValidation(new ExpressionValidationContext(etb), out errorMessage))
692             {
693                 etb.UpdateValidationError(errorMessage);
694             }
695         }
696
697         [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.ReviewUnusedParameters, Justification = "Existing code")]
698         void OnLinesChanged(DependencyPropertyChangedEventArgs e)
699         {
700             if (this.MinLines > this.MaxLines)
701             {
702                 this.MaxLines = this.MinLines;
703             }
704         }
705
706         static void OnTextChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
707         {
708             VisualBasicEditor textBox = (VisualBasicEditor)dependencyObject;
709
710             if (textBox.ExpressionEditorService != null && textBox.expressionEditorInstance != null)
711             {
712                 textBox.expressionEditorInstance.Text = textBox.Text;
713             }
714
715         }
716
717         void OnOwnerModelItemChanged(DependencyPropertyChangedEventArgs e)
718         {
719             this.InitializeContext(e);
720             this.OnPathToArgumentChanged(this.PathToArgument);
721         }
722
723         public override IExpressionEditorService ExpressionEditorService
724         {
725             get { return this.expressionEditorService; }
726         }
727
728         internal string Text
729         {
730             get { return (string)GetValue(TextProperty); }
731             set { SetValue(TextProperty, value); }
732         }
733
734         internal string ExpressionText
735         {
736             get { return (string)GetValue(ExpressionTextProperty); }
737             set { SetValue(ExpressionTextProperty, value); }
738         }
739
740         internal ValidationState ValidationState
741         {
742             get { return (ValidationState)GetValue(VisualBasicEditor.ValidationStateProperty); }
743             set { SetValue(VisualBasicEditor.ValidationStateProperty, value); }
744         }
745
746         internal bool HasErrors
747         {
748             get
749             {
750                 bool hasErrors = false;
751                 if (this.EditingState == EditingState.Idle
752                     && !this.IsIndependentExpression)
753                 {
754                     if (this.Expression != null && this.ValidationService != null && this.ValidationService.ValidationStateProperty != null)
755                     {
756                         ValidationState state = this.ValidationService.ValidationStateProperty.Getter(this.Expression);
757                         hasErrors = state == ValidationState.Error;
758                     }
759                 }
760                 else
761                 {
762                     hasErrors = this.HasValidationError;
763                 }
764                 return hasErrors;
765             }
766         }
767
768         internal string ErrorMessage
769         {
770             get
771             {
772                 string errorMessage = string.Empty;
773
774                 if (this.EditingState == EditingState.Idle && !this.IsIndependentExpression)
775                 {
776                     if (this.Expression != null && this.ValidationService != null && this.ValidationService.ValidationStateProperty != null)
777                     {
778                         errorMessage = this.ValidationService.ValidationMessageProperty.Getter(this.Expression);
779                     }
780                 }
781                 else
782                 {
783                     errorMessage = this.ValidationErrorMessage;
784                 }
785                 return errorMessage;
786             }
787         }
788
789         internal EditingState EditingState
790         {
791             get { return (EditingState)GetValue(EditingStateProperty); }
792             set { SetValue(EditingStateProperty, value); }
793         }
794
795         internal bool HasValidationError
796         {
797             get { return (bool)GetValue(HasValidationErrorProperty); }
798             set { SetValue(HasValidationErrorProperty, value); }
799         }
800
801         internal string ValidationErrorMessage
802         {
803             get { return (string)GetValue(ValidationErrorMessageProperty); }
804             set { SetValue(ValidationErrorMessageProperty, value); }
805         }
806
807         DesignerPerfEventProvider PerfProvider
808         {
809             get
810             {
811                 if (this.perfProvider == null && this.Context != null)
812                 {
813                     perfProvider = this.Context.Services.GetService<DesignerPerfEventProvider>();
814                 }
815                 return this.perfProvider;
816             }
817         }
818
819         ValidationService ValidationService
820         {
821             get
822             {
823                 if (this.Context != null)
824                 {
825                     return this.Context.Services.GetService<ValidationService>();
826                 }
827                 else
828                 {
829                     return null;
830                 }
831             }
832         }
833
834         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
835             Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
836         [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
837             Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
838         internal void GenerateExpression()
839         {
840             Activity valueExpression = null;
841
842             // If the text is null we don't need to bother generating the expression (this would be the case the
843             // first time you enter an ETB. We still need to generate the expression when it is EMPTY however - otherwise
844             // the case where you had an expression (valid or invalid), then deleted the whole thing will not be evaluated.
845             if (this.Text != null)
846             {
847                 using (ModelEditingScope scope = this.OwnerActivity.BeginEdit(SR.PropertyChangeEditingScopeDescription))
848                 {
849                     this.EditingState = EditingState.Validating;
850                     // we set the expression to null
851                     // a) when the expressionText is empty AND it's a reference expression or
852                     // b) when the expressionText is empty AND the DefaultValue property is null
853                     if (this.Text.Length == 0 &&
854                         (this.UseLocationExpression || (this.DefaultValue == null)))
855                     {
856                         valueExpression = null;
857                     }
858                     else
859                     {
860                         if (this.Text.Length == 0)
861                         {
862                             this.Text = this.DefaultValue;
863                         }
864                         valueExpression = CreateVBExpression();
865                     }
866                     CreateExpressionModelItem(valueExpression);
867                     scope.Complete();
868                 }
869             }
870         }
871
872         void OnValidationCompleted(object sender, EventArgs e)
873         {
874             if (this.EditingState != EditingState.Editing)
875             {
876                 if (this.Expression != null && this.ValidationService != null && this.ValidationService.ValidationStateProperty != null)
877                 {
878                     this.ValidationState = this.ValidationService.ValidationStateProperty.Getter(this.Expression);
879                 }
880
881                 this.EditingState = EditingState.Idle;
882             }
883         }
884
885         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
886             Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
887         [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
888             Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
889         private void CreateExpressionModelItem(object valueExpression)
890         {
891             // try to wrap the droppedObject in  a ModelItem.
892             ModelItem expressionModelItem = null;
893             if (valueExpression != null)
894             {
895                 ModelServiceImpl modelService = (ModelServiceImpl)this.Context.Services.GetService<ModelService>();
896                 expressionModelItem = modelService.WrapAsModelItem(valueExpression);
897                 expressionModelItem.PropertyChanged += this.OnExpressionModelItemChanged;
898                 this.boundedExpression = expressionModelItem;
899             }
900             try
901             {
902                 this.internalModelItemChange = true;
903                 this.EditingState = EditingState.Validating;
904                 SetValue(ExpressionProperty, expressionModelItem);
905             }
906             catch (Exception err)
907             {
908                 Trace.WriteLine(string.Format(CultureInfo.CurrentUICulture, "{0}\r\n{1}", err.Message, err.StackTrace));
909                 this.internalModelItemChange = false;
910             }
911         }
912
913         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
914             Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
915         [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
916             Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
917         private Activity CreateVBExpression()
918         {
919             Activity valueExpression = null;
920             if (this.OwnerActivity != null)
921             {
922                 ExpressionValidationContext validationContext = new ExpressionValidationContext(this);
923
924                 Type expReturnType = null;
925                 string newExpressionText = null;
926                 SourceExpressionException compileErrorMessages;
927
928                 try
929                 {
930                     VisualBasicSettings settings = null;
931                     valueExpression = CreateVBExpression(validationContext, out newExpressionText, out expReturnType, out compileErrorMessages, out settings);
932
933                     if (settings != null)
934                     {
935                         Fx.Assert(this.Context != null, "editing context cannot be null");
936                         //merge with import designer
937                         foreach (VisualBasicImportReference reference in settings.ImportReferences)
938                         {
939                             ImportDesigner.AddImport(reference.Import, this.Context);
940                         }
941                     }
942
943                     if (!string.IsNullOrEmpty(newExpressionText))
944                     {
945                         this.previousText = this.Text;
946                         this.Text = newExpressionText;
947                     }
948                 }
949                 catch (Exception err)
950                 {
951                     //if the VisualBasicDesignerHelper were able to resolve the type we use that
952                     if (expReturnType == null)
953                     {
954                         //if not we try to use the expression type
955                         expReturnType = this.ExpressionType;
956                     }
957
958                     //if expression type is also null, the we use object
959                     if (expReturnType == null)
960                     {
961                         expReturnType = typeof(object);
962                     }
963
964                     valueExpression = VisualBasicEditor.CreateExpressionFromString(expReturnType, this.Text, UseLocationExpression, validationContext.ParserContext);
965
966                     Trace.WriteLine(string.Format(CultureInfo.CurrentUICulture, "{0}\r\n{1}", err.Message, err.StackTrace));
967                 }
968                 this.ExpressionText = this.Text;
969             }
970             else
971             {
972                 // If the OwnerActivity is null, do not try to compile the expression otherwise VS will crash
973                 // Inform the user that OwnerActivity is null (i.e. there is a error in their code)
974                 Trace.WriteLine("ExpressionTextBox OwnerActivity is null.");
975             }
976             return valueExpression;
977         }
978
979         internal static ActivityWithResult CreateExpressionFromString(string expressionText, bool isLocation, Type type)
980         {
981             return VisualBasicEditor.CreateExpressionFromString(type, expressionText, isLocation, new ParserContext());
982         }
983
984         internal static ActivityWithResult CreateExpressionFromString(Type type, string expressionText, bool isLocation, ParserContext context)
985         {
986             ActivityWithResult newExpression;
987
988             if (!isLocation)
989             {
990                 newExpression = ExpressionHelper.TryCreateLiteral(type, expressionText, context);
991
992                 if (newExpression != null)
993                 {
994                     return newExpression;
995                 }
996             }
997
998             Type targetExpressionType = null;
999             if (isLocation)
1000             {
1001                 targetExpressionType = typeof(VisualBasicReference<>).MakeGenericType(type);
1002             }
1003             else
1004             {
1005                 targetExpressionType = typeof(VisualBasicValue<>).MakeGenericType(type);
1006             }
1007
1008             //create new visual basic value and pass expression text into it
1009             newExpression = (ActivityWithResult)Activator.CreateInstance(targetExpressionType, expressionText);
1010             //targetExpressionType.GetProperty("Settings").SetValue(newExpression, settings, null);
1011             //this code below is never executed - it is placed here only to enable compilation support whenver VisualBasicValue constructor
1012             //changes its parameter list.
1013             if (null == newExpression)
1014             {
1015                 //if this gives compilation error, please update CreateInstance parameter list above as well!
1016                 newExpression = new VisualBasicValue<string>(expressionText);
1017             }
1018
1019             return newExpression;
1020         }
1021
1022         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
1023             Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
1024         [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
1025             Justification = "The conversion to an expression might fail due to invalid user input. Propagating exceptions might lead to VS crash.")]
1026         private static Activity CreateVBExpression(ExpressionValidationContext context, out string newExpressionText, out Type expReturnType, out SourceExpressionException compileErrorMessages, out VisualBasicSettings vbSettings)
1027         {
1028             expReturnType = null;
1029             newExpressionText = null;
1030             compileErrorMessages = null;
1031             vbSettings = null;
1032
1033             //try easy way first - look if there is a type converter which supports conversion between expression type and string
1034             ActivityWithResult literal = null;
1035             try
1036             {
1037                 if (!context.UseLocationExpression)
1038                 {
1039                     literal = ExpressionHelper.TryCreateLiteral(context.ExpressionType, context.ExpressionText, context.ParserContext);
1040                 }
1041
1042                 if (literal != null)
1043                 {
1044                     //need to get new expression text - converter might have changed its format, and we want it to be up to date
1045                     IValueSerializableExpression serializableExpression = literal as IValueSerializableExpression;
1046                     Fx.Assert(serializableExpression != null, "the expression has to be a Literal<>, which should be IValueSerializableExpression");
1047                     if (serializableExpression.CanConvertToString(context.ParserContext))
1048                     {
1049                         bool shouldBeQuoted = typeof(string) == context.ExpressionType || typeof(Uri) == context.ExpressionType;
1050
1051                         //whether string begins and ends with quotes '"'. also, if there are
1052                         //more quotes within than those begining and ending ones, do not bother with literal - assume this is an expression.
1053                         bool isQuotedString = shouldBeQuoted &&
1054                                 context.ExpressionText.StartsWith("\"", StringComparison.CurrentCulture) &&
1055                                 context.ExpressionText.EndsWith("\"", StringComparison.CurrentCulture) &&
1056                                 context.ExpressionText.IndexOf("\"", 1, StringComparison.CurrentCulture) == context.ExpressionText.Length - 1;
1057                         var formatString = isQuotedString ? "\"{0}\"" : "{0}";
1058                         newExpressionText = string.Format(CultureInfo.InvariantCulture, formatString, serializableExpression.ConvertToString(context.ParserContext));
1059                     }
1060                 }
1061             }
1062             //conversion failed - do nothing, let VB compiler take care of the expression
1063             catch
1064             {
1065             }
1066
1067             Activity valueExpression = literal;
1068
1069             if (null == valueExpression)
1070             {
1071                 if (!context.UseLocationExpression)
1072                 {
1073                     //Compile for validation.
1074                     valueExpression = VisualBasicDesignerHelper.CreatePrecompiledVisualBasicValue(context.ExpressionType, context.ExpressionText, context.ParserContext.Namespaces, context.ReferencedAssemblies, context.ParserContext, out expReturnType, out compileErrorMessages, out vbSettings);
1075                 }
1076                 else
1077                 {
1078                     //Compile for validation.
1079                     valueExpression = VisualBasicDesignerHelper.CreatePrecompiledVisualBasicReference(context.ExpressionType, context.ExpressionText, context.ParserContext.Namespaces, context.ReferencedAssemblies, context.ParserContext, out expReturnType, out compileErrorMessages, out vbSettings);
1080                 }
1081
1082                 ////It's possible the inferred type of expression is a dynamic type (e.g. delegate type), in this case it will cause serialization failure.
1083                 ////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
1084                 if ((expReturnType.Assembly.IsDynamic) && (context.ExpressionType == null))
1085                 {
1086                     ActivityWithResult originalExpression = valueExpression as ActivityWithResult;
1087                     ActivityWithResult morphedExpression;
1088                     if (ExpressionHelper.TryMorphExpression(originalExpression, ExpressionHelper.IsGenericLocationExpressionType(originalExpression), typeof(object), context.EditingContext, out morphedExpression))
1089                     {
1090                         valueExpression = morphedExpression;
1091                     }
1092                 }
1093             }
1094
1095             return valueExpression;
1096         }
1097
1098         [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.ReviewUnusedParameters, Justification = "Existing code")]
1099         void OnExpressionTypeChanged(DependencyPropertyChangedEventArgs e)
1100         {
1101             //for independent expressions, when the type changes, we need to validate the expressions
1102             if (this.initialized
1103                 && this.IsIndependentExpression
1104                 && this.EditingState == EditingState.Idle)
1105             {
1106                 ValidateExpression(this);
1107             }
1108         }
1109
1110         [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.ReviewUnusedParameters, Justification = "Existing code")]
1111         void OnUseLocationExpressionChanged(DependencyPropertyChangedEventArgs e)
1112         {
1113             //for independent expressions, when the type changes, we need to validate the expressions
1114             if (this.initialized
1115                 && this.IsIndependentExpression
1116                 && this.EditingState == EditingState.Idle
1117                 && this.OwnerActivity != null)
1118             {
1119                 ValidateExpression(this);
1120             }
1121         }
1122
1123         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
1124             Justification = "The entered expression might be invalid and may throw on deserialization. Propagating exception might lead to VS crash")]
1125         [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
1126             Justification = "The entered expression might be invalid and may throw on deserialization. Propagating exception might lead to VS crash")]
1127         void OnExpressionChanged(DependencyPropertyChangedEventArgs e)
1128         {
1129             ModelItem oldExpression = e.OldValue as ModelItem;
1130             if (oldExpression != null)
1131             {
1132                 oldExpression.PropertyChanged -= this.OnExpressionModelItemChanged;
1133             }
1134             ModelItem expression = e.NewValue as ModelItem;
1135             if (expression != null && expression != this.boundedExpression)
1136             {
1137                 expression.PropertyChanged += this.OnExpressionModelItemChanged;
1138             }
1139
1140             try
1141             {
1142                 this.boundedExpression = expression;
1143
1144                 this.OnExpressionChanged();
1145             }
1146             catch (Exception err)
1147             {
1148                 //if context is set - use error reporting
1149                 if (null != this.Context)
1150                 {
1151                     this.Context.Items.SetValue(new ErrorItem() { Message = err.Message, Details = err.ToString() });
1152                 }
1153                 //otherwise - fallback to message box
1154                 else
1155                 {
1156                     MessageBox.Show(err.ToString(), err.Message);
1157                 }
1158             }
1159
1160         }
1161
1162         void expressionModelItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
1163         {
1164             ModelItem item = sender as ModelItem;
1165             if (item != null)
1166             {
1167                 if (e.PropertyName.Equals("ExpressionText", StringComparison.Ordinal))
1168                 {
1169                     this.OnExpressionChanged();
1170                 }
1171             }
1172         }
1173
1174         void OnPathToArgumentChanged(DependencyPropertyChangedEventArgs e)
1175         {
1176             this.OnPathToArgumentChanged((string)e.NewValue);
1177         }
1178
1179         void OnIsIndependentExpressionChanged()
1180         {
1181             //if this is an independent expression, we need to initialize the validation error because validation service will not validate it
1182             if (this.initialized
1183                 && this.IsIndependentExpression
1184                 && this.EditingState == EditingState.Idle)
1185             {
1186                 ValidateExpression(this);
1187             }
1188         }
1189
1190         void UpdateValidationState()
1191         {
1192             if (this.Expression != null && this.ValidationService != null && this.ValidationService.ValidationStateProperty != null)
1193             {
1194                 this.ValidationState = this.ValidationService.ValidationStateProperty.Getter(this.Expression);
1195             }
1196             else
1197             {
1198                 this.ValidationState = ValidationState.Valid;
1199             }
1200         }
1201
1202         //We need to react to OnExpressionChanged, since there might be multiple ExpressionTextBoxes(ETB) associated to a single Expression.
1203         //All the ETBs should be updated if the value in any of the ETBs is changed.
1204         void OnExpressionChanged()
1205         {
1206             if (this.HintText == SR.UnsupportedExpressionHintText)
1207             {
1208                 this.HintText = SR.ExpressionDefaultText;
1209                 this.InitializeHintText();
1210             }
1211
1212             if (!this.internalModelItemChange)
1213             {
1214                 if (this.Expression == null)
1215                 {
1216                     //new expression is null - there is no text, no previous text, erros should be clear as well as error message
1217                     this.Text = string.Empty;
1218                     this.previousText = this.Text;
1219                     this.ExpressionText = null;
1220                     this.ValidationState = ValidationState.Valid;
1221                 }
1222                 else
1223                 {
1224                     this.UpdateValidationState();
1225
1226                     object expressionObject = this.Expression.GetCurrentValue();
1227                     ActivityWithResult expression = expressionObject as ActivityWithResult;
1228                     if (VisualBasicEditor.IsSupportedExpressionType(expression))
1229                     {
1230                         String expressionString = null;
1231                         //create parser context - do not pass ownerActivity - it might be null at this time
1232                         ParserContext context = new ParserContext();
1233                         expressionString = ExpressionHelper.GetExpressionString(expression, context);
1234
1235                         this.Text = expressionString;
1236                         this.ExpressionText = expressionString;
1237                         this.previousText = this.Text;
1238                         this.IsSupportedExpression = true;
1239                     }
1240                     else
1241                     {
1242                         this.Text = string.Empty;
1243                         this.IsSupportedExpression = false;
1244                         this.HintText = SR.UnsupportedExpressionHintText;
1245                     }
1246
1247                     this.isExpressionLoaded = true;
1248                     if (this.isBeginEditPending)
1249                     {
1250                         this.BeginEdit();
1251                     }
1252                 }
1253             }
1254             internalModelItemChange = false;
1255         }
1256
1257         private static bool IsSupportedExpressionType(object expressionObject)
1258         {
1259             ActivityWithResult expression = expressionObject as ActivityWithResult;
1260             bool isSupported = false;
1261             if (expression != null)
1262             {
1263                 Type expressionType = expression.GetType();
1264                 Type genericExpressionType = null;
1265                 if (expressionType.IsGenericType)
1266                 {
1267                     genericExpressionType = expressionType.GetGenericTypeDefinition();
1268                 }
1269
1270                 if (genericExpressionType == VisualBasicValueType ||
1271                     genericExpressionType == VisualBasicReferenceType ||
1272                     genericExpressionType == VariableReferenceType ||
1273                     genericExpressionType == VariableValueType ||
1274                     (genericExpressionType == LiteralType && ExpressionHelper.CanTypeBeSerializedAsLiteral(expression.ResultType)))
1275                 {
1276                     isSupported = true;
1277                 }
1278             }
1279
1280             return isSupported;
1281         }
1282
1283         void OnPathToArgumentChanged(string pathAsString)
1284         {
1285             this.expressionModelProperty = null;
1286             this.expressionConverter = null;
1287             if (!string.IsNullOrEmpty(pathAsString) && null != this.OwnerActivity)
1288             {
1289                 string[] path = pathAsString.Split('.');
1290                 if (path.Length > 0)
1291                 {
1292                     this.expressionModelProperty = this.OwnerActivity.Properties[path[0]];
1293                     for (int i = 1; i < path.Length; ++i)
1294                     {
1295                         if (null != this.expressionModelProperty && null != this.expressionModelProperty.Value)
1296                         {
1297                             this.expressionModelProperty = this.expressionModelProperty.Value.Properties[path[i]];
1298                         }
1299                         else
1300                         {
1301                             this.expressionModelProperty = null;
1302                             break;
1303                         }
1304                     }
1305                 }
1306             }
1307             if (null != this.expressionModelProperty)
1308             {
1309                 this.expressionConverter = ((ModelPropertyImpl)this.expressionModelProperty).PropertyDescriptor.Converter;
1310             }
1311             this.InitializeHintText();
1312         }
1313
1314         void InitializeHintText()
1315         {
1316             DescriptionAttribute customHint = null;
1317             if (this.expressionModelProperty != null && this.expressionModelProperty.Attributes.Count != 0)
1318             {
1319                 customHint = this.expressionModelProperty.Attributes
1320                     .OfType<DescriptionAttribute>()
1321                     .FirstOrDefault();
1322             }
1323             this.HintText = (null == customHint || string.IsNullOrEmpty(customHint.Description) ?
1324                 (string.Equals(this.HintText, SR.ExpressionDefaultText) ? SR.ExpressionDefaultText : this.HintText) : customHint.Description);
1325
1326             string hint = null;
1327             if (this.HintText != null)
1328             {
1329                 hint = this.HintText.Trim(new char[] { '<', '>' });
1330                 this.SetValue(AutomationProperties.HelpTextProperty, hint);
1331             }
1332         }
1333
1334         void InitializeContext(DependencyPropertyChangedEventArgs e)
1335         {
1336             if (e.OldValue != null)
1337             {
1338                 // remove the OnValidationCompleted event handler on the old value
1339                 ModelItem modelItem = (ModelItem)e.OldValue;
1340                 if (modelItem != null)
1341                 {
1342                     EditingContext context = modelItem.GetEditingContext();
1343                     ValidationService validationService = context.Services.GetService<ValidationService>();
1344                     if (validationService != null)
1345                     {
1346                         validationService.ValidationCompleted -= this.OnValidationCompleted;
1347                     }
1348                 }
1349             }
1350
1351
1352             if (null != this.OwnerActivity)
1353             {
1354                 if (this.ValidationService != null)
1355                 {
1356                     this.ValidationService.ValidationCompleted += this.OnValidationCompleted;
1357                     this.UpdateValidationState();
1358                 }
1359             }
1360         }
1361
1362         #region Command Handlers
1363
1364         public override bool CanCommit()
1365         {
1366             string currentText = this.Text;
1367             if (this.expressionEditorInstance != null)
1368             {
1369                 currentText = this.expressionEditorInstance.Text ?? this.expressionEditorInstance.Text.Trim();
1370             }
1371             else if (this.editingTextBox != null)
1372             {
1373                 currentText = this.editingTextBox.Text ?? this.editingTextBox.Text.Trim();
1374             }
1375
1376             //we dont need to commit change if currentText and previousText is the same
1377             //null and empty should be considered equal in this context
1378
1379             return !string.Equals(currentText, this.previousText) &&
1380                    !(string.IsNullOrEmpty(currentText) && string.IsNullOrEmpty(this.previousText));
1381         }
1382
1383         void OnExpressionTextBoxLoaded(object sender, RoutedEventArgs e)
1384         {
1385             this.InitializeHintText();
1386
1387             //if this is an independent expression, we need to initialize the validation error because validation service will not validate it
1388             if (this.IsIndependentExpression)
1389             {
1390                 ValidateExpression(this);
1391             }
1392
1393             this.initialized = true;
1394         }
1395
1396         void OnExpressionTextBoxUnloaded(object sender, RoutedEventArgs e)
1397         {
1398             if (this.ValidationService != null)
1399             {
1400                 this.ValidationService.ValidationCompleted -= this.OnValidationCompleted;
1401             }
1402             KillValidator();
1403
1404             if (this.boundedExpression != null)
1405             {
1406                 this.boundedExpression.PropertyChanged -= this.OnExpressionModelItemChanged;
1407             }
1408         }
1409
1410         public override void OnCompleteWordCommandCanExecute(CanExecuteRoutedEventArgs e)
1411         {
1412             if (this.expressionEditorInstance != null)
1413             {
1414
1415                 e.CanExecute = this.expressionEditorInstance.CanCompleteWord();
1416                 e.Handled = true;
1417             }
1418             else
1419             {
1420                 e.Handled = false;
1421             }
1422         }
1423
1424         public override void OnGlobalIntellisenseCommandCanExecute(CanExecuteRoutedEventArgs e)
1425         {
1426
1427             if (this.expressionEditorInstance != null)
1428             {
1429                 e.CanExecute = this.expressionEditorInstance.CanGlobalIntellisense();
1430                 e.Handled = true;
1431             }
1432             else
1433             {
1434                 e.Handled = false;
1435             }
1436         }
1437
1438         public override void OnParameterInfoCommandCanExecute(CanExecuteRoutedEventArgs e)
1439         {
1440
1441             if (this.expressionEditorInstance != null)
1442             {
1443                 e.CanExecute = this.expressionEditorInstance.CanParameterInfo();
1444                 e.Handled = true;
1445             }
1446             else
1447             {
1448                 e.Handled = false;
1449             }
1450         }
1451
1452         public override void OnQuickInfoCommandCanExecute(CanExecuteRoutedEventArgs e)
1453         {
1454             if (this.expressionEditorInstance != null)
1455             {
1456                 e.CanExecute = this.expressionEditorInstance.CanQuickInfo();
1457                 e.Handled = true;
1458             }
1459             else
1460             {
1461                 e.Handled = false;
1462             }
1463         }
1464
1465         public override void OnIncreaseFilterLevelCommandCanExecute(CanExecuteRoutedEventArgs e)
1466         {
1467             if (this.expressionEditorInstance != null)
1468             {
1469                 e.CanExecute = this.expressionEditorInstance.CanIncreaseFilterLevel();
1470                 e.Handled = true;
1471             }
1472             else
1473             {
1474                 e.Handled = false;
1475             }
1476         }
1477
1478         public override void OnDecreaseFilterLevelCommandCanExecute(CanExecuteRoutedEventArgs e)
1479         {
1480             if (this.expressionEditorInstance != null)
1481             {
1482                 e.CanExecute = this.expressionEditorInstance.CanDecreaseFilterLevel();
1483                 e.Handled = true;
1484             }
1485             else
1486             {
1487                 e.Handled = false;
1488             }
1489         }
1490
1491         void OnCutCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
1492         {
1493             if (this.expressionEditorInstance != null)
1494             {
1495                 e.CanExecute = this.expressionEditorInstance.CanCut();
1496                 e.Handled = true;
1497             }
1498             else
1499             {
1500                 e.Handled = false;
1501             }
1502         }
1503
1504         public override void OnCompleteWordCommandExecute(ExecutedRoutedEventArgs e)
1505         {
1506             if (this.expressionEditorInstance != null)
1507             {
1508                 e.Handled = this.expressionEditorInstance.CompleteWord();
1509             }
1510             else
1511             {
1512                 e.Handled = false;
1513             }
1514
1515         }
1516
1517         public override void OnGlobalIntellisenseCommandExecute(ExecutedRoutedEventArgs e)
1518         {
1519             if (this.expressionEditorInstance != null)
1520             {
1521                 e.Handled = this.expressionEditorInstance.GlobalIntellisense();
1522             }
1523             else
1524             {
1525                 e.Handled = false;
1526             }
1527
1528         }
1529
1530         public override void OnParameterInfoCommandExecute(ExecutedRoutedEventArgs e)
1531         {
1532             if (this.expressionEditorInstance != null)
1533             {
1534                 e.Handled = this.expressionEditorInstance.ParameterInfo();
1535             }
1536             else
1537             {
1538                 e.Handled = false;
1539             }
1540
1541         }
1542
1543         public override void OnQuickInfoCommandExecute(ExecutedRoutedEventArgs e)
1544         {
1545             if (this.expressionEditorInstance != null)
1546             {
1547                 e.Handled = this.expressionEditorInstance.QuickInfo();
1548             }
1549             else
1550             {
1551                 e.Handled = false;
1552             }
1553
1554         }
1555
1556         public override void OnDecreaseFilterLevelCommandExecute(ExecutedRoutedEventArgs e)
1557         {
1558             if (this.expressionEditorInstance != null)
1559             {
1560                 e.Handled = this.expressionEditorInstance.DecreaseFilterLevel();
1561             }
1562             else
1563             {
1564                 e.Handled = false;
1565             }
1566
1567         }
1568
1569         public override void OnIncreaseFilterLevelCommandExecute(ExecutedRoutedEventArgs e)
1570         {
1571             if (this.expressionEditorInstance != null)
1572             {
1573                 e.Handled = this.expressionEditorInstance.IncreaseFilterLevel();
1574             }
1575             else
1576             {
1577                 e.Handled = false;
1578             }
1579
1580         }
1581
1582         void OnCutCommandExecute(object sender, ExecutedRoutedEventArgs e)
1583         {
1584             if (this.expressionEditorInstance != null)
1585             {
1586                 e.Handled = this.expressionEditorInstance.Cut();
1587             }
1588             else
1589             {
1590                 e.Handled = false;
1591             }
1592         }
1593
1594         void OnCopyCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
1595         {
1596             if (this.expressionEditorInstance != null)
1597             {
1598                 e.CanExecute = this.expressionEditorInstance.CanCopy();
1599                 e.Handled = true;
1600             }
1601             else
1602             {
1603                 e.Handled = false;
1604             }
1605         }
1606
1607         void OnCopyCommandExecute(object sender, ExecutedRoutedEventArgs e)
1608         {
1609             if (this.expressionEditorInstance != null)
1610             {
1611                 e.Handled = this.expressionEditorInstance.Copy();
1612             }
1613             else
1614             {
1615                 e.Handled = false;
1616             }
1617         }
1618
1619         void OnPasteCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
1620         {
1621             if (this.expressionEditorInstance != null)
1622             {
1623                 e.CanExecute = this.expressionEditorInstance.CanPaste();
1624                 e.Handled = true;
1625             }
1626             else
1627             {
1628                 e.Handled = false;
1629             }
1630         }
1631
1632         void OnPasteCommandExecute(object sender, ExecutedRoutedEventArgs e)
1633         {
1634             if (this.expressionEditorInstance != null)
1635             {
1636                 e.Handled = this.expressionEditorInstance.Paste();
1637             }
1638             else
1639             {
1640                 e.Handled = false;
1641             }
1642         }
1643
1644         void OnUndoCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
1645         {
1646             if (this.expressionEditorInstance != null)
1647             {
1648                 e.CanExecute = this.expressionEditorInstance.CanUndo();
1649                 e.Handled = true;
1650             }
1651             else
1652             {
1653                 e.Handled = false;
1654             }
1655         }
1656
1657         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
1658             Justification = "Catch all execeptions to prevent crash.")]
1659         [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
1660             Justification = "Catch all execeptions to prevent crash.")]
1661         void OnUndoCommandExecute(object sender, ExecutedRoutedEventArgs e)
1662         {
1663             if (this.expressionEditorInstance != null)
1664             {
1665                 try
1666                 {
1667                     e.Handled = this.expressionEditorInstance.Undo();
1668                 }
1669                 catch (Exception ex)
1670                 {
1671                     MessageBox.Show(ex.Message);
1672                 }
1673             }
1674             else
1675             {
1676                 e.Handled = false;
1677             }
1678         }
1679
1680         void OnRedoCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
1681         {
1682             if (this.expressionEditorInstance != null)
1683             {
1684                 e.CanExecute = this.expressionEditorInstance.CanRedo();
1685                 e.Handled = true;
1686             }
1687             else
1688             {
1689                 e.Handled = false;
1690             }
1691         }
1692
1693         void OnRedoCommandExecute(object sender, ExecutedRoutedEventArgs e)
1694         {
1695             if (this.expressionEditorInstance != null)
1696             {
1697                 e.Handled = this.expressionEditorInstance.Redo();
1698             }
1699             else
1700             {
1701                 e.Handled = false;
1702             }
1703         }
1704
1705         void OnHelpExecute(object sender, ExecutedRoutedEventArgs e)
1706         {
1707             IIntegratedHelpService help = this.Context.Services.GetService<IIntegratedHelpService>();
1708             if (help != null)
1709             {
1710                 help.ShowHelpFromKeyword(HelpKeywords.ExpressionEditorPage);
1711             }
1712             else
1713             {
1714                 System.Diagnostics.Process.Start(SR.DefaultHelpUrl);
1715             }
1716         }
1717
1718         #endregion
1719
1720         void OnHintTextChanged(DependencyPropertyChangedEventArgs e)
1721         {
1722             if (!string.Equals(SR.ExpressionDefaultText, e.NewValue) && !string.Equals(e.OldValue, e.NewValue))
1723             {
1724                 this.InitializeHintText();
1725             }
1726         }
1727
1728         void OnAcceptsReturnChanged(DependencyPropertyChangedEventArgs e)
1729         {
1730             if (this.expressionEditorInstance != null)
1731             {
1732                 this.expressionEditorInstance.AcceptsReturn = (bool)e.NewValue;
1733             }
1734         }
1735
1736         void OnAcceptsTabChanged(DependencyPropertyChangedEventArgs e)
1737         {
1738             if (this.expressionEditorInstance != null)
1739             {
1740                 this.expressionEditorInstance.AcceptsTab = (bool)e.NewValue;
1741             }
1742         }
1743
1744         void StartValidator()
1745         {
1746             if (this.validator == null)
1747             {
1748                 this.validator = new BackgroundWorker();
1749                 this.validator.WorkerReportsProgress = true;
1750                 this.validator.WorkerSupportsCancellation = true;
1751
1752                 this.validator.DoWork += delegate(object obj, DoWorkEventArgs args)
1753                 {
1754                     BackgroundWorker worker = obj as BackgroundWorker;
1755                     if (worker.CancellationPending)
1756                     {
1757                         args.Cancel = true;
1758                         return;
1759                     }
1760                     ExpressionValidationContext validationContext = args.Argument as ExpressionValidationContext;
1761                     if (validationContext != null)
1762                     {
1763                         string errorMessage;
1764                         if (DoValidation(validationContext, out errorMessage))
1765                         {
1766                             worker.ReportProgress(0, errorMessage);
1767                         }
1768
1769                         //sleep
1770                         if (worker.CancellationPending)
1771                         {
1772                             args.Cancel = true;
1773                             return;
1774                         }
1775
1776                         Thread.Sleep(ValidationWaitTime);
1777                         args.Result = validationContext;
1778                     }
1779
1780                 };
1781
1782                 this.validator.RunWorkerCompleted += delegate(object obj, RunWorkerCompletedEventArgs args)
1783                 {
1784                     if (!args.Cancelled)
1785                     {
1786                         ExpressionValidationContext validationContext = args.Result as ExpressionValidationContext;
1787                         if (validationContext != null)
1788                         {
1789                             Dispatcher.BeginInvoke(new Action<ExpressionValidationContext>((target) =>
1790                             {
1791                                 //validator could be null by the time we try to validate again or
1792                                 //if it's already busy
1793                                 if (this.validator != null && !this.validator.IsBusy)
1794                                 {
1795                                     target.Update(this);
1796                                     this.validator.RunWorkerAsync(target);
1797                                 }
1798                             }), validationContext);
1799                         }
1800                     }
1801                 };
1802
1803                 this.validator.ProgressChanged += delegate(object obj, ProgressChangedEventArgs args)
1804                 {
1805                     string error = args.UserState as string;
1806                     Dispatcher.BeginInvoke(new Action<string>(UpdateValidationError), error);
1807                 };
1808
1809                 this.validator.RunWorkerAsync(new ExpressionValidationContext(this));
1810             }
1811         }
1812
1813         //perform one validation synchronously
1814         //return value indicates whether errorMessage is updated.
1815         [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
1816             Justification = "The entered expression might be invalid and may throw on deserialization. Propagating exception might lead to VS crash")]
1817         [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
1818             Justification = "The entered expression might be invalid and may throw on deserialization. Propagating exception might lead to VS crash")]
1819         bool DoValidation(ExpressionValidationContext validationContext, out string errorMessage)
1820         {
1821             Fx.Assert(validationContext != null, "only work when context is not null");
1822             errorMessage = null;
1823
1824             //validate
1825             //if the text is empty we clear the error message
1826             if (string.IsNullOrEmpty(validationContext.ExpressionText))
1827             {
1828                 errorMessage = null;
1829                 return true;
1830             }
1831             // if the expression text is different from the last time we run the validation we run the validation
1832             else if (!string.Equals(validationContext.ExpressionText, validationContext.ValidatedExpressionText))
1833             {
1834                 Type expReturnType = null;
1835                 string newExpressionText = null;
1836                 SourceExpressionException compileErrorMessages = null;
1837                 VisualBasicSettings settings = null;
1838                 try
1839                 {
1840                     CreateVBExpression(validationContext, out newExpressionText, out expReturnType, out compileErrorMessages, out settings);
1841                     if (compileErrorMessages != null)
1842                     {
1843                         errorMessage = compileErrorMessages.Message;
1844                     }
1845                 }
1846                 catch (Exception err)
1847                 {
1848                     errorMessage = err.Message;
1849                 }
1850
1851                 return true;
1852             }
1853
1854             return false;
1855         }
1856
1857         void UpdateValidationError(string errorMessage)
1858         {
1859             if (!string.IsNullOrEmpty(errorMessage))
1860             {
1861                 //report error
1862                 this.HasValidationError = true;
1863                 this.ValidationErrorMessage = errorMessage;
1864             }
1865             else
1866             {
1867                 this.HasValidationError = false;
1868                 this.ValidationErrorMessage = null;
1869             }
1870         }
1871
1872         private class ExpressionValidationContext
1873         {
1874             internal ParserContext ParserContext { get; set; }
1875             internal Type ExpressionType { get; set; }
1876             internal String ExpressionText { get; set; }
1877             internal EditingContext EditingContext { get; set; }
1878             internal String ValidatedExpressionText { get; set; }
1879             internal bool UseLocationExpression { get; set; }
1880
1881             internal ExpressionValidationContext(VisualBasicEditor etb)
1882             {
1883                 Update(etb);
1884             }
1885
1886             internal void Update(VisualBasicEditor etb)
1887             {
1888                 Fx.Assert(etb.OwnerActivity != null, "Owner Activity is null");
1889                 this.EditingContext = etb.OwnerActivity.GetEditingContext();
1890
1891                 //setup ParserContext
1892                 this.ParserContext = new ParserContext(etb.OwnerActivity)
1893                 {
1894                     //callee is a ExpressionTextBox
1895                     Instance = etb,
1896                     //pass property descriptor belonging to epression's model property (if one exists)
1897                     PropertyDescriptor = (null != etb.expressionModelProperty ? ((ModelPropertyImpl)etb.expressionModelProperty).PropertyDescriptor : null),
1898                 };
1899
1900                 this.ExpressionType = etb.ExpressionType;
1901                 this.ValidatedExpressionText = this.ExpressionText;
1902                 if (etb.expressionEditorInstance != null)
1903                 {
1904                     this.ExpressionText = etb.expressionEditorInstance.Text;
1905                 }
1906                 else if (etb.editingTextBox != null)
1907                 {
1908                     this.ExpressionText = etb.editingTextBox.Text;
1909                 }
1910                 else
1911                 {
1912                     this.ExpressionText = etb.Text;
1913                 }
1914                 this.UseLocationExpression = etb.UseLocationExpression;
1915             }
1916
1917             internal IEnumerable<string> ReferencedAssemblies
1918             {
1919                 get
1920                 {
1921                     Fx.Assert(this.EditingContext != null, "ModelItem.Context = null");
1922                     AssemblyContextControlItem assemblyContext = this.EditingContext.Items.GetValue<AssemblyContextControlItem>();
1923                     if (assemblyContext != null)
1924                     {
1925                         return assemblyContext.AllAssemblyNamesInContext;
1926                     }
1927                     return null;
1928                 }
1929             }
1930         }
1931
1932         private static List<ModelItem> GetVariablesInScopeWithShadowing(ModelItem ownerActivity, bool includeArguments)
1933         {
1934             List<ModelItem> variablesInScope = new List<ModelItem>();
1935             if (ownerActivity != null)
1936             {
1937                 HashSet<string> variableNames = new HashSet<string>();
1938                 ModelItem currentItem = ownerActivity;
1939                 Func<ModelItem, bool> filterDelegate = new Func<ModelItem, bool>((variable) =>
1940                     {
1941                         string variableName = (string)variable.Properties["Name"].ComputedValue;
1942                         if (variableName == null)
1943                         {
1944                             return false;
1945                         }
1946                         else
1947                         {
1948                             return !variableNames.Contains(variableName.ToUpperInvariant());
1949                         }
1950                     });
1951
1952                 while (currentItem != null)
1953                 {
1954                     List<ModelItem> variables = new List<ModelItem>();
1955                     ModelItemCollection variablesCollection = currentItem.GetVariableCollection();
1956                     if (variablesCollection != null)
1957                     {
1958                         variables.AddRange(variablesCollection);
1959                     }
1960                     variables.AddRange(currentItem.FindActivityDelegateArguments());
1961
1962                     // For the variables defined at the same level, shadowing doesn't apply. If there're multiple variables defined at the same level
1963                     // have duplicate names when case is ignored, all of these variables should bee added as variables in scope and let validation reports
1964                     // ambiguous reference error. So that we need to scan all variables defined at the same level first and then add names to the HashSet.                                        
1965                     IEnumerable<ModelItem> filteredVariables = variables.Where<ModelItem>(filterDelegate);
1966                     variablesInScope.AddRange(filteredVariables);
1967                     foreach (ModelItem variable in filteredVariables)
1968                     {
1969                         variableNames.Add(((string)variable.Properties["Name"].ComputedValue).ToUpperInvariant());
1970                     }
1971
1972                     currentItem = currentItem.Parent;
1973                 }
1974
1975                 if (includeArguments)
1976                 {
1977                     List<ModelItem> arguments = VisualBasicEditor.GetVariablesForArguments(ownerActivity.Root);
1978                     variablesInScope.AddRange(arguments.Where<ModelItem>(filterDelegate));
1979                 }
1980             }
1981
1982             return variablesInScope;
1983         }
1984
1985         private static List<ModelItem> GetVariablesForArguments(ModelItem modelItem)
1986         {
1987             List<ModelItem> arguments = new List<ModelItem>();
1988             //if expression editor is loaded in the WF which is hosted within ActivityBuilder, there is a need to pickup defined arguments
1989             //and feed them as variables, so intellisense can include them
1990             if (null != modelItem && ActivityBuilderHelper.IsActivityBuilderType(modelItem))
1991             {
1992                 ModelTreeManager treeManager = ((IModelTreeItem)modelItem).ModelTreeManager;
1993                 //call ActivityBuilderHelper.GetVariables - it will create a collection of Variable - each variable corresponds to a specific argument
1994                 arguments.AddRange(
1995                     ActivityBuilderHelper.GetVariables(modelItem)
1996                     //create a fake model item implementation - there is no need to store that model item anywhere in the model tree, it is required
1997                     //of the expression editor interface to pass instances of model items wrapping variables, rather than actual variables
1998                     .Select<Variable, ModelItem>(entry => new FakeModelItemImpl(treeManager, typeof(Variable), entry, null)));
1999             }
2000
2001             return arguments;
2002         }
2003
2004         internal static List<ModelItem> GetVariablesInScope(ModelItem ownerActivity)
2005         {
2006             List<ModelItem> declaredVariables = new List<ModelItem>();
2007             if (ownerActivity != null)
2008             {
2009                 bool includeArguments = !(ownerActivity.GetCurrentValue() is ActivityBuilder);
2010                 FrameworkName targetFramework = WorkflowDesigner.GetTargetFramework(ownerActivity.GetEditingContext());
2011                 if ((targetFramework != null) && (targetFramework.IsLessThan45()))
2012                 {
2013                     declaredVariables.AddRange(VariableHelper.FindVariablesInScope(ownerActivity));
2014                     declaredVariables.AddRange(VariableHelper.FindActivityDelegateArgumentsInScope(ownerActivity));
2015                     if (includeArguments)
2016                     {
2017                         declaredVariables.AddRange(VisualBasicEditor.GetVariablesForArguments(ownerActivity.Root));
2018                     }
2019                 }
2020                 else
2021                 {
2022                     declaredVariables.AddRange(VisualBasicEditor.GetVariablesInScopeWithShadowing(ownerActivity, includeArguments));
2023                 }
2024             }
2025
2026             return declaredVariables;
2027         }
2028     }
2029
2030     internal sealed class LineToHeightConverter : IMultiValueConverter
2031     {
2032         public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
2033         {
2034             double convertedValue = Double.NaN;
2035             bool isDefault = true;
2036
2037             // Calculate the height for the textblock as ExpressionTextBox exposes lines properties,
2038             // and TextBlock doesn't have lines properties.
2039             FontFamily fontFamily = values.OfType<FontFamily>().FirstOrDefault();
2040             int lines = values.OfType<int>().FirstOrDefault();
2041             double[] doubleArray = values.OfType<double>().ToArray<double>();
2042
2043             if (doubleArray.Length == 2)
2044             {
2045                 double height = doubleArray[0]; // The first element of the array is going to be the height
2046                 double fontSize = doubleArray[1]; // The seconed element of the array is going to be the fontSize
2047
2048                 // 0.0 is default for MinHeight, PositiveInfinity is default for MaxHeight
2049                 if (string.Equals(parameter as string, "MinHeight"))
2050                 {
2051                     isDefault = (height == 0.0);
2052                 }
2053                 else if (string.Equals(parameter as string, "MaxHeight"))
2054                 {
2055                     isDefault = (double.IsPositiveInfinity(height));
2056                 }
2057
2058                 // If the height value we are evaluating is default, use Lines for sizing...
2059                 // If no heights (height or lines) have been explicitly specified, we would rather default the height
2060                 // as if the Line was 1 - so use the line heights, rather than 0.0 and/or PositiveInfinity.
2061                 if (isDefault)
2062                 {
2063                     double lineHeight = fontSize * fontFamily.LineSpacing;
2064
2065                     if (fontFamily != null)
2066                     {
2067                         convertedValue = lineHeight * (double)lines + 4;
2068                     }
2069                 }
2070                 else
2071                 {
2072                     convertedValue = height;
2073                 }
2074             }
2075
2076             return convertedValue;
2077         }
2078
2079         public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
2080         {
2081             throw FxTrace.Exception.AsError(new NotSupportedException());
2082         }
2083     }
2084
2085     internal sealed class ValidationStateToErrorConverter : IMultiValueConverter
2086     {
2087
2088         #region IMultiValueConverter Members
2089
2090         public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
2091         {
2092             VisualBasicEditor etb = values[0] as VisualBasicEditor;
2093             if (values[0] == DependencyProperty.UnsetValue || etb == null)
2094             {
2095                 return false;
2096             }
2097             return etb.HasErrors;
2098         }
2099
2100         public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
2101         {
2102             throw FxTrace.Exception.AsError(new NotImplementedException());
2103         }
2104
2105         #endregion
2106     }
2107
2108     internal sealed class ValidationErrorMessageConverter : IMultiValueConverter
2109     {
2110         #region IMultiValueConverter Members
2111
2112         public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
2113         {
2114             VisualBasicEditor etb = values[0] as VisualBasicEditor;
2115             if (values[0] == DependencyProperty.UnsetValue || etb == null)
2116             {
2117                 return false;
2118             }
2119             return etb.ErrorMessage;
2120         }
2121
2122         public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
2123         {
2124             throw FxTrace.Exception.AsError(new NotImplementedException());
2125         }
2126
2127         #endregion
2128     }
2129
2130     internal sealed class TypeToPromptTextConverter : IValueConverter
2131     {
2132         #region IValueConverter Members
2133
2134         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
2135         {
2136             return TypeToPromptTextConverter.GetPromptText(value);
2137         }
2138
2139         internal static string GetPromptText(object value)
2140         {
2141             Type expressionType = value as Type;
2142             if (value == DependencyProperty.UnsetValue || expressionType == null || !expressionType.IsValueType)
2143             {
2144                 return "Nothing";
2145             }
2146             else
2147             {
2148                 return Activator.CreateInstance(expressionType).ToString();
2149             }
2150         }
2151
2152         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
2153         {
2154             throw FxTrace.Exception.AsError(new NotSupportedException());
2155         }
2156
2157         #endregion
2158     }
2159
2160
2161     public enum EditingState
2162     {
2163         Editing,
2164         Validating,
2165         Idle
2166     }
2167 }