1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
6 namespace System.Activities.Presentation.Toolbox
9 using System.Activities.Presentation.View;
10 using System.Collections.Generic;
11 using System.Collections.Specialized;
12 using System.ComponentModel;
13 using System.Diagnostics.CodeAnalysis;
14 using System.Drawing.Design;
17 using System.Windows.Controls;
18 using System.Windows.Input;
19 using System.Windows.Markup;
21 // This class is responsible for rendering cate----ezed tools collection
22 // It also provides methods for notifing user about tool selection/creation events
24 [TemplatePart(Name = "PART_SearchBox"), TemplatePart(Name = "PART_Tools")]
25 [ContentProperty("Categories")]
26 sealed public partial class ToolboxControl : Control
28 public static readonly DependencyProperty ToolboxFileProperty =
29 DependencyProperty.Register("ToolboxFile",
31 typeof(ToolboxControl),
34 new PropertyChangedCallback(OnToolboxFileChanged)));
36 static readonly DependencyPropertyKey SelectedToolPropertyKey =
37 DependencyProperty.RegisterReadOnly("SelectedTool",
39 typeof(ToolboxControl),
42 new PropertyChangedCallback(OnToolSelected)));
44 public static readonly DependencyProperty SelectedToolProperty = SelectedToolPropertyKey.DependencyProperty;
46 public static readonly DependencyProperty ToolItemStyleProperty =
47 DependencyProperty.Register("ToolItemStyle",
49 typeof(ToolboxControl),
50 new UIPropertyMetadata(null));
52 public static readonly DependencyProperty CategoryItemStyleProperty =
53 DependencyProperty.Register("CategoryItemStyle",
55 typeof(ToolboxControl),
56 new UIPropertyMetadata(null));
58 public static readonly DependencyProperty ToolTemplateProperty =
59 DependencyProperty.Register("ToolTemplate",
61 typeof(ToolboxControl),
62 new UIPropertyMetadata(null));
64 public static readonly DependencyProperty CategoryTemplateProperty =
65 DependencyProperty.Register("CategoryTemplate",
67 typeof(ToolboxControl),
68 new UIPropertyMetadata(null));
70 public static readonly RoutedEvent ToolCreatedEvent =
71 EventManager.RegisterRoutedEvent("ToolCreated",
72 RoutingStrategy.Bubble,
73 typeof(ToolCreatedEventHandler),
74 typeof(ToolboxControl));
76 public static readonly RoutedEvent ToolSelectedEvent =
77 EventManager.RegisterRoutedEvent("ToolSelected",
78 RoutingStrategy.Bubble,
79 typeof(RoutedEventHandler),
80 typeof(ToolboxControl));
83 internal TextBox searchBox;
84 TreeView toolsTreeView;
85 ToolboxCategoryItems categories;
87 [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
88 static ToolboxControl()
90 DefaultStyleKeyProperty.OverrideMetadata(typeof(ToolboxControl), new FrameworkPropertyMetadata(typeof(ToolboxControl)));
93 public ToolboxControl()
95 var callback = new NotifyCollectionChangedEventHandler(this.OnCategoryCollectionChanged);
96 this.categories = new ToolboxCategoryItems(callback);
99 public event ToolCreatedEventHandler ToolCreated
103 AddHandler(ToolCreatedEvent, value);
107 RemoveHandler(ToolCreatedEvent, value);
111 public event RoutedEventHandler ToolSelected
115 AddHandler(ToolSelectedEvent, value);
119 RemoveHandler(ToolSelectedEvent, value);
123 [Fx.Tag.KnownXamlExternal]
124 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
125 [SuppressMessage(FxCop.Category.Usage, "CA2227:CollectionPropertiesShouldBeReadOnly",
126 Justification = "The setter implemenation is required for XAML support. The setter doesn't replace the collection instance, but copies its content to internal collection")]
127 public ToolboxCategoryItems Categories
129 get { return this.categories; }
132 this.categories.Clear();
135 foreach (var category in value)
137 this.categories.Add(category);
143 public string ToolboxFile
145 get { return (string)GetValue(ToolboxFileProperty); }
146 set { SetValue(ToolboxFileProperty, value); }
149 [Fx.Tag.KnownXamlExternal]
150 public ToolboxItem SelectedTool
152 get { return (ToolboxItem)GetValue(SelectedToolProperty); }
153 private set { SetValue(SelectedToolPropertyKey, value); }
156 [Fx.Tag.KnownXamlExternal]
157 public Style ToolItemStyle
159 get { return (Style)GetValue(ToolItemStyleProperty); }
160 set { SetValue(ToolItemStyleProperty, value); }
163 [Fx.Tag.KnownXamlExternal]
164 public Style CategoryItemStyle
166 get { return (Style)GetValue(CategoryItemStyleProperty); }
167 set { SetValue(CategoryItemStyleProperty, value); }
170 [Fx.Tag.KnownXamlExternal]
171 public DataTemplate ToolTemplate
173 get { return (DataTemplate)GetValue(ToolTemplateProperty); }
174 set { SetValue(ToolTemplateProperty, value); }
177 [Fx.Tag.KnownXamlExternal]
178 public DataTemplate CategoryTemplate
180 get { return (DataTemplate)GetValue(CategoryTemplateProperty); }
181 set { SetValue(CategoryTemplateProperty, value); }
184 [Fx.Tag.KnownXamlExternal]
185 public WorkflowDesigner AssociatedDesigner
191 static void OnToolboxFileChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
193 ToolboxControl toolboxControl = sender as ToolboxControl;
194 string fileName = args.NewValue as string;
195 if (null == toolboxControl || null == fileName)
197 throw FxTrace.Exception.AsError(new ArgumentNullException(null == toolboxControl ? "toolboxControl" : "fileName"));
202 ToolboxItemLoader loader = ToolboxItemLoader.GetInstance();
203 loader.LoadToolboxItems(fileName, toolboxControl.categories, false);
207 if (!DesignerProperties.GetIsInDesignMode(toolboxControl))
214 static void OnToolSelected(DependencyObject sender, DependencyPropertyChangedEventArgs args)
216 ToolboxControl toolboxControl = sender as ToolboxControl;
217 if (null == toolboxControl)
219 throw FxTrace.Exception.AsError(new ArgumentNullException("sender"));
221 if (null != toolboxControl.SelectedTool)
223 toolboxControl.RaiseEvent(new RoutedEventArgs(ToolSelectedEvent, toolboxControl));
227 public override void OnApplyTemplate()
229 base.OnApplyTemplate();
230 //template is applied, look for required controls within it
231 this.searchBox = this.Template.FindName("PART_SearchBox", this) as TextBox;
232 this.toolsTreeView = this.Template.FindName("PART_Tools", this) as TreeView;
233 //if tools tree view exists - assign style and container selectors (there are different styles
234 //for Cateogries and Tools
235 if (null != this.toolsTreeView)
237 this.toolsTreeView.ItemsSource = this.Categories;
238 this.toolsTreeView.ItemContainerStyleSelector = new TreeViewContainerStyleSelector(this);
239 this.toolsTreeView.ItemTemplateSelector = new TreeViewTemplateSelector(this);
240 this.toolsTreeView.SelectedItemChanged += (s, e) =>
242 var toolWrapper = e.NewValue as ToolboxItemWrapper;
243 this.SelectedTool = toolWrapper != null ? toolWrapper.ToolboxItem : null;
248 protected override void OnPreviewKeyDown(KeyEventArgs e)
254 if (null != this.searchBox &&
255 e.OriginalSource == this.searchBox &&
256 null != this.toolsTreeView)
258 this.toolsTreeView.Focus();
263 ToolboxItemCreated();
268 if (null != this.searchBox && e.Source != this.searchBox)
270 if (((e.Key >= Key.A && e.Key <= Key.Z) || (e.Key >= Key.D0 && e.Key <= Key.D9)) &&
271 (e.KeyboardDevice.Modifiers == ModifierKeys.None || e.KeyboardDevice.Modifiers == ModifierKeys.Shift))
273 this.searchBox.Focus();
278 base.OnPreviewKeyDown(e);
281 void OnCategoryCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
285 case NotifyCollectionChangedAction.Add:
286 foreach (ToolboxCategory category in e.NewItems)
288 if (null == category)
290 throw FxTrace.Exception.ArgumentNull("category");
293 var listener = new NotifyCollectionChangedEventHandler(OnToolsCollectionChange);
294 category.HandleToolCollectionNotification(listener, true);
296 var items = new List<ToolboxItemWrapper>();
297 foreach (ToolboxItemWrapper toolWrapper in category.Tools)
299 items.Add(toolWrapper);
301 OnToolsCollectionChange(category,
302 new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, items, 0));
309 if (null != this.toolsTreeView)
311 this.toolsTreeView.ItemsSource = null;
312 this.toolsTreeView.ItemsSource = this.categories;
317 void OnToolsCollectionChange(object sender, NotifyCollectionChangedEventArgs args)
321 case NotifyCollectionChangedAction.Add:
322 foreach (ToolboxItemWrapper tool in args.NewItems)
326 throw FxTrace.Exception.ArgumentNull("tool");
328 tool.PropertyChanged += new PropertyChangedEventHandler(OnToolPropertyChanged);
329 OnToolPropertyChanged(tool, null);
338 void OnToolPropertyChanged(object sender, PropertyChangedEventArgs e)
342 ToolboxItemWrapper tool = (ToolboxItemWrapper)sender;
343 tool.ResolveToolboxItem();
347 if (!DesignerProperties.GetIsInDesignMode(this))
354 internal void OnToolMouseMove(object sender, MouseEventArgs args)
357 ToolboxItemWrapper toolWrapper;
358 if (args.LeftButton == MouseButtonState.Pressed && TryGetSelectedToolboxItem(out tool, out toolWrapper))
360 IDataObject dataObject = toolWrapper.DataObject ?? new DataObject();
361 dataObject.SetData(DragDropHelper.WorkflowItemTypeNameFormat, toolWrapper.Type.AssemblyQualifiedName);
362 DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Link | DragDropEffects.Copy);
366 internal void OnTreeViewDoubleClick(object sender, MouseEventArgs args)
368 ToolboxItemCreated();
371 void ToolboxItemCreated()
374 ToolboxItemWrapper toolWrapper;
375 if (TryGetSelectedToolboxItem(out tool, out toolWrapper))
377 if (null != this.AssociatedDesigner && null != this.AssociatedDesigner.Context)
379 DesignerView target = this.AssociatedDesigner.Context.Services.GetService<DesignerView>();
380 IDataObject dataObject = toolWrapper.DataObject ?? new DataObject();
381 dataObject.SetData(DragDropHelper.WorkflowItemTypeNameFormat, toolWrapper.Type.AssemblyQualifiedName);
382 ((RoutedCommand)DesignerView.CreateWorkflowElementCommand).Execute(dataObject, target);
384 ToolCreatedEventArgs args = new ToolCreatedEventArgs(ToolCreatedEvent, this, tool.CreateComponents());
389 bool TryGetSelectedToolboxItem(out ToolboxItem toolboxItem, out ToolboxItemWrapper toolboxItemWrapper)
392 toolboxItemWrapper = null;
393 if (null != this.toolsTreeView && null != this.toolsTreeView.SelectedItem)
395 ToolboxItemWrapper tool = this.toolsTreeView.SelectedItem as ToolboxItemWrapper;
396 if (null != tool && null != tool.ToolboxItem)
398 toolboxItem = tool.ToolboxItem;
399 toolboxItemWrapper = tool;
403 return (null != toolboxItem);