a612f5e00a4448be93b269f518b16ac0c45be0c5
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / View / ActivityTypeResolver.xaml.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4 namespace System.Activities.Presentation.View
5 {
6     using System;
7     using System.Collections.ObjectModel;
8     using System.Diagnostics.CodeAnalysis;
9     using System.Runtime;
10     using System.Windows;
11     using System.Windows.Automation.Peers;
12     using System.Windows.Controls;
13     using System.Windows.Input;
14     using System.Windows.Media;
15     using Microsoft.Activities.Presentation;
16
17     // This class is used to resolve generic type in case when a generic activity is 
18     // dropped on design surface
19     internal partial class ActivityTypeResolver : DialogWindow
20     {
21         public static readonly DependencyProperty GenericTypeMappingProperty =
22             DependencyProperty.Register("GenericTypeMapping",
23             typeof(ObservableCollection<TypeKeyValue>),
24             typeof(ActivityTypeResolver));
25
26         public static readonly DependencyProperty EditedTypeProperty =
27             DependencyProperty.Register("EditedType",
28             typeof(Type),
29             typeof(ActivityTypeResolver),
30             new PropertyMetadata(new PropertyChangedCallback(OnEditedTypeChanged)));
31
32         static readonly DependencyPropertyKey IsTypeResolvedKey =
33             DependencyProperty.RegisterReadOnly("IsTypeResolved",
34             typeof(bool),
35             typeof(ActivityTypeResolver),
36             new PropertyMetadata(false));
37
38         public static readonly DependencyProperty IsTypeResolvedProperty = IsTypeResolvedKey.DependencyProperty;
39
40         public ActivityTypeResolver()
41         {
42             InitializeComponent();
43             this.HelpKeyword = HelpKeywords.ActivityTypeResolver;
44         }
45
46         protected override void OnInitialized(EventArgs e)
47         {
48             base.OnInitialized(e);
49             SetValue(GenericTypeMappingProperty, new ObservableCollection<TypeKeyValue>());
50             this.Title = SR.TypeResolverWindowTitle;
51             this.typeResolver.Focus();
52
53         }
54
55         public Type ConcreteType
56         {
57             get;
58             private set;
59         }
60
61
62
63         public Type EditedType
64         {
65             get { return (Type)GetValue(EditedTypeProperty); }
66             set { SetValue(EditedTypeProperty, value); }
67         }
68
69         public ObservableCollection<TypeKeyValue> GenericTypeMapping
70         {
71             get { return (ObservableCollection<TypeKeyValue>)GetValue(GenericTypeMappingProperty); }
72             set { SetValue(GenericTypeMappingProperty, value); }
73         }
74
75         public bool IsTypeResolved
76         {
77             get { return (bool)GetValue(IsTypeResolvedProperty); }
78             private set { SetValue(IsTypeResolvedKey, value); }
79         }
80
81         public TypeResolvingOptions Options
82         {
83             get;
84             set;
85         }
86
87         [SuppressMessage(FxCop.Category.Design, FxCop.Rule.DoNotCatchGeneralExceptionTypes,
88             Justification = "Catching all exceptions to avoid VS Crash")]
89         [SuppressMessage("Reliability", "Reliability108", Justification = "Catching all exceptions to avoid VS Crash")]
90         public void NotifyTypeChanged(TypeKeyValue sender)
91         {
92             this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.ApplicationIdle,
93                     new Action(() =>
94                     {
95                         try
96                         {
97                             IsTypeResolved = (null != ResolveType() ? true : false);
98                             ClearError();
99                         }
100                         catch (Exception err)
101                         {
102                             SetError(err.Message);
103                             IsTypeResolved = false;
104                         }
105                     }));
106         }
107
108         private void SetError(string message)
109         {
110             if (this.GenericTypeMapping != null)
111             {
112                 foreach (TypeKeyValue tkv in this.GenericTypeMapping)
113                 {
114                     tkv.IsValid = false;
115                     tkv.ErrorText = message;
116                 }
117             }
118         }
119
120         private void ClearError()
121         {
122             if (this.GenericTypeMapping != null)
123             {
124                 foreach (TypeKeyValue tkv in this.GenericTypeMapping)
125                 {
126                     tkv.IsValid = true;
127                     tkv.ErrorText = null;
128                 }
129             }
130         }
131
132
133         protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
134         {
135             return new UIElementAutomationPeer(this);
136         }
137
138         static void OnEditedTypeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
139         {
140             ActivityTypeResolver resolver = (ActivityTypeResolver)sender;
141             resolver.OnEditTypeAssigned();
142         }
143
144         void OnCancelClick(object sender, RoutedEventArgs e)
145         {
146             DialogResult = false;
147         }
148
149         void OnEditTypeAssigned()
150         {
151             if (null != this.EditedType && this.EditedType.IsGenericTypeDefinition)
152             {
153                 this.typeName.Text = TypeNameHelper.GetDisplayName(this.EditedType, false);
154
155                 Type[] generics = this.EditedType.GetGenericArguments();
156                 foreach (Type type in generics)
157                 {
158                     Type temp = type; // reference this temp variable instead of reference type in the anonymous delegate
159                     TypeKeyValue tkv = new TypeKeyValue(type, new Action<TypeKeyValue>(NotifyTypeChanged))
160                                     {
161                                         IsSelected = false,
162                                         Filter = delegate(Type t)
163                                         {
164                                             if (!TypeUtilities.CanSubstituteGenericParameter(temp, t))
165                                             {
166                                                 return false;
167                                             }
168                                             
169                                             return this.Options == null
170                                                 || this.Options.Filter == null
171                                                 || this.Options.Filter(t);
172                                         },
173                                         MostRecentlyUsedTypes = this.Options != null ? this.Options.MostRecentlyUsedTypes : null,
174                                     };
175                     string hintText = null;
176                     if (this.Options != null && this.Options.HintTextMap.TryGetValue(type.Name, out hintText))
177                     {
178                         tkv.HintText = hintText;
179                     }
180
181                     this.GenericTypeMapping.Add(tkv);
182
183                     if (this.Options == null || !this.Options.BrowseTypeDirectly)
184                     {
185                         tkv.BrowseTypeDirectly = false;
186                         //this has to happen after the tkv is added GenericTypeMapping because:
187                         //when TargetType is set, TypeResolver will try to resolve the generic type with this TargetType as type argument,
188                         //and when resolvig the type, TypeResolver needs to know all the mappings                        
189                         if (tkv.MostRecentlyUsedTypes == null)
190                         {
191                             if (tkv.Filter == null || tkv.Filter(typeof(int)))
192                             {
193                                 tkv.TargetType = typeof(int);
194                             }
195                         }
196                         else if (tkv.MostRecentlyUsedTypes.Contains(typeof(int)))
197                         {
198                             tkv.TargetType = typeof(int);
199                         }
200                         else if (tkv.MostRecentlyUsedTypes.Count > 0)
201                         {
202                             tkv.TargetType = tkv.MostRecentlyUsedTypes[0];
203                         }
204                     }
205                 }
206             }
207         }
208
209         void OnOkClick(object sender, RoutedEventArgs e)
210         {
211             try
212             {
213                 Type type = ResolveType();
214                 if (null != type)
215                 {
216                     this.ConcreteType = type;
217                     DialogResult = true;
218                 }
219                 else
220                 {
221                     MessageBox.Show(SR.TypeResolverError, SR.TypeResolverErrorMessageTitle, MessageBoxButton.OK, MessageBoxImage.Error);
222                 }
223             }
224             catch (ArgumentException err)
225             {
226                 MessageBox.Show(err.Message, err.GetType().Name, MessageBoxButton.OK, MessageBoxImage.Error);
227             }
228         }
229
230         void TypeKeyDown(object sender, KeyEventArgs e)
231         {
232             if (TypePresenter.IsPreviewKey(e.Key))
233             {
234                 ListViewItem typeView = (ListViewItem)sender;
235                 //always focus on the type presenter so the presenter could handle keyboard events
236                 TypePresenter typePresenter = FindChildElement<TypePresenter>(typeView);
237                 if (typePresenter != null)
238                 {
239                     typePresenter.Preview();
240                 }
241                 e.Handled = true;
242             }
243         }
244
245         ChildType FindChildElement<ChildType>(DependencyObject tree) where ChildType : DependencyObject
246         {
247             //recursively traverse the visual tree and find the element of a given type
248             for (int i = 0; i < VisualTreeHelper.GetChildrenCount(tree); i++)
249             {
250                 DependencyObject child = VisualTreeHelper.GetChild(tree, i);
251                 if (child != null && child is ChildType)
252                 {
253                     return child as ChildType;
254                 }
255                 else
256                 {
257                     ChildType childInSubtree = FindChildElement<ChildType>(child);
258                     if (childInSubtree != null)
259                     {
260                         return childInSubtree;
261                     }
262                 }
263             }
264
265             return null;
266         }
267
268         Type ResolveType()
269         {
270             Type result = null;
271             bool isValid = true;
272             //get number of generic parameters in edited type
273             Type[] arguments = new Type[this.GenericTypeMapping.Count];
274
275             //for each argument, get resolved type
276             for (int i = 0; i < this.GenericTypeMapping.Count && isValid; ++i)
277             {
278                 arguments[i] = this.GenericTypeMapping[i].GetConcreteType();
279                 isValid = isValid && (null != arguments[i]);
280             }
281             //if all parameters are resolved, create concrete type
282             if (isValid)
283             {
284                 result = this.EditedType.MakeGenericType(arguments);
285             }
286             return result;
287         }
288     }
289
290 }