[reflection] Coop handles icalls in System.Reflection and System.RuntimeTypeHandle...
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / View / TypePresenter.xaml.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4
5 namespace System.Activities.Presentation.View
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.Collections.ObjectModel;
10     using System.Collections.Specialized;
11     using System.ComponentModel;
12     using System.Globalization;
13     using System.Linq;
14     using System.Windows;
15     using System.Windows.Automation.Peers;
16     using System.Windows.Controls;
17     using System.Windows.Data;
18     using System.Windows.Input;
19     using System.Runtime;
20     using System.Windows.Automation;
21     using System.Diagnostics.CodeAnalysis;
22     using System.Windows.Threading;
23     using System.Activities.Presentation.Hosting;
24     using Microsoft.Activities.Presentation;
25
26     // This control presents a System.Type as textblock, which is editable on click, or F2.
27     public sealed partial class TypePresenter : ContentControl, INotifyPropertyChanged
28     {
29         public static readonly DependencyProperty ContextProperty =
30             DependencyProperty.Register("Context",
31             typeof(EditingContext),
32             typeof(TypePresenter),
33             new PropertyMetadata(new PropertyChangedCallback(OnContextChanged)));
34
35         public static readonly DependencyProperty AllowNullProperty =
36             DependencyProperty.Register("AllowNull",
37             typeof(bool),
38             typeof(TypePresenter),
39             new PropertyMetadata(false, OnAllowNullChanged));
40
41         public static readonly DependencyProperty BrowseTypeDirectlyProperty =
42             DependencyProperty.Register("BrowseTypeDirectly",
43             typeof(bool),
44             typeof(TypePresenter),
45             new PropertyMetadata(false, OnBrowseTypeDirectlyChanged));
46
47         public static readonly DependencyProperty TypeProperty =
48             DependencyProperty.Register("Type",
49             typeof(Type),
50             typeof(TypePresenter),
51             new PropertyMetadata(null, new PropertyChangedCallback(OnTypeChanged)));
52
53         public static readonly DependencyProperty LabelProperty =
54             DependencyProperty.Register("Label",
55             typeof(string),
56             typeof(TypePresenter),
57             new PropertyMetadata(string.Empty));
58
59         public static readonly DependencyProperty FilterProperty =
60             DependencyProperty.Register("Filter",
61             typeof(Func<Type, bool>),
62             typeof(TypePresenter),
63             new PropertyMetadata(new PropertyChangedCallback(OnFilterChanged)));
64
65         static readonly DependencyPropertyKey TextPropertyKey = DependencyProperty.RegisterReadOnly(
66             "Text",
67             typeof(string),
68             typeof(TypePresenter),
69             new UIPropertyMetadata(null));
70
71         public static readonly DependencyProperty TextProperty = TextPropertyKey.DependencyProperty;
72
73         public static readonly DependencyProperty MostRecentlyUsedTypesProperty =
74             DependencyProperty.Register("MostRecentlyUsedTypes",
75             typeof(ObservableCollection<Type>),
76             typeof(TypePresenter),
77             new PropertyMetadata(TypePresenter.DefaultMostRecentlyUsedTypes, new PropertyChangedCallback(OnMostRecentlyUsedTypesPropertyChanged), new CoerceValueCallback(OnCoerceMostRecentlyUsedTypes)));
78
79         public static readonly DependencyProperty CenterActivityTypeResolverDialogProperty =
80             DependencyProperty.Register("CenterActivityTypeResolverDialog",
81             typeof(bool),
82             typeof(TypePresenter),
83             new PropertyMetadata(true));
84
85         public static readonly DependencyProperty CenterTypeBrowserDialogProperty =
86             DependencyProperty.Register("CenterTypeBrowserDialog",
87             typeof(bool),
88             typeof(TypePresenter),
89             new PropertyMetadata(true));
90
91         public static readonly RoutedEvent TypeBrowserOpenedEvent = EventManager.RegisterRoutedEvent(
92             "TypeBrowserOpened",
93             RoutingStrategy.Bubble,
94             typeof(RoutedEventHandler),
95             typeof(TypePresenter));
96
97         public static readonly RoutedEvent TypeBrowserClosedEvent = EventManager.RegisterRoutedEvent(
98             "TypeBrowserClosed",
99             RoutingStrategy.Bubble,
100             typeof(RoutedEventHandler),
101             typeof(TypePresenter));
102
103         public static readonly RoutedEvent TypeChangedEvent = EventManager.RegisterRoutedEvent(
104             "TypeChanged",
105             RoutingStrategy.Bubble,
106             typeof(RoutedEventHandler),
107             typeof(TypePresenter));
108
109         static List<Type> defaultTypes = null;
110         static ObservableCollection<Type> defaultMostRecentlyUsedTypes;
111
112         internal static List<Type> DefaultTypes
113         {
114             get
115             {
116                 if (defaultTypes == null)
117                 {
118                     defaultTypes = new List<Type>
119                     {
120                         typeof(Boolean),
121                         typeof(Int32),
122                         typeof(String),
123                         typeof(Object),
124                     };
125                 }
126                 return defaultTypes;
127             }
128         }
129
130         public static ObservableCollection<Type> DefaultMostRecentlyUsedTypes
131         {
132             get
133             {
134                 if (defaultMostRecentlyUsedTypes == null)
135                 {
136                     defaultMostRecentlyUsedTypes = new ObservableCollection<Type>(DefaultTypes);
137                 }
138                 return defaultMostRecentlyUsedTypes;
139             }
140         }
141
142         [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.CollectionPropertiesShouldBeReadOnly,
143             Justification = "Setter is provided to bind data on this property.")]
144         [Fx.Tag.KnownXamlExternal]
145         public ObservableCollection<Type> MostRecentlyUsedTypes
146         {
147             get { return (ObservableCollection<Type>)GetValue(MostRecentlyUsedTypesProperty); }
148             set { SetValue(MostRecentlyUsedTypesProperty, value); }
149         }
150
151         bool isMouseLeftButtonDown = true;
152         Type lastSelection;
153         TypeWrapper nullTypeWrapper = null;
154
155         public TypePresenter()
156         {
157             InitializeComponent();
158
159             OnBrowseTypeDirectlyChanged(this, new DependencyPropertyChangedEventArgs(
160                 TypePresenter.BrowseTypeDirectlyProperty, false, this.BrowseTypeDirectly));
161             DisableEdit();
162
163             this.typeComboBox.DropDownClosed += OnTypePresenterDropDownClosed;
164             this.typeComboBox.PreviewLostKeyboardFocus += OnTypePresenterComboBoxPreviewLostKeyboardFocus;
165             this.typeComboBox.LostFocus += OnTypePresenterComboBoxLostFocus;
166             this.typeComboBox.KeyDown += OnTypePresenterKeyDown;
167
168             Binding textToType = new Binding();
169             textToType.Converter = new TypeWrapperConverter(this);
170             textToType.Source = this;
171             textToType.Path = new PropertyPath(TypeProperty);
172             this.typeComboBox.SetBinding(ComboBox.SelectedItemProperty, textToType);
173             this.lastSelection = (Type)TypeProperty.DefaultMetadata.DefaultValue;
174
175             MultiBinding automationNameBinding = new MultiBinding();
176             Binding labelBinding = new Binding("Label");
177             labelBinding.Source = this;
178             automationNameBinding.Bindings.Add(labelBinding);
179             Binding typeBinding = new Binding("Text");
180             typeBinding.Source = this.typeTextBlock;
181             automationNameBinding.Bindings.Add(typeBinding);
182             automationNameBinding.Converter = new AutomationNameConverter();
183             this.SetBinding(AutomationProperties.NameProperty, automationNameBinding);
184
185             this.Loaded += new RoutedEventHandler(TypePresenter_Loaded);
186             this.Unloaded += new RoutedEventHandler(TypePresenter_Unloaded);
187         }
188
189         void OnTypePresenterComboBoxPreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
190         {
191             if (this.typeComboBox.Visibility == Visibility.Visible && this.typeComboBox.IsDropDownOpen)
192             {
193                 e.Handled = true;
194             }
195         }
196
197         void OnTypePresenterComboBoxLostFocus(object sender, RoutedEventArgs e)
198         {
199             TypeWrapper tw = (TypeWrapper)this.typeComboBox.SelectedItem;
200             if (tw != null)
201             {
202                 if (tw.Type == typeof(ArrayOf<>) || tw.Type == typeof(BrowseForType))
203                 {
204                     SetComboBoxToLastSelection();
205                 }
206             }
207         }
208
209         void SetComboBoxToLastSelection()
210         {
211             if (this.lastSelection == null)
212             {
213                 this.typeComboBox.SelectedIndex = this.typeComboBox.Items.IndexOf(this.NullTypeWrapper);
214             }
215             else
216             {
217                 for (int i = 0; i < this.typeComboBox.Items.Count; i++)
218                 {
219                     TypeWrapper typeWrapper = (TypeWrapper)this.typeComboBox.Items.GetItemAt(i);
220                     if (typeWrapper.IsTypeDefinition && Type.Equals(this.lastSelection, typeWrapper.Type))
221                     {
222                         this.typeComboBox.SelectedIndex = i;
223                         break;
224                     }
225                 }
226             }
227         }
228
229         public void FocusOnVisibleControl()
230         {
231             if (BrowseTypeDirectly)
232             {
233                 this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)(() =>
234                 {
235                     Keyboard.Focus(this.typeTextBlock);
236                 }));
237             }
238             else
239             {
240                 this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)(() =>
241                 {
242                     Keyboard.Focus(this.typeComboBox);
243                 }));
244             }
245         }
246
247
248         void TypePresenter_Loaded(object sender, RoutedEventArgs e)
249         {
250             //UnRegistering because of 137896: Inside tab control multiple Loaded events happen without an Unloaded event.
251             this.MostRecentlyUsedTypes.CollectionChanged -= OnMostRecentlyUsedTypesChanged;
252             this.MostRecentlyUsedTypes.CollectionChanged += OnMostRecentlyUsedTypesChanged;
253             OnMostRecentlyUsedTypesChanged(this, null);
254         }
255
256         void TypePresenter_Unloaded(object sender, RoutedEventArgs e)
257         {
258             this.MostRecentlyUsedTypes.CollectionChanged -= OnMostRecentlyUsedTypesChanged;
259         }
260
261         public event RoutedEventHandler TypeBrowserOpened
262         {
263             add { this.AddHandler(TypeBrowserOpenedEvent, value); }
264             remove { this.RemoveHandler(TypeBrowserOpenedEvent, value); }
265         }
266
267         public event RoutedEventHandler TypeBrowserClosed
268         {
269             add { this.AddHandler(TypeBrowserClosedEvent, value); }
270             remove { this.RemoveHandler(TypeBrowserClosedEvent, value); }
271         }
272
273         public event RoutedEventHandler TypeChanged
274         {
275             add { this.AddHandler(TypeChangedEvent, value); }
276             remove { this.RemoveHandler(TypeChangedEvent, value); }
277         }
278
279         public event PropertyChangedEventHandler PropertyChanged;
280
281         [Fx.Tag.KnownXamlExternal]
282         public EditingContext Context
283         {
284             get { return (EditingContext)GetValue(ContextProperty); }
285             set { SetValue(ContextProperty, value); }
286         }
287
288         public bool AllowNull
289         {
290             get { return (bool)GetValue(AllowNullProperty); }
291             set { SetValue(AllowNullProperty, value); }
292         }
293
294         public string Label
295         {
296             get { return (string)GetValue(LabelProperty); }
297             set { SetValue(LabelProperty, value); }
298         }
299
300         [Fx.Tag.KnownXamlExternal]
301         public Func<Type, bool> Filter
302         {
303             get { return (Func<Type, bool>)GetValue(FilterProperty); }
304             set { SetValue(FilterProperty, value); }
305         }
306
307         public bool CenterActivityTypeResolverDialog
308         {
309             get { return (bool)GetValue(CenterActivityTypeResolverDialogProperty); }
310             set { SetValue(CenterActivityTypeResolverDialogProperty, value); }
311         }
312
313         public bool CenterTypeBrowserDialog
314         {
315             get { return (bool)GetValue(CenterTypeBrowserDialogProperty); }
316             set { SetValue(CenterTypeBrowserDialogProperty, value); }
317         }
318
319         internal TypeWrapper NullTypeWrapper
320         {
321             get
322             {
323                 if (this.nullTypeWrapper == null)
324                 {
325                     this.nullTypeWrapper = new TypeWrapper(NullString, "Null", null);
326                 }
327                 return this.nullTypeWrapper;
328             }
329         }
330
331         public string Text
332         {
333             get { return (string)GetValue(TextProperty); }
334             private set { SetValue(TextPropertyKey, value); }
335         }
336
337
338         public IEnumerable<TypeWrapper> Items
339         {
340             get
341             {
342                 if (AllowNull)
343                 {
344                     yield return this.NullTypeWrapper;
345                 }
346                 foreach (Type type in this.MostRecentlyUsedTypes)
347                 {
348                     if (type != null)
349                     {
350                         if (this.Filter == null
351                            || this.Filter(type))
352                         {
353                             yield return new TypeWrapper(type);
354                         }
355                     }
356                 }
357
358                 //display Array of [T] option
359                 if (this.Filter == null
360                     || this.Filter(typeof(Array)))
361                 {
362                     yield return new TypeWrapper("Array of [T]", "T[]", typeof(ArrayOf<>));
363                 }
364                 //display "Browse for types" option
365                 //if there are referenced and local assembly info in Editing context (inside VS), type browser will show those assemblies,
366                 //otherwise (standalone), type browser will just show all loaded assemblies in current appdomain
367                 yield return new TypeWrapper(BrowseTypeString, "BrowseForTypes", typeof(BrowseForType));
368             }
369         }
370
371         public bool BrowseTypeDirectly
372         {
373             get { return (bool)GetValue(BrowseTypeDirectlyProperty); }
374             set { SetValue(BrowseTypeDirectlyProperty, value); }
375         }
376
377
378         [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "By design.")]
379         public Type Type
380         {
381             get { return (Type)GetValue(TypeProperty); }
382             set { SetValue(TypeProperty, value); }
383         }
384
385         public string TypeName
386         {
387             get
388             {
389                 string typeName = string.Empty;
390                 this.ToolTip = null;
391                 if (null != this.Type)
392                 {
393                     typeName = ResolveTypeName(this.Type);
394                     this.ToolTip = typeName;
395                 }
396                 return typeName;
397             }
398         }
399
400         internal static string ResolveTypeName(Type type)
401         {
402             Fx.Assert(type != null, "parameter type is null!");
403             string typeName;
404             if (TypePresenter.DefaultTypes.Contains(type))
405             {
406                 typeName = type.Name;
407             }
408             else
409             {
410                 typeName = TypeNameHelper.GetDisplayName(type, true);
411             }
412             return typeName;
413         }
414
415         AssemblyContextControlItem AssemblyContext
416         {
417             get
418             {
419                 return (null != Context ? Context.Items.GetValue<AssemblyContextControlItem>() : null);
420             }
421         }
422
423         string BrowseTypeString
424         {
425             get { return (string)this.FindResource("BrowseTypeString"); }
426         }
427
428         string NullString
429         {
430             get { return "(null)"; }
431         }
432
433         protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
434         {
435             return new UIElementAutomationPeer(this);
436         }
437
438         protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
439         {
440             base.OnMouseLeftButtonDown(e);
441             this.isMouseLeftButtonDown = true;
442             e.Handled = true;
443         }
444
445         protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
446         {
447             base.OnMouseLeftButtonUp(e);
448             if (this.isMouseLeftButtonDown)
449             {
450                 if (this.BrowseTypeDirectly)
451                 {
452                     HandleBrowseType();
453                 }
454                 else
455                 {
456                     this.EnableEdit();
457                 }
458             }
459             this.isMouseLeftButtonDown = false;
460             e.Handled = true;
461         }
462
463         protected override void OnPreviewKeyDown(KeyEventArgs e)
464         {
465             base.OnPreviewKeyDown(e);
466             if (IsPreviewKey(e.Key))
467             {
468                 Preview();
469             }
470         }
471
472         internal static bool IsPreviewKey(Key key)
473         {
474             return (key == Key.F2 || key == Key.Space || key == Key.Enter);
475         }
476
477         internal void Preview()
478         {
479             if (this.BrowseTypeDirectly)
480             {
481                 HandleBrowseType();
482             }
483             else
484             {
485                 this.EnableEdit();
486             }
487         }
488
489         static void OnContextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
490         {
491             TypePresenter ctrl = (TypePresenter)sender;
492             ctrl.OnItemsChanged();
493         }
494
495         static void OnAllowNullChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
496         {
497             TypePresenter ctrl = (TypePresenter)sender;
498             ctrl.OnItemsChanged();
499         }
500
501         static void OnBrowseTypeDirectlyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
502         {
503             TypePresenter ctrl = (TypePresenter)sender;
504             if (!(bool)args.NewValue)
505             {
506                 ctrl.typeComboBox.Visibility = Visibility.Visible;
507                 ctrl.typeTextBlock.Visibility = Visibility.Collapsed;
508                 ctrl.Focusable = false;
509             }
510             else
511             {
512                 ctrl.typeComboBox.Visibility = Visibility.Collapsed;
513                 ctrl.typeTextBlock.Visibility = Visibility.Visible;
514                 ctrl.Focusable = true;
515             }
516         }
517
518         static void OnTypeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
519         {
520             TypePresenter ctrl = (TypePresenter)sender;
521             ctrl.lastSelection = (Type)args.NewValue;
522
523             if (null != ctrl.PropertyChanged)
524             {
525                 ctrl.PropertyChanged(ctrl, new PropertyChangedEventArgs("TypeName"));
526             }
527
528             if (null == ctrl.lastSelection)
529             {
530                 ctrl.typeComboBox.SelectedIndex = ctrl.typeComboBox.Items.IndexOf(ctrl.NullTypeWrapper);
531             }
532
533             ctrl.Text = ctrl.TypeName;
534             ctrl.RaiseEvent(new RoutedEventArgs(TypePresenter.TypeChangedEvent, ctrl));
535         }
536
537         static void OnFilterChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
538         {
539             TypePresenter ctrl = (TypePresenter)sender;
540             if (null != ctrl.PropertyChanged)
541             {
542                 ctrl.PropertyChanged(ctrl, new PropertyChangedEventArgs("Items"));
543             }
544         }
545
546         static void OnMostRecentlyUsedTypesPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
547         {
548             TypePresenter ctrl = (TypePresenter)sender;
549             ((ObservableCollection<Type>)args.NewValue).CollectionChanged += ctrl.OnMostRecentlyUsedTypesChanged;
550             ((ObservableCollection<Type>)args.OldValue).CollectionChanged -= ctrl.OnMostRecentlyUsedTypesChanged;
551
552             ctrl.OnItemsChanged();
553         }
554
555         static object OnCoerceMostRecentlyUsedTypes(DependencyObject sender, object value)
556         {
557             if (value != null)
558             {
559                 return value;
560             }
561             else
562             {
563                 return TypePresenter.DefaultMostRecentlyUsedTypes;
564             }
565         }
566
567         void DisableEdit()
568         {
569             if (BrowseTypeDirectly)
570             {
571                 this.typeTextBlock.Visibility = Visibility.Visible;
572                 this.typeComboBox.Visibility = Visibility.Collapsed;
573             }
574         }
575
576         void EnableEdit()
577         {
578             if (BrowseTypeDirectly)
579             {
580                 this.typeTextBlock.Visibility = Visibility.Collapsed;
581                 this.typeComboBox.Visibility = Visibility.Visible;
582             }
583             this.typeComboBox.Focus();
584         }
585
586         // return true if KeyDownEvent should be set to handled
587         bool HandleBrowseType()
588         {
589             bool retval = false;
590             TypeWrapper wrapper = (TypeWrapper)this.typeComboBox.SelectedItem;
591
592             if ((wrapper != null && !wrapper.IsTypeDefinition)
593                 || this.BrowseTypeDirectly)
594             {
595                 Type result = null;
596                 bool? dialogResult = true;
597                 bool typeIsArray = true;
598                 bool fireEvent = false;
599                 //handle choosing an array of T
600                 if (wrapper != null && typeof(ArrayOf<>) == wrapper.Type)
601                 {
602                     fireEvent = true;
603                     this.RaiseEvent(new RoutedEventArgs(TypePresenter.TypeBrowserOpenedEvent, this));
604                     result = wrapper.Type;
605                 }
606                 else if (wrapper != null && wrapper.DisplayName == NullString)
607                 {
608                     this.Type = null;
609                     return false;
610                 }
611                 else
612                 {
613                     retval = true;
614                     fireEvent = true;
615                     this.RaiseEvent(new RoutedEventArgs(TypePresenter.TypeBrowserOpenedEvent, this));
616                     TypeBrowser browser = new TypeBrowser(AssemblyContext, this.Context, this.Filter);
617                     SetWindowOwner(browser);
618                     if (this.CenterTypeBrowserDialog)
619                     {
620                         browser.WindowStartupLocation = WindowStartupLocation.CenterScreen;
621                     }
622                     dialogResult = browser.ShowDialog();
623                     if (dialogResult.HasValue && dialogResult.Value)
624                     {
625                         result = browser.ConcreteType;
626                     }
627
628                     typeIsArray = false;
629                 }
630
631                 if (dialogResult.HasValue && dialogResult.Value)
632                 {
633                     //user may have chosen generic type (IList)
634                     if (result.IsGenericTypeDefinition)
635                     {
636                         retval = true;
637                         ActivityTypeResolver wnd = new ActivityTypeResolver();
638                         SetWindowOwner(wnd);
639                         wnd.Context = this.Context;
640                         wnd.EditedType = result;
641                         if (this.CenterActivityTypeResolverDialog)
642                         {
643                             wnd.WindowStartupLocation = WindowStartupLocation.CenterScreen;
644                         }
645
646                         result = (true == wnd.ShowDialog() ? wnd.ConcreteType : null);
647                     }
648                     //if we have a type
649                     if (null != result)
650                     {
651                         //if we have a ArrayOf<some type here>, create actual array type
652                         if (typeIsArray)
653                         {
654                             result = result.GetGenericArguments()[0].MakeArrayType();
655                         }
656                         //add it to the cache
657                         if (!MostRecentlyUsedTypes.Any<Type>(p => Type.Equals(p, result)))
658                         {
659                             MostRecentlyUsedTypes.Add(result);
660                         }
661
662                         //and return updated result
663                         this.Type = result;
664                     }
665                     else
666                     {
667                         this.Type = this.lastSelection;
668                     }
669
670                     BindingExpression binding = this.typeComboBox.GetBindingExpression(ComboBox.SelectedItemProperty);
671                     binding.UpdateTarget();
672                 }
673                 else
674                 {
675                     SetComboBoxToLastSelection();
676                 }
677                 if (fireEvent)
678                 {
679                     this.RaiseEvent(new RoutedEventArgs(TypePresenter.TypeBrowserClosedEvent, this));
680                 }
681             }
682
683             return retval;
684         }
685
686         void OnMostRecentlyUsedTypesChanged(object sender, NotifyCollectionChangedEventArgs e)
687         {
688             OnItemsChanged();
689         }
690
691         void OnItemsChanged()
692         {
693             if (null != PropertyChanged)
694             {
695                 PropertyChanged(this, new PropertyChangedEventArgs("Items"));
696             }
697         }
698
699         void OnTypePresenterDropDownClosed(object sender, EventArgs e)
700         {
701             HandleBrowseType();
702             DisableEdit();
703             if (!this.BrowseTypeDirectly)
704             {
705                 this.typeComboBox.Focus();
706             }
707             else
708             {
709                 this.Focus();
710             }
711         }
712
713         void OnTypePresenterKeyDown(object sender, KeyEventArgs e)
714         {
715             if (e.Key == Key.Enter)
716             {
717                 if (HandleBrowseType())
718                 {
719                     e.Handled = true;
720                 }
721                 DisableEdit();
722
723                 FocusOnVisibleControl();
724             }
725         }
726
727         void OnTypePresenterLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
728         {
729             if (!(e.NewFocus == this))
730             {
731                 if (!(this.typeComboBox.IsDropDownOpen || this.typeComboBox.IsSelectionBoxHighlighted))
732                 {
733                     DisableEdit();
734                 }
735             }
736         }
737
738         void SetWindowOwner(Window wnd)
739         {
740             WindowHelperService.TrySetWindowOwner(this, this.Context, wnd);
741         }
742
743         // internal converter class - assign a meaningful AutomationProperties.Name to the type presenter
744         // AutomationProperties.Name = Label + the string displayed on the TypePresenter
745         sealed class AutomationNameConverter : IMultiValueConverter
746         {
747             public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
748             {
749                 Fx.Assert(values.Length == 2, "There should be exactly 2 values");
750                 return (string)values[0] + ": " + (string)values[1];
751             }
752
753             public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
754             {
755                 Fx.Assert("Not supported!");
756                 return null;
757             }
758         }
759     }
760
761     [Fx.Tag.XamlVisible(false)]
762     public sealed class TypeWrapper
763     {
764         string displayName;
765         bool isTypeDefinition;
766         Type type;
767
768         internal TypeWrapper(Type type)
769         {
770             this.type = type;
771             this.isTypeDefinition = true;
772             this.Tag = DisplayName;
773         }
774
775         internal TypeWrapper(string text, string tag, Type type)
776         {
777             this.displayName = text;
778             this.isTypeDefinition = false;
779             this.Tag = tag;
780             this.type = type;
781         }
782
783         public string DisplayName
784         {
785             get
786             {
787                 if (this.isTypeDefinition)
788                 {
789                     if (TypePresenter.DefaultTypes.Contains(this.type))
790                     {
791                         return this.type.Name;
792                     }
793
794                     return TypeNameHelper.GetDisplayName(this.Type, true);
795                 }
796                 return this.displayName;
797             }
798         }
799
800         public bool IsTypeDefinition
801         {
802             get { return this.isTypeDefinition; }
803         }
804
805         public object Tag
806         {
807             get;
808             private set;
809         }
810
811         [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "By design.")]
812         public Type Type
813         {
814             get { return this.type; }
815         }
816
817         public override string ToString()
818         {
819             return Tag as string;
820         }
821
822         public override bool Equals(object obj)
823         {
824             TypeWrapper that = obj as TypeWrapper;
825             if (that == null)
826             {
827                 return false;
828             }
829             if (that.IsTypeDefinition ^ this.IsTypeDefinition)
830             {
831                 return false;
832             }
833             if (this.displayName != that.displayName)
834             {
835                 return false;
836             }
837             return object.Equals(this.Type, that.Type);
838         }
839
840         public override int GetHashCode()
841         {
842             if (this.Type != null)
843             {
844                 return this.Type.GetHashCode();
845             }
846             else
847             {
848                 return base.GetHashCode();
849             }
850         }
851     }
852
853     sealed class ArrayOf<T>
854     {
855     }
856
857     sealed class BrowseForType
858     {
859     }
860
861     // internal converter class - keeps link between display friendly string representation of types
862     // and actual underlying system type.
863     sealed class TypeWrapperConverter : IValueConverter
864     {
865         TypePresenter typePresenter;
866
867         //ctor - initialzied with list of loaded types into the presenter
868         internal TypeWrapperConverter(TypePresenter typePresenter)
869         {
870             this.typePresenter = typePresenter;
871         }
872
873         //convert from System.Type to TypeWrapper (display friendly)
874         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
875         {
876             if (null != value)
877             {
878                 //lookup in loaded types if type is already there
879
880                 //if no - add it to collection - may be reused later
881                 if (null == this.typePresenter.MostRecentlyUsedTypes.SingleOrDefault<Type>(p => Type.Equals(p, (Type)value)))
882                 {
883                     this.typePresenter.MostRecentlyUsedTypes.Add((Type)value);
884                 }
885
886                 return new TypeWrapper((Type)value);
887             }
888             else
889             {
890                 return this.typePresenter.NullTypeWrapper;
891             }
892         }
893
894         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
895         {
896             //convert back - just get the Type property of the wrapper object
897             TypeWrapper typeWrapper = value as TypeWrapper;
898
899             if (typeWrapper == this.typePresenter.NullTypeWrapper)
900             {
901                 return null;
902             }
903
904             if (null != typeWrapper && null != typeWrapper.Type && typeof(ArrayOf<>) != typeWrapper.Type && typeof(BrowseForType) != typeWrapper.Type)
905             {
906                 return typeWrapper.Type;
907             }
908
909             return Binding.DoNothing;
910         }
911     }
912 }