1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------
5 namespace System.ServiceModel.Activities.Presentation
7 using System.Activities.Presentation;
8 using System.Collections.Generic;
9 using System.Reflection;
10 using System.Runtime.Serialization;
12 using System.Windows.Controls;
13 using System.Windows.Input;
14 using System.Windows.Threading;
17 using System.Collections;
18 using System.Xml.Linq;
20 partial class ContentCorrelationTypeExpander
22 static readonly DependencyPropertyKey IsSelectionValidPropertyKey = DependencyProperty.RegisterReadOnly(
25 typeof(ContentCorrelationTypeExpander),
26 new UIPropertyMetadata(false, OnIsSelectionValidChanged));
28 public static readonly DependencyProperty IsSelectionValidProperty = IsSelectionValidPropertyKey.DependencyProperty;
30 public static readonly RoutedEvent IsSelectionValidChangedEvent = EventManager.RegisterRoutedEvent(
31 "IsSelectionValidChanged",
32 RoutingStrategy.Bubble,
33 typeof(RoutedEventHandler),
34 typeof(ContentCorrelationTypeExpander));
36 public static readonly RoutedEvent SelectionChangedEvent = EventManager.RegisterRoutedEvent(
38 RoutingStrategy.Bubble,
39 typeof(RoutedEventHandler),
40 typeof(ContentCorrelationTypeExpander));
42 public static readonly DependencyProperty TypesToExpandProperty = DependencyProperty.Register(
44 typeof(IList<ExpanderTypeEntry>),
45 typeof(ContentCorrelationTypeExpander),
46 new UIPropertyMetadata(null, OnTypesToExpandChanged));
48 static readonly DependencyPropertyKey SelectedTypeEntryPropertyKey = DependencyProperty.RegisterReadOnly(
50 typeof(ExpanderTypeEntry),
51 typeof(ContentCorrelationTypeExpander),
52 new UIPropertyMetadata(null));
54 public static readonly DependencyProperty SelectedTypeEntryProperty = SelectedTypeEntryPropertyKey.DependencyProperty;
56 static readonly Type[] PrimitiveTypesInXPath = new Type[]
60 typeof(XmlQualifiedName),
70 MemberInfo[] path = null;
71 Type selectedType = null;
73 public ContentCorrelationTypeExpander()
75 InitializeComponent();
78 public event RoutedEventHandler IsSelectionValidChanged
82 AddHandler(IsSelectionValidChangedEvent, value);
86 RemoveHandler(IsSelectionValidChangedEvent, value);
90 public event RoutedEventHandler SelectionChanged
94 AddHandler(SelectionChangedEvent, value);
98 RemoveHandler(SelectionChangedEvent, value);
101 public bool IsSelectionValid
103 get { return (bool)GetValue(IsSelectionValidProperty); }
104 private set { SetValue(IsSelectionValidPropertyKey, value); }
107 public IList<ExpanderTypeEntry> TypesToExpand
109 get { return (IList<ExpanderTypeEntry>)GetValue(TypesToExpandProperty); }
110 set { SetValue(TypesToExpandProperty, value); }
113 public ExpanderTypeEntry SelectedTypeEntry
115 get { return (ExpanderTypeEntry)GetValue(SelectedTypeEntryProperty); }
116 private set { SetValue(SelectedTypeEntryPropertyKey, value); }
119 public Type GetSelectedType()
121 return this.selectedType;
124 public MemberInfo[] GetMemberPath()
129 void RaiseSelectionValidChanged()
131 this.RaiseEvent(new RoutedEventArgs(IsSelectionValidChangedEvent, this));
134 void OnTypesToExpandChanged()
136 this.typeExpander.ItemsSource = this.TypesToExpand;
137 this.emptyContent.Visibility = null == this.TypesToExpand || 0 == this.TypesToExpand.Count ? Visibility.Visible : Visibility.Collapsed;
140 void OnTypeExpanderLoaded(object sender, RoutedEventArgs e)
142 this.typeExpander.Focus();
145 void OnTreeViewItemLoaded(object sender, RoutedEventArgs e)
147 var item = (TreeViewItem)sender;
148 if (null != item.Header)
150 if (item.Header is ExpanderTypeEntry)
152 item.IsExpanded = true;
154 else if (item.Header is Type)
156 var type = (Type)item.Header;
157 item.IsExpanded = true;
162 void OnTreeViewItemMouseAccept(object sender, MouseButtonEventArgs e)
164 var item = sender as TreeViewItem;
165 if (null != item && item.Header is ExpanderTypeEntry)
167 this.SelectedTypeEntry = (ExpanderTypeEntry)item.Header;
169 if (null != item && item.IsSelected && item.IsSelectionActive)
176 void OnTreeViewItemKeyboardAccept(object sender, KeyEventArgs e)
178 var item = sender as TreeViewItem;
179 if (null != item && item.Header is ExpanderTypeEntry)
181 this.SelectedTypeEntry = (ExpanderTypeEntry)item.Header;
183 if (null != item && item.IsSelected && item.IsSelectionActive && Key.Enter == e.Key && Keyboard.Modifiers == ModifierKeys.None)
190 void Accept(TreeViewItem item)
192 bool isType = item.Header is ExpanderTypeEntry;
193 bool isMember = item.Header is MemberInfo;
196 var members = new List<MemberInfo>(1);
197 while (null != item && item.Header is MemberInfo)
199 var member = (MemberInfo)item.Header;
200 members.Insert(0, member);
202 if (item.Tag is TreeViewItem)
204 item = (TreeViewItem)item.Tag;
211 this.SelectedTypeEntry = (ExpanderTypeEntry)item.Header;
212 this.selectedType = this.SelectedTypeEntry.TypeToExpand;
213 this.path = members.ToArray();
217 this.SelectedTypeEntry = (ExpanderTypeEntry)item.Header;
218 this.selectedType = this.SelectedTypeEntry.TypeToExpand;
219 this.path = new MemberInfo[0];
223 this.SelectedTypeEntry = null;
224 this.selectedType = null;
227 this.IsSelectionValid = isType || isMember;
228 this.RaiseEvent(new RoutedEventArgs(SelectionChangedEvent, this));
231 //The following types are considered as primitives as far as XPath generation is concerned and shouldn't be expanded any more
232 // 1. CLR built-in types
233 // 2. Byte array, DateTime, TimeSpan, GUID, Uri, XmlQualifiedName, XmlElement and XmlNode array [This includes XElement and XNode array from .NET 3.5]
235 // 4. Arrays and Collection classes including List<T>, Dictionary<K,V> and Hashtable (Anything that implements IEnumerable or IDictionary or is an array is treated as a collection).
236 // 5. Type has [CollectionDataContract] attribute
237 internal static bool IsPrimitiveTypeInXPath(Type type)
239 return ((type.IsPrimitive) || type.IsEnum || PrimitiveTypesInXPath.Any((item => item == type))
240 || (typeof(IEnumerable).IsAssignableFrom(type)) || typeof(IDictionary).IsAssignableFrom(type) || type.IsArray
241 || (type.GetCustomAttributes(typeof(CollectionDataContractAttribute), false).Length > 0));
244 static void OnIsSelectionValidChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
246 ((ContentCorrelationTypeExpander)sender).RaiseSelectionValidChanged();
249 static void OnTypesToExpandChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
251 var control = (ContentCorrelationTypeExpander)sender;
252 control.Dispatcher.BeginInvoke(new Action(() => { control.OnTypesToExpandChanged(); }), DispatcherPriority.Render);
256 internal sealed class TypeEntryContainer
258 public string DisplayText { get; set; }
259 public IList<ExpanderTypeEntry> Items { get; set; }
261 public override string ToString()
263 return this.DisplayText ?? base.ToString();
267 internal sealed class ExpanderTypeEntry : DependencyObject
269 public static readonly DependencyProperty NameProperty = DependencyProperty.Register(
272 typeof(ExpanderTypeEntry),
273 new UIPropertyMetadata(string.Empty));
275 public static readonly DependencyProperty TypeToExpandProperty = DependencyProperty.Register(
278 typeof(ExpanderTypeEntry),
279 new UIPropertyMetadata(null));
281 public static readonly DependencyProperty TagProperty = DependencyProperty.Register(
284 typeof(ExpanderTypeEntry),
285 new UIPropertyMetadata(null));
289 get { return (string)GetValue(NameProperty); }
290 set { SetValue(NameProperty, value); }
293 public Type TypeToExpand
295 get { return (Type)GetValue(TypeToExpandProperty); }
296 set { SetValue(TypeToExpandProperty, value); }
299 public Type[] TypeToExpandSource
301 get { return new Type[] { this.TypeToExpand }; }
306 get { return GetValue(TagProperty); }
307 set { SetValue(TagProperty, value); }
310 public override string ToString()
312 return this.Name ?? "<null>";