Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Activities.Core.Presentation / System / ServiceModel / Activities / Presentation / MessageQuerySetDesigner.xaml.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4 namespace System.ServiceModel.Activities.Presentation
5 {
6     using System.Activities;
7     using System.Activities.Presentation;
8     using System.Activities.Presentation.Model;
9     using System.Activities.Presentation.View;
10     using System.Collections;
11     using System.Collections.Generic;
12     using System.Collections.ObjectModel;
13     using System.Collections.Specialized;
14     using System.ComponentModel;
15     using System.Globalization;
16     using System.Linq;
17     using System.Runtime;
18     using System.ServiceModel;
19     using System.Windows;
20
21     partial class MessageQuerySetDesigner : INotifyPropertyChanged
22     {
23         static readonly string key = "key";
24         DataGridHelper messageQueriesDGHelper;
25         string querySetPropertyName = string.Empty;
26         ObservableCollection<MessageQueryEntry> dataSource = new ObservableCollection<MessageQueryEntry>();
27         public event PropertyChangedEventHandler PropertyChanged;
28
29         public static readonly DependencyProperty ActivityProperty = DependencyProperty.Register(
30             "Activity",
31             typeof(ModelItem),
32             typeof(MessageQuerySetDesigner),
33             new UIPropertyMetadata(OnActivityChanged));
34
35         public static readonly DependencyProperty MessageQuerySetContainerProperty = DependencyProperty.Register(
36             "MessageQuerySetContainer",
37             typeof(ModelItem),
38             typeof(MessageQuerySetDesigner),
39             new UIPropertyMetadata(null, OnMessageQuerySetContainerChanged));
40
41         static readonly DependencyPropertyKey IsTypeExpanderEnabledPropertyKey = DependencyProperty.RegisterReadOnly(
42             "IsTypeExpanderEnabled",
43             typeof(bool),
44             typeof(MessageQuerySetDesigner),
45             new UIPropertyMetadata(false));
46
47         public static readonly DependencyProperty IsTypeExpanderEnabledProperty =
48             IsTypeExpanderEnabledPropertyKey.DependencyProperty;
49
50         public MessageQuerySetDesigner()
51         {
52             InitializeComponent();
53         }
54
55         //reference to messaging activity containing given message query set
56         public ModelItem Activity
57         {
58             get { return (ModelItem)GetValue(ActivityProperty); }
59             set { SetValue(ActivityProperty, value); }
60         }
61
62         //reference to model item which contains edited message query set (may be the same as Activty)
63         public ModelItem MessageQuerySetContainer
64         {
65             get { return (ModelItem)GetValue(MessageQuerySetContainerProperty); }
66             set { SetValue(MessageQuerySetContainerProperty, value); }
67         }
68
69         public bool IsTypeExpanderEnabled
70         {
71             get { return (bool)GetValue(IsTypeExpanderEnabledProperty); }
72             private set { SetValue(IsTypeExpanderEnabledPropertyKey, value); }
73         }
74
75         public IList<KeyValuePair<string, Type>> ActivityParameters
76         {
77             get
78             {
79                 return null != this.Activity ? this.GetActivityParameters() : null;
80             }
81         }
82
83         protected override void OnInitialized(EventArgs e)
84         {
85             base.OnInitialized(e);
86             //create data grid helper and provide drop down with type expander as new row template
87             this.messageQueriesDGHelper = new DataGridHelper(this.messageQueries, this);
88             this.messageQueriesDGHelper.AddNewRowContent = this.FindResource("newRowTemplate");
89             this.messageQueriesDGHelper.ShowValidationErrorAsToolTip = true;
90             this.messageQueries.ItemsSource = this.dataSource;
91             this.dataSource.CollectionChanged += this.OnDataCollectionChanged;
92         }
93
94         void OnXpathCreated(object sender, RoutedEventArgs e)
95         {
96             //user created a xpath
97             var editor = (MessageQueryEditor)sender;
98             //get its value
99             var query = editor.Query;
100             if (null != query)
101             {
102                 //get reference to message query set dictionary
103                 var messageQuerySet = this.MessageQuerySetContainer.Properties[this.querySetPropertyName].Dictionary;
104                 //create unique key name
105                 var name = messageQuerySet.GetUniqueName(key, p => (string)p.GetCurrentValue());
106                 //add new entry with created key and query
107                 messageQuerySet.Add(name, query);
108                 //look for created key value pair
109                 var entry = messageQuerySet.First(p => string.Equals(p.Key.GetCurrentValue(), name));
110                 //wrap it 
111                 var wrapper = new MessageQueryEntry(entry);
112                 //and add it to the ui
113                 this.messageQueriesDGHelper.Source<IList>().Add(wrapper);
114             }
115             //reset editor, so new query can be created
116             editor.SelectedItem = null;
117         }
118
119         void OnActivityChanged()
120         {
121             if (null != this.PropertyChanged)
122             {
123                 this.PropertyChanged(this, new PropertyChangedEventArgs("ActivityParameters"));
124             }
125             this.OnInitialzeView();
126         }
127
128         //method called whenever Activity or MessageQuerySetContainer changes
129         void OnInitialzeView()
130         {
131             //cleanup previous ui binding
132             this.dataSource.Clear();
133
134             //if we have activity and valid message query set container
135             if (null != this.Activity && null != this.MessageQuerySetContainer && !string.IsNullOrEmpty(this.querySetPropertyName))
136             {
137                 //check if message query set is initialized
138                 if (!this.MessageQuerySetContainer.Properties[this.querySetPropertyName].IsSet)
139                 {
140                     //initialize if required
141                     this.MessageQuerySetContainer.Properties[this.querySetPropertyName].SetValue(new MessageQuerySet());
142                 }
143                 //get reference to message query set
144                 var input = this.MessageQuerySetContainer.Properties[this.querySetPropertyName].Dictionary;
145
146                 if (null != input)
147                 {
148                     //create all model objects into ux collection
149                     foreach (var entry in input)
150                     {
151                         var wrapper = new MessageQueryEntry(entry);
152                         this.dataSource.Add(wrapper);
153                     }
154                     this.IsTypeExpanderEnabled = true;
155                 }
156             }
157         }
158
159         void OnDataCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
160         {
161             //whenever user removes an entry from ux, reflect that change into underlying model
162             switch (e.Action)
163             {
164                 case NotifyCollectionChangedAction.Remove:
165                     var messageQuerySet = this.MessageQuerySetContainer.Properties[this.querySetPropertyName].Dictionary;
166                     foreach (MessageQueryEntry entry in e.OldItems)
167                     {
168                         messageQuerySet.Remove(entry.GetKey());
169                         entry.Dispose();
170                     }
171                     break;
172
173                 case NotifyCollectionChangedAction.Reset:
174                     this.IsTypeExpanderEnabled = false;
175                     break;
176             }
177         }
178
179         //helper method - used to pull activity's parameters 
180         IList<KeyValuePair<string, Type>> GetActivityParameters()
181         {
182             var result = new List<KeyValuePair<string, Type>>();
183             //get activity's content
184             var content = this.Activity.Properties["Content"].Value;
185             if (null != content)
186             {
187                 //simple scenario - content is just one argument - get its type
188                 if ((content.IsAssignableFrom<ReceiveMessageContent>() || content.IsAssignableFrom<SendMessageContent>()) &&
189                     content.Properties["Message"].IsSet)
190                 {
191                     ModelItem type = null;
192                     content.TryGetPropertyValue(out type, "Message", "ArgumentType");
193                     result.Add(new KeyValuePair<string, Type>((string)this.FindResource("defaultParameterName"), (Type)type.GetCurrentValue()));
194                 }
195                 //complex scenario - content is a collection of parameters, for each one get its name and type
196                 else if (content.IsAssignableFrom<ReceiveParametersContent>() && content.Properties["Parameters"].IsSet)
197                 {
198                     var source = (IDictionary<string, OutArgument>)content.Properties["Parameters"].ComputedValue;
199                     foreach (var entry in source)
200                     {
201                         result.Add(new KeyValuePair<string, Type>(entry.Key, entry.Value.ArgumentType));
202                     }
203                 }
204                 else if (content.IsAssignableFrom<SendParametersContent>() && content.Properties["Parameters"].IsSet)
205                 {
206                     var source = (IDictionary<string, InArgument>)content.Properties["Parameters"].ComputedValue;
207                     foreach (var entry in source)
208                     {
209                         result.Add(new KeyValuePair<string, Type>(entry.Key, entry.Value.ArgumentType));
210                     }
211                 }
212             }
213             return result;
214         }
215
216         static void OnActivityChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
217         {
218             var activity = e.NewValue as ModelItem;
219             //throw if activity is not valid messaging activity type
220             if (null != activity && !activity.IsMessagingActivity())
221             {
222                 throw FxTrace.Exception.AsError(new NotSupportedException(activity.ItemType.FullName));
223             }
224             ((MessageQuerySetDesigner)sender).OnActivityChanged();
225         }
226
227         static void OnMessageQuerySetContainerChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
228         {
229             var control = (MessageQuerySetDesigner)sender;
230             var container = e.NewValue as ModelItem;
231             //throw if query set container is not derived from correlation initializer or doesn't have required property
232             if (null != container)
233             {
234                 var property = container.Properties.FirstOrDefault(p => typeof(MessageQuerySet).IsAssignableFrom(p.PropertyType));
235                 if (!container.IsAssignableFrom<CorrelationInitializer>() && null == property)
236                 {
237                     throw FxTrace.Exception.AsError(new NotSupportedException(container.ItemType.FullName));
238                 }
239                 control.querySetPropertyName = null != property ? property.Name : string.Empty;
240             }
241             control.OnInitialzeView();
242         }
243
244         void OnEditingControlLoaded(object sender, RoutedEventArgs args)
245         {
246             DataGridHelper.OnEditingControlLoaded(sender, args);
247         }
248
249         void OnEditingControlUnloaded(object sender, RoutedEventArgs args)
250         {
251             DataGridHelper.OnEditingControlUnloaded(sender, args);
252         }
253
254         internal sealed class MessageQueryEntry : DesignObjectWrapper
255         {
256             internal static string KeyProperty = "Key";
257             internal static string ValueProperty = "Expression";
258
259             string keyValue;
260
261             public MessageQueryEntry()
262             {
263                 throw FxTrace.Exception.AsError(new NotSupportedException());
264             }
265
266             public MessageQueryEntry(KeyValuePair<ModelItem, ModelItem> entry)
267                 : base(entry.Value)
268             {
269                 this.keyValue = (string)entry.Key.GetCurrentValue();
270             }
271
272             #region Initialize type properties code
273             public static PropertyDescriptorData[] InitializeTypeProperties()
274             {
275                 return new PropertyDescriptorData[]
276                 {
277                     new PropertyDescriptorData()
278                     {
279                          PropertyType = typeof(string),
280                          PropertyName = KeyProperty,
281                          PropertyGetter = (instance) => ( ((MessageQueryEntry)instance).GetKey() ),
282                          PropertyValidator = (instance, value, errors) => (((MessageQueryEntry)instance).ValidateKey(value, errors)),
283                          PropertySetter = (instance, value) => { ((MessageQueryEntry)instance).SetKey(value); },
284                     },
285                     new PropertyDescriptorData()
286                     {
287                         PropertyType = typeof(string),
288                         PropertyName = ValueProperty,
289                         PropertyGetter = (instance) => (((MessageQueryEntry)instance).ReflectedObject.Properties[ValueProperty].ComputedValue),
290                         PropertySetter = (instance, value) => { ((MessageQueryEntry)instance).ReflectedObject.Properties[ValueProperty].SetValue( value ); },
291                     }
292                 };
293             }
294             #endregion
295
296             internal string GetKey()
297             {
298                 return this.keyValue;
299             }
300
301             void SetKey(object value)
302             {
303                 string name = (string)(value is ModelItem ? ((ModelItem)value).GetCurrentValue() : value);
304                 name = name.Trim();
305
306                 var source = (ModelItemDictionary)this.ReflectedObject.Parent;
307                 ModelItem newKeyMI = null;
308                 source.SwitchKeys(this.keyValue, name, out newKeyMI);
309                 this.keyValue = name;
310             }
311
312             bool ValidateKey(object newValue, List<string> errors)
313             {
314                 string name = (string)(newValue is ModelItem ? ((ModelItem)newValue).GetCurrentValue() : newValue);
315                 if (null != name)
316                 {
317                     name = name.Trim();
318                 }
319
320                 if (string.IsNullOrEmpty(name))
321                 {
322                     errors.Add(System.Activities.Core.Presentation.SR.NullOrEmptyKeyName);
323                 }
324                 else
325                 {
326                     var source = (ModelItemDictionary)this.ReflectedObject.Parent;
327                     if (source.Keys.Any(p => string.Equals(p.GetCurrentValue(), name)))
328                     {
329                         errors.Add(string.Format(CultureInfo.CurrentUICulture, System.Activities.Core.Presentation.SR.DuplicateKeyName, name));
330                     }
331                 }
332                 return errors.Count == 0;
333             }
334
335             protected override string AutomationId
336             {
337                 get { return this.keyValue; }
338             }
339         }
340     }
341 }