1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
4 namespace System.ServiceModel.Activities.Presentation
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;
18 using System.ServiceModel;
21 partial class MessageQuerySetDesigner : INotifyPropertyChanged
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;
29 public static readonly DependencyProperty ActivityProperty = DependencyProperty.Register(
32 typeof(MessageQuerySetDesigner),
33 new UIPropertyMetadata(OnActivityChanged));
35 public static readonly DependencyProperty MessageQuerySetContainerProperty = DependencyProperty.Register(
36 "MessageQuerySetContainer",
38 typeof(MessageQuerySetDesigner),
39 new UIPropertyMetadata(null, OnMessageQuerySetContainerChanged));
41 static readonly DependencyPropertyKey IsTypeExpanderEnabledPropertyKey = DependencyProperty.RegisterReadOnly(
42 "IsTypeExpanderEnabled",
44 typeof(MessageQuerySetDesigner),
45 new UIPropertyMetadata(false));
47 public static readonly DependencyProperty IsTypeExpanderEnabledProperty =
48 IsTypeExpanderEnabledPropertyKey.DependencyProperty;
50 public MessageQuerySetDesigner()
52 InitializeComponent();
55 //reference to messaging activity containing given message query set
56 public ModelItem Activity
58 get { return (ModelItem)GetValue(ActivityProperty); }
59 set { SetValue(ActivityProperty, value); }
62 //reference to model item which contains edited message query set (may be the same as Activty)
63 public ModelItem MessageQuerySetContainer
65 get { return (ModelItem)GetValue(MessageQuerySetContainerProperty); }
66 set { SetValue(MessageQuerySetContainerProperty, value); }
69 public bool IsTypeExpanderEnabled
71 get { return (bool)GetValue(IsTypeExpanderEnabledProperty); }
72 private set { SetValue(IsTypeExpanderEnabledPropertyKey, value); }
75 public IList<KeyValuePair<string, Type>> ActivityParameters
79 return null != this.Activity ? this.GetActivityParameters() : null;
83 protected override void OnInitialized(EventArgs e)
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;
94 void OnXpathCreated(object sender, RoutedEventArgs e)
96 //user created a xpath
97 var editor = (MessageQueryEditor)sender;
99 var query = editor.Query;
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));
111 var wrapper = new MessageQueryEntry(entry);
112 //and add it to the ui
113 this.messageQueriesDGHelper.Source<IList>().Add(wrapper);
115 //reset editor, so new query can be created
116 editor.SelectedItem = null;
119 void OnActivityChanged()
121 if (null != this.PropertyChanged)
123 this.PropertyChanged(this, new PropertyChangedEventArgs("ActivityParameters"));
125 this.OnInitialzeView();
128 //method called whenever Activity or MessageQuerySetContainer changes
129 void OnInitialzeView()
131 //cleanup previous ui binding
132 this.dataSource.Clear();
134 //if we have activity and valid message query set container
135 if (null != this.Activity && null != this.MessageQuerySetContainer && !string.IsNullOrEmpty(this.querySetPropertyName))
137 //check if message query set is initialized
138 if (!this.MessageQuerySetContainer.Properties[this.querySetPropertyName].IsSet)
140 //initialize if required
141 this.MessageQuerySetContainer.Properties[this.querySetPropertyName].SetValue(new MessageQuerySet());
143 //get reference to message query set
144 var input = this.MessageQuerySetContainer.Properties[this.querySetPropertyName].Dictionary;
148 //create all model objects into ux collection
149 foreach (var entry in input)
151 var wrapper = new MessageQueryEntry(entry);
152 this.dataSource.Add(wrapper);
154 this.IsTypeExpanderEnabled = true;
159 void OnDataCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
161 //whenever user removes an entry from ux, reflect that change into underlying model
164 case NotifyCollectionChangedAction.Remove:
165 var messageQuerySet = this.MessageQuerySetContainer.Properties[this.querySetPropertyName].Dictionary;
166 foreach (MessageQueryEntry entry in e.OldItems)
168 messageQuerySet.Remove(entry.GetKey());
173 case NotifyCollectionChangedAction.Reset:
174 this.IsTypeExpanderEnabled = false;
179 //helper method - used to pull activity's parameters
180 IList<KeyValuePair<string, Type>> GetActivityParameters()
182 var result = new List<KeyValuePair<string, Type>>();
183 //get activity's content
184 var content = this.Activity.Properties["Content"].Value;
187 //simple scenario - content is just one argument - get its type
188 if ((content.IsAssignableFrom<ReceiveMessageContent>() || content.IsAssignableFrom<SendMessageContent>()) &&
189 content.Properties["Message"].IsSet)
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()));
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)
198 var source = (IDictionary<string, OutArgument>)content.Properties["Parameters"].ComputedValue;
199 foreach (var entry in source)
201 result.Add(new KeyValuePair<string, Type>(entry.Key, entry.Value.ArgumentType));
204 else if (content.IsAssignableFrom<SendParametersContent>() && content.Properties["Parameters"].IsSet)
206 var source = (IDictionary<string, InArgument>)content.Properties["Parameters"].ComputedValue;
207 foreach (var entry in source)
209 result.Add(new KeyValuePair<string, Type>(entry.Key, entry.Value.ArgumentType));
216 static void OnActivityChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
218 var activity = e.NewValue as ModelItem;
219 //throw if activity is not valid messaging activity type
220 if (null != activity && !activity.IsMessagingActivity())
222 throw FxTrace.Exception.AsError(new NotSupportedException(activity.ItemType.FullName));
224 ((MessageQuerySetDesigner)sender).OnActivityChanged();
227 static void OnMessageQuerySetContainerChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
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)
234 var property = container.Properties.FirstOrDefault(p => typeof(MessageQuerySet).IsAssignableFrom(p.PropertyType));
235 if (!container.IsAssignableFrom<CorrelationInitializer>() && null == property)
237 throw FxTrace.Exception.AsError(new NotSupportedException(container.ItemType.FullName));
239 control.querySetPropertyName = null != property ? property.Name : string.Empty;
241 control.OnInitialzeView();
244 void OnEditingControlLoaded(object sender, RoutedEventArgs args)
246 DataGridHelper.OnEditingControlLoaded(sender, args);
249 void OnEditingControlUnloaded(object sender, RoutedEventArgs args)
251 DataGridHelper.OnEditingControlUnloaded(sender, args);
254 internal sealed class MessageQueryEntry : DesignObjectWrapper
256 internal static string KeyProperty = "Key";
257 internal static string ValueProperty = "Expression";
261 public MessageQueryEntry()
263 throw FxTrace.Exception.AsError(new NotSupportedException());
266 public MessageQueryEntry(KeyValuePair<ModelItem, ModelItem> entry)
269 this.keyValue = (string)entry.Key.GetCurrentValue();
272 #region Initialize type properties code
273 public static PropertyDescriptorData[] InitializeTypeProperties()
275 return new PropertyDescriptorData[]
277 new PropertyDescriptorData()
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); },
285 new PropertyDescriptorData()
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 ); },
296 internal string GetKey()
298 return this.keyValue;
301 void SetKey(object value)
303 string name = (string)(value is ModelItem ? ((ModelItem)value).GetCurrentValue() : value);
306 var source = (ModelItemDictionary)this.ReflectedObject.Parent;
307 ModelItem newKeyMI = null;
308 source.SwitchKeys(this.keyValue, name, out newKeyMI);
309 this.keyValue = name;
312 bool ValidateKey(object newValue, List<string> errors)
314 string name = (string)(newValue is ModelItem ? ((ModelItem)newValue).GetCurrentValue() : newValue);
320 if (string.IsNullOrEmpty(name))
322 errors.Add(System.Activities.Core.Presentation.SR.NullOrEmptyKeyName);
326 var source = (ModelItemDictionary)this.ReflectedObject.Parent;
327 if (source.Keys.Any(p => string.Equals(p.GetCurrentValue(), name)))
329 errors.Add(string.Format(CultureInfo.CurrentUICulture, System.Activities.Core.Presentation.SR.DuplicateKeyName, name));
332 return errors.Count == 0;
335 protected override string AutomationId
337 get { return this.keyValue; }