Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / Tools / System.Activities.Presentation / System / Activities / Presentation / View / VariableDesigner.xaml.cs / 1305376 / VariableDesigner.xaml.cs
//---------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //--------------------------------------------------------------- namespace System.Activities.Presentation.View { using Microsoft.VisualBasic.Activities; using System; using System.Activities.Presentation.PropertyEditing; using System.Activities.Presentation.View; using System.Activities.Presentation.Model; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Globalization; using System.Linq; using System.Runtime; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Activities.Presentation.Services; using System.Windows.Threading; using System.Reflection; partial class VariableDesigner { public static readonly DependencyProperty ContextProperty = DependencyProperty.Register( "Context", typeof(EditingContext), typeof(VariableDesigner), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(VariableDesigner.OnContextChanged))); static readonly DependencyPropertyKey CurrentVariableScopePropertyKey = DependencyProperty.RegisterReadOnly( "CurrentVariableScope", typeof(ModelItemCollection), typeof(VariableDesigner), new UIPropertyMetadata(null, new PropertyChangedCallback(OnVariableScopeChanged))); public static readonly DependencyProperty CurrentVariableScopeProperty = CurrentVariableScopePropertyKey.DependencyProperty; public static readonly RoutedEvent VariableCollectionChangedEvent = EventManager.RegisterRoutedEvent("VariableCollectionChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(VariableDesigner)); const string DefaultVariableName = "variable"; ListscopesList = new List (); ObservableCollection variableWrapperCollection = new ObservableCollection (); bool trackVariableWrapperContainerChanges = true; bool isSelectionSourceInternal = false; ModelItem variableToSelect = null; bool continueScopeEdit = false; ModelItem lastSelection; DataGridHelper dgHelper; public VariableDesigner() { InitializeComponent(); this.dgHelper = new DataGridHelper(this.variableDataGrid, this); this.dgHelper.Context = this.Context; this.dgHelper.AddNewRowCommand = DesignerView.CreateVariableCommand; this.dgHelper.AddNewRowContent = (string)this.FindResource("addVariableNewRowLabel"); this.dgHelper.ResolveDynamicTemplateCallback = this.OnResolveDynamicContentTemplate; this.dgHelper.LoadDynamicContentDataCallback = this.OnShowExtendedValueEditor; this.dgHelper.LoadCustomPropertyValueEditorCallback = this.OnLoadExtendedValueEditor; this.dgHelper.ShowValidationErrorAsToolTip = false; this.variableDataGrid.SelectionChanged += OnDataGridRowSelected; this.variableWrapperCollection.CollectionChanged += OnVariableWrapperCollectionChanged; this.variableDataGrid.ItemsSource = this.variableWrapperCollection; var converter = (BreadCrumbTextConverter)this.FindResource("scopeToNameConverter"); converter.PixelsPerChar = (this.FontSize - 5); } public event RoutedEventHandler VariableCollectionChanged { add { AddHandler(VariableCollectionChangedEvent, value); } remove { RemoveHandler(VariableCollectionChangedEvent, value); } } public EditingContext Context { get { return (EditingContext)GetValue(ContextProperty); } set { SetValue(ContextProperty, value); } } public ModelItemCollection CurrentVariableScope { get { return (ModelItemCollection)GetValue(CurrentVariableScopeProperty); } private set { SetValue(CurrentVariableScopePropertyKey, value); } } public List ScopesList { get { return this.scopesList; } } public bool CreateNewVariableWrapper() { bool result = false; ModelItemCollection scope = this.GetDefaultVariableScope(); if (null != scope) { DesignTimeVariable wrapperObject = null; Variable variable = Variable.Create(this.GetDefaultName(), this.GetDefaultType(), VariableModifiers.None); using (ModelEditingScope change = scope.BeginEdit((string)this.FindResource("addNewVariableDescription"))) { ModelItem wrappedVariable = scope.Add(variable); wrapperObject = new DesignTimeVariable(wrappedVariable, this); this.variableWrapperCollection.Add(wrapperObject); change.Complete(); result = true; } this.dgHelper.BeginRowEdit(wrapperObject); } return result; } internal void ChangeVariableType(DesignTimeVariable oldVariableWrapper, Variable newVariable) { //check who is the sender of the event - data grid or property inspector int index = this.variableDataGrid.Items.IndexOf(this.variableDataGrid.SelectedItem); DataGridCell cell = DataGridHelper.GetCell(this.variableDataGrid, index, 1); bool shouldReselct = cell.IsEditing; //get location of the variable ModelItemCollection container = VariableHelper.GetVariableCollection(oldVariableWrapper.ReflectedObject.Parent.Parent); index = container.IndexOf(oldVariableWrapper.ReflectedObject); //remove all value container.RemoveAt(index); oldVariableWrapper.Dispose(); oldVariableWrapper.Initialize(container.Insert(index, newVariable)); } internal void NotifyVariableScopeChanged(DesignTimeVariable variable) { this.variableToSelect = null != variable ? variable.ReflectedObject : null; int index = this.variableDataGrid.Items.IndexOf(this.variableDataGrid.SelectedItem); DataGridCell cell = DataGridHelper.GetCell(this.variableDataGrid, index, 2); this.continueScopeEdit = cell.IsEditing; } //Check case-insensitive duplicates, which are not allowed in VB expressions internal void CheckCaseInsensitiveDuplicates(VBIdentifierName identifierName, string newName) { Func checkForDuplicates = new Func (p => string.Equals((string)p.ReflectedObject.Properties["Name"].ComputedValue, newName, StringComparison.OrdinalIgnoreCase) && !object.Equals(p.GetVariableName(), identifierName)); DesignTimeVariable duplicate = this.variableWrapperCollection.FirstOrDefault (checkForDuplicates); if (duplicate != null) { identifierName.IsValid = false; identifierName.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateVisualBasicIdentifier, newName); VBIdentifierName duplicateIdentifier = duplicate.GetVariableName(); if (duplicateIdentifier.IsValid) { duplicateIdentifier.IsValid = false; duplicateIdentifier.ErrorMessage = string.Format(CultureInfo.CurrentUICulture, SR.DuplicateVisualBasicIdentifier, duplicateIdentifier.IdentifierName); } }; } //Check duplicates with old value. When there's only one variable duplicate with the old value, //the only one variable should be valid now after the change void ClearCaseInsensitiveDuplicates(VBIdentifierName identifier, string oldName) { Func checkForOldNameDuplicates = new Func (p => string.Equals((string)p.ReflectedObject.Properties["Name"].ComputedValue, oldName, StringComparison.OrdinalIgnoreCase) && !object.Equals(p.GetVariableName(), identifier)); IEnumerable oldDuplicates = this.variableWrapperCollection.Where (checkForOldNameDuplicates); if (oldDuplicates.Count () == 1) { DesignTimeVariable wrapper = oldDuplicates.First (); VBIdentifierName oldDuplicate = wrapper.GetVariableName(); oldDuplicate.IsValid = true; oldDuplicate.ErrorMessage = string.Empty; } } internal void NotifyVariableNameChanged(VBIdentifierName identifierName, string newName, string oldName) { //Check whether there're any variables' name conflict with the old name which can be cleaned up now this.ClearCaseInsensitiveDuplicates(identifierName, oldName); //Check whether there're any duplicates with new name this.CheckCaseInsensitiveDuplicates(identifierName, newName); } internal void UpdateTypeDesigner(DesignTimeVariable variable) { this.dgHelper.UpdateDynamicContentColumns(variable); } string GetDefaultName() { return this.variableWrapperCollection.GetUniqueName (VariableDesigner.DefaultVariableName, wrapper => wrapper.GetVariableName().IdentifierName); } Type GetDefaultType() { return typeof(string); } ModelItemCollection GetDefaultVariableScope() { //do a lazdy scope refresh //if we have a valid variable scope if (null != this.CurrentVariableScope) { //get the tree manager var treeManager = this.Context.Services.GetService (); if (null != treeManager) { //get the model tree root var root = treeManager.Root; //get the first scope, which is attached to the model tree (in case of undo/redo operations, even though VariableScope might be //valid, it actually isn't attached to model tree, so using it as a variable scope doesn't make any sense) var validScope = this.scopesList.FirstOrDefault( p => ModelItem.Equals(p, root) || root.IsParentOf(p) ); //check if valid scope is different that current variable scope. most likely - due to undo/redo operation which removed an activity if (!ModelItem.Equals(validScope, this.CurrentVariableScope.Parent)) { //it is different - update the current variable scope (this setter will unhook old event handlers, clean the scopesList collection and hook //for new event notifications this.CurrentVariableScope = validScope.GetVariableCollection(); } } } //return validated variable scope return this.CurrentVariableScope; } void Populate(ModelItem workflowElement) { this.scopesList.ForEach(p => { p.Properties["Variables"].Collection.CollectionChanged -= OnVariableCollectionChanged; }); this.scopesList.Clear(); this.variableDataGrid.ItemsSource = null; this.variableWrapperCollection.All(p => { p.Dispose(); return true; }); this.variableWrapperCollection.Clear(); var allVariables = VariableHelper.FindDeclaredVariables(workflowElement, this.scopesList); //fill variable wrapper collection only if designer is visible if (workflowElement != null && this.IsVisible) { allVariables.ForEach(variable => { this.variableWrapperCollection.Add(new DesignTimeVariable(variable, this)); }); } this.variableDataGrid.ItemsSource = this.variableWrapperCollection; this.scopesList.ForEach(p => { p.Properties["Variables"].Collection.CollectionChanged += OnVariableCollectionChanged; }); } void StoreLastSelection() { if (!this.isSelectionSourceInternal) { ModelItem current = this.Context.Items.GetValue ().PrimarySelection; if (null == current || !typeof(DesignTimeVariable).IsAssignableFrom(current.ItemType)) { this.lastSelection = current; } } } void OnDataGridRowSelected(object sender, RoutedEventArgs e) { if (null != this.Context && !this.isSelectionSourceInternal) { this.isSelectionSourceInternal = true; if (null != this.variableDataGrid.SelectedItem && this.variableDataGrid.SelectedItem is DesignTimeVariable) { DesignTimeVariable variable = (DesignTimeVariable)this.variableDataGrid.SelectedItem; this.Context.Items.SetValue(new Selection(variable.Content)); } else { this.Context.Items.SetValue(new Selection()); } this.isSelectionSourceInternal = false; } } void OnContextChanged() { if (null != this.Context) { this.Context.Items.Subscribe (new SubscribeContextCallback (OnItemSelected)); } this.dgHelper.Context = this.Context; } protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e) { base.OnIsKeyboardFocusWithinChanged(e); if ((bool)e.NewValue) { //Re-select the already selected row to raise DataGridSelectionChanged event, //which will update the Selection context item and will refresh property grid object selectedRow = this.variableDataGrid.SelectedItem; this.isSelectionSourceInternal = true; this.variableDataGrid.SelectedItem = null; this.isSelectionSourceInternal = false; this.variableDataGrid.SelectedItem = selectedRow; } } void OnItemSelected(Selection newSelection) { //check if selection update source is internal - it is internal if someone clicks on row in variable designer. in such case, do not update selection if (!this.isSelectionSourceInternal) { //whenever selection changes: //1) check if selection is a result of undo/redo operation - if it is, we might be in the middle of collection changed // notification, so i have to postpone variable scope update untill collection update is completed. if (this.Context.Services.GetService ().IsUndoRedoInProgress) { //delegate call to update selection after update is completed this.Dispatcher.BeginInvoke(new Action(() => { //get current selection - i can't use newSelection passed into the method, because undo/redo may alter that value var current = this.Context.Items.GetValue ().PrimarySelection; //do the actual selection update this.OnItemSelectedCore(current); }), DispatcherPriority.ApplicationIdle); } else { //store element selected before variable designer started updating selection - when designer is closed, we try to restore that selection this.StoreLastSelection(); this.OnItemSelectedCore(newSelection.PrimarySelection); } } } void OnItemSelectedCore(ModelItem primarySelection) { //update variable scope - but ignore selection changes made by selecting variables. if (null == primarySelection || !primarySelection.IsAssignableFrom ()) { ModelItem element = VariableHelper.GetVariableScopeElement(primarySelection); this.CurrentVariableScope = VariableHelper.GetVariableCollection(element); } } void OnVariableScopeChanged() { this.Populate(null != this.CurrentVariableScope ? this.CurrentVariableScope.Parent : null); } void OnVariableCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { var isUndoRedoInProgress = this.Context.Services.GetService ().IsUndoRedoInProgress; switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (ModelItem variable in e.NewItems) { DesignTimeVariable wrapper = this.variableWrapperCollection .FirstOrDefault (p => (ModelItem.Equals(p.ReflectedObject, variable))); if (wrapper == null) { wrapper = new DesignTimeVariable(variable, this); this.variableWrapperCollection.Add(wrapper); } if (null != this.variableToSelect && this.variableToSelect == variable) { this.variableDataGrid.SelectedItem = wrapper; this.variableToSelect = null; int index = this.variableDataGrid.Items.IndexOf(this.variableDataGrid.SelectedItem); DataGridRow row = DataGridHelper.GetRow(this.variableDataGrid, index); if (!row.IsSelected) { row.IsSelected = true; } if (this.continueScopeEdit) { DataGridCell cell = DataGridHelper.GetCell(this.variableDataGrid, index, 2); cell.IsEditing = true; } } } break; case NotifyCollectionChangedAction.Remove: foreach (ModelItem variable in e.OldItems) { DesignTimeVariable wrapper = this.variableWrapperCollection.FirstOrDefault(p => ModelItem.Equals(p.ReflectedObject, variable)); if (null != wrapper) { //in case of undo/redo operation - just remove old reference to the wrapper, new one will be added be undo stack anyway if (!this.ScopesList.Contains((sender as ModelItem).Parent) || isUndoRedoInProgress) { this.variableWrapperCollection.Remove(wrapper); } } } break; } this.RaiseEvent(new RoutedEventArgs(VariableDesigner.VariableCollectionChangedEvent, this)); } void OnVariableWrapperCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Remove: foreach (DesignTimeVariable arg in e.OldItems) { if (this.trackVariableWrapperContainerChanges) { this.ClearCaseInsensitiveDuplicates(arg.GetVariableName(), (string)arg.ReflectedObject.Properties["Name"].ComputedValue); ModelItemCollection collection = (ModelItemCollection)arg.ReflectedObject.Parent; collection.Remove(arg.ReflectedObject); } arg.Dispose(); } break; case NotifyCollectionChangedAction.Add: foreach (DesignTimeVariable var in e.NewItems) { this.CheckCaseInsensitiveDuplicates(var.GetVariableName(), (string)var.ReflectedObject.Properties["Name"].ComputedValue); } break; } } void OnVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { if (bool.Equals(true, e.NewValue)) { this.StoreLastSelection(); this.OnVariableScopeChanged(); } else if (this.variableDataGrid.SelectedItem is DesignTimeVariable) { Selection newSelection = null == this.lastSelection ? new Selection() : new Selection(this.lastSelection); this.isSelectionSourceInternal = true; this.Context.Items.SetValue(newSelection); this.variableDataGrid.SelectedItem = null; this.isSelectionSourceInternal = false; } } bool OnResolveDynamicContentTemplate(ResolveTemplateParams resolveParams) { var variable = (DesignObjectWrapper)resolveParams.Cell.DataContext; //get editor associated with variable's value var editorType = variable.GetDynamicPropertyValueEditorType(DesignTimeVariable.VariableValueProperty); //if yes there is a custom one - use it if (!typeof(ExpressionValueEditor).IsAssignableFrom(editorType)) { //get inline editor template - it will be used for both templates - view and editing; resolveParams.Template = variable.GetDynamicPropertyValueEditor(DesignTimeVariable.VariableValueProperty).InlineEditorTemplate; resolveParams.IsDefaultTemplate = false; } else { //no custom editor - depending on grid state display either editable or readonly expression template string key = resolveParams.Cell.IsEditing ? "variableExpressionEditableTemplate" : "variableExpressionReadonlyTemplate"; resolveParams.Template = (DataTemplate)this.FindResource(key); resolveParams.IsDefaultTemplate = true; } return true; } DialogPropertyValueEditor OnLoadExtendedValueEditor(DataGridCell cell, object instance) { var variable = (DesignObjectWrapper)cell.DataContext; return variable.GetDynamicPropertyValueEditor(DesignTimeVariable.VariableValueProperty) as DialogPropertyValueEditor; } ModelProperty OnShowExtendedValueEditor(DataGridCell cell, object instance) { var variable = (DesignObjectWrapper)cell.DataContext; return variable.Content.Properties[DesignTimeVariable.VariableValueProperty]; } static void OnContextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { ((VariableDesigner)sender).OnContextChanged(); } static void OnVariableScopeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { VariableDesigner control = (VariableDesigner)sender; if (!object.Equals(e.OldValue, e.NewValue)) { control.OnVariableScopeChanged(); } } } internal static class VariableHelper { static Type VariablesCollectionType = typeof(Collection ); static Type CodeActivityType = typeof(CodeActivity); static Type GenericCodeActivityType = typeof(CodeActivity<>); static Type AsyncCodeActivityType = typeof(AsyncCodeActivity); static Type GenericAsyncCodeActivityType = typeof(AsyncCodeActivity<>); internal static ModelItemCollection GetVariableCollection(this ModelItem element) { if (null != element) { Type elementType = element.ItemType; if (!((CodeActivityType.IsAssignableFrom(elementType)) || (GenericAsyncCodeActivityType.IsAssignableFrom(elementType)) || (AsyncCodeActivityType.IsAssignableFrom(elementType)) || (GenericAsyncCodeActivityType.IsAssignableFrom(elementType)))) { ModelProperty variablesProperty = element.Properties["Variables"]; if ((variablesProperty != null) && (variablesProperty.PropertyType == VariablesCollectionType)) { return variablesProperty.Collection; } } } return null; } internal static ModelItem GetVariableScopeElement(this ModelItem element) { while (null != element && null == VariableHelper.GetVariableCollection(element)) { element = element.Parent; } return element; } internal static List FindDeclaredVariables(this ModelItem element, IList scopeList) { var variables = VariableHelper.FindVariablesInScope(element, scopeList); var contained = VariableHelper.GetVariableCollection(element); if (null != contained) { if (null != scopeList) { scopeList.Insert(0, element); } variables.InsertRange(0, contained.AsEnumerable()); } return variables; } internal static List FindDeclaredVariables(this ModelItem element) { return VariableHelper.FindDeclaredVariables(element, null); } internal static List FindActionHandlerVariables(this ModelItem workflowElement) { List variables = new List (); while (null != workflowElement) //if (null != workflowElement) { //variables = IEnumerable > actionHandlers = //take into account all properties defined in workflow element workflowElement.Properties. //select only those, which can be assigned to ActivityDelegate Where (p => typeof(ActivityDelegate).IsAssignableFrom(p.PropertyType)). //from those, take actual ModelItem value and and get its properties Select(p => p.Value == null ? Enumerable.Empty () : p.Value.Properties); //there might be many(?) action handlers within one activity, so get variables from all of them foreach (IEnumerable actionHandler in actionHandlers) { //browse all properties in given action handler IEnumerable variablesInScope = actionHandler. //choose only those of base type equal to DelegateArgument Where (p => (typeof(DelegateArgument).IsAssignableFrom(p.PropertyType) && null != p.Value)). //from those, take actual ModelItem value Select (p => p.Value); //if anything is returned - add it to variables list variables.AddRange(variablesInScope); } workflowElement = workflowElement.Parent; } return variables; } internal static List FindVariablesInScope(this ModelItem element, IList scopeList) { List variables = new List (); if (null != scopeList) { scopeList.Clear(); } if (null != element) { element = element.Parent; while (element != null) { ModelItemCollection variablesInElement = VariableHelper.GetVariableCollection(element); if (null != variablesInElement) { if (null != scopeList) { scopeList.Add(element); } variables.AddRange(variablesInElement.AsEnumerable()); } element = element.Parent; } } return variables; } internal static List FindUniqueVariablesInScope(ModelItem element) { Dictionary variables = new Dictionary (); while (element != null) { ModelItemCollection variablesInElement = VariableHelper.GetVariableCollection(element); if (null != variablesInElement) { foreach (ModelItem modelVariable in variablesInElement) { LocationReference locationReference = modelVariable.GetCurrentValue() as LocationReference; if (locationReference != null && !string.IsNullOrWhiteSpace(locationReference.Name) && !variables.ContainsKey(locationReference.Name)) { variables.Add(locationReference.Name, modelVariable); } } } element = element.Parent; } return new List (variables.Values); } internal static List FindVariablesInScope(ModelItem element) { return VariableHelper.FindVariablesInScope(element, null); } internal static bool ContainsVariable(this ModelItemCollection variableContainer, string variableName) { if (null == variableContainer) { throw FxTrace.Exception.AsError(new ArgumentNullException("variableContainer")); } if (!variableContainer.ItemType.IsGenericType || variableContainer.ItemType.GetGenericArguments().Length != 1 || !typeof(Variable).IsAssignableFrom(variableContainer.ItemType.GetGenericArguments()[0])) { throw FxTrace.Exception.AsError(new ArgumentException("non variable collection")); } return variableContainer.Any(p => string.Equals(p.Properties[DesignTimeVariable.VariableNameProperty].ComputedValue, variableName)); } internal static string CreateUniqueVariableName(this ModelItemCollection variableContainer, string namePrefix, int countStartValue) { if (null == variableContainer) { throw FxTrace.Exception.AsError(new ArgumentNullException("variableContainer")); } if (!variableContainer.ItemType.IsGenericType || variableContainer.ItemType.GetGenericArguments().Length != 1 || !typeof(Variable).IsAssignableFrom(variableContainer.ItemType.GetGenericArguments()[0])) { throw FxTrace.Exception.AsError(new ArgumentException("non variable collection")); } string name = string.Empty; //in order to generate unique variable name, browse all scopes from current to the root - variable name should be unique in whole tree up to //the root. we don't check unique check below current scope - it would be too expensive to ---- whole tree var variables = VariableHelper.FindVariablesInScope(variableContainer); while (true) { name = string.Format(CultureInfo.CurrentUICulture, "{0}{1}", namePrefix, countStartValue++); if (!variables.Any(p => string.Equals(p.Properties[DesignTimeVariable.VariableNameProperty].ComputedValue, name))) { break; } } return name; } internal static ModelItem FindRootVariableScope(ModelItem element) { if (null == element) { throw FxTrace.Exception.ArgumentNull("element"); } ModelItem result = element.GetParentEnumerator().Where(p => null != VariableHelper.GetVariableCollection(p)).LastOrDefault(); return result; } internal static ModelItem FindCommonVariableScope(ModelItem scope1, ModelItem scope2) { if (null == scope1 || null == scope2) { throw FxTrace.Exception.AsError(new ArgumentNullException(null == scope1 ? "scope1" : "scope2")); } var scope1List = scope1.GetParentEnumerator().Where(p => null != VariableHelper.GetVariableCollection(p)).ToList(); var scope2List = scope2.GetParentEnumerator().Where(p => null != VariableHelper.GetVariableCollection(p)).ToList(); if (null != VariableHelper.GetVariableCollection(scope1)) { scope1List.Insert(0, scope1); } if (null != VariableHelper.GetVariableCollection(scope2)) { scope2List.Insert(0, scope2); } if (scope1 == scope2) { return scope1List.FirstOrDefault(); } return scope1List.Intersect(scope2List).FirstOrDefault(); } } sealed class DesignTimeVariable : DesignObjectWrapper { internal static readonly string VariableNameProperty = "Name"; internal static readonly string VariableTypeProperty = "Type"; internal static readonly string VariableScopeProperty = "Scope"; internal static readonly string VariableValueProperty = "Default"; internal static readonly string ToolTipProperty = "ToolTip"; internal static readonly string VariableScopeLevelProperty = "ScopeLevel"; internal static readonly string VariableModifiersProperty = "Modifiers"; static readonly string[] Properties = new string[] { VariableNameProperty, VariableTypeProperty, VariableScopeProperty, VariableValueProperty, ToolTipProperty, VariableScopeLevelProperty, VariableModifiersProperty }; bool variableTypeChanged = false; internal VariableDesigner Editor { get; private set; } VBIdentifierName identifierName; #region Initialize type properties code public static PropertyDescriptorData[] InitializeTypeProperties() { return new PropertyDescriptorData[] { new PropertyDescriptorData() { PropertyName = VariableNameProperty, PropertyType = typeof(VBIdentifierName), PropertyAttributes = TypeDescriptor.GetAttributes(typeof(VBIdentifierName)).OfType ().ToArray(), PropertySetter = (instance, newValue) => { ((DesignTimeVariable)instance).SetVariableName((VBIdentifierName)newValue); }, PropertyGetter = (instance) => (((DesignTimeVariable)instance).GetVariableName()), PropertyValidator = (instance, value, errors) => (((DesignTimeVariable)instance).ValidateVariableName(value, errors)) }, new PropertyDescriptorData() { PropertyName = VariableTypeProperty, PropertyType = typeof(Type), PropertyAttributes = TypeDescriptor.GetAttributes(typeof(Type)).OfType ().ToArray(), PropertySetter = (instance, newValue) => { ((DesignTimeVariable)instance).SetVariableType((Type)newValue); }, PropertyGetter = (instance) => (((DesignTimeVariable)instance).GetVariableType()), PropertyValidator = null }, new PropertyDescriptorData() { PropertyName = VariableScopeProperty, PropertyType = typeof(ModelItem), PropertyAttributes = TypeDescriptor.GetAttributes(typeof(ModelItem)).OfType ().Union(new Attribute[] { new EditorAttribute(typeof(ScopeValueEditor), typeof(PropertyValueEditor))}).ToArray(), PropertySetter = (instance, newValue) => { ((DesignTimeVariable)instance).SetVariableScope(newValue); }, PropertyGetter = (instance) => (((DesignTimeVariable)instance).GetVariableScope()), PropertyValidator = (instance, value, errors) => (((DesignTimeVariable)instance).ValidateVariableScope(value, errors)) }, new PropertyDescriptorData() { PropertyName = VariableValueProperty, PropertyType = typeof(Activity), PropertyAttributes = TypeDescriptor.GetAttributes(typeof(Activity)).OfType ().Union(new Attribute[] { new EditorAttribute(typeof(DesignObjectWrapperDynamicPropertyEditor), typeof(DialogPropertyValueEditor)), new EditorReuseAttribute(false) }).ToArray(), PropertySetter = (instance, newValue) => { ((DesignTimeVariable)instance).SetVariableValue(newValue); }, PropertyGetter = (instance) => (((DesignTimeVariable)instance).GetVariableValue()), PropertyValidator = null, }, new PropertyDescriptorData() { PropertyName = ToolTipProperty, PropertyType = typeof(string), PropertyAttributes = new Attribute[] { BrowsableAttribute.No }, PropertySetter = null, PropertyGetter = (instance) => (((DesignTimeVariable)instance).GetToolTip()), PropertyValidator = null }, new PropertyDescriptorData() { PropertyName = VariableScopeLevelProperty, PropertyType = typeof(int), PropertyAttributes = new Attribute[] { BrowsableAttribute.No }, PropertySetter = null, PropertyValidator = null, PropertyGetter = (instance) => ( ((DesignTimeVariable)instance).GetScopeLevel() ), }, new PropertyDescriptorData() { PropertyName = VariableModifiersProperty, PropertyType = typeof(VariableModifiers), PropertyAttributes = TypeDescriptor.GetAttributes(typeof(VariableModifiers)).OfType ().ToArray(), PropertySetter = (instance, newValue) => { ((DesignTimeVariable)instance).SetVariableModifiers(newValue); }, PropertyValidator = null, PropertyGetter = (instance) => { return ((DesignTimeVariable)instance).GetVariableModifiers(); } } }; } #endregion public DesignTimeVariable() { throw FxTrace.Exception.AsError(new NotSupportedException(SR.InvalidConstructorCall)); } internal DesignTimeVariable(ModelItem modelItem, VariableDesigner editor) : base(modelItem) { this.Editor = editor; this.identifierName = new VBIdentifierName { IdentifierName = (string)modelItem.Properties[VariableNameProperty].ComputedValue }; } protected override string AutomationId { get { return this.GetVariableNameString(); } } void SetVariableName(VBIdentifierName identifierName) { using (ModelEditingScope change = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeVariableNameDescription"))) { this.identifierName = identifierName; string name = this.identifierName.IdentifierName; this.Editor.NotifyVariableNameChanged(this.identifierName, name, (string)this.ReflectedObject.Properties[VariableNameProperty].ComputedValue); this.ReflectedObject.Properties[VariableNameProperty].SetValue(name); change.Complete(); } } internal VBIdentifierName GetVariableName() { return this.identifierName; } string GetVariableNameString() { return (string)this.ReflectedObject.Properties[VariableNameProperty].ComputedValue; } protected override void OnReflectedObjectPropertyChanged(string propertyName) { if (propertyName == VariableNameProperty) { string oldValue = this.identifierName.IdentifierName; string newValue = GetVariableNameString(); //This is invoked in undo stack if (oldValue != newValue) { this.identifierName = new VBIdentifierName { IdentifierName = newValue }; Editor.NotifyVariableNameChanged(this.identifierName, newValue, oldValue); } } } void SetVariableModifiers(object modifiers) { this.ReflectedObject.Properties[VariableModifiersProperty].SetValue( modifiers is ModelItem ? (modifiers as ModelItem).GetCurrentValue() : modifiers); } object GetVariableModifiers() { return this.ReflectedObject.Properties[VariableModifiersProperty].ComputedValue; } int GetScopeLevel() { int level = 0; ModelItem parent = this.ReflectedObject.Parent; while (null != parent) { ++level; parent = parent.Parent; } return level; } // Used by screen reader to read the DataGrid row. public override string ToString() { string name = this.GetVariableNameString(); if (!string.IsNullOrEmpty(name)) { return name; } return "Variable"; } void SetVariableType(Type type) { if (!Type.Equals(type, this.GetVariableType())) { using (ModelEditingScope change = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeVariableTypeDescription"))) { this.variableTypeChanged = true; ModelItemCollection variableContainer = (ModelItemCollection)this.ReflectedObject.Parent; //proceed only if variable is associated with container if (null != variableContainer) { Variable variable = Variable.Create(this.GetVariableNameString(), type, (VariableModifiers)this.GetVariableModifiers()); //try to preserve expression ModelItem expressionModelItem = this.ReflectedObject.Properties[VariableValueProperty].Value; if (expressionModelItem != null) { Activity expression = expressionModelItem.GetCurrentValue() as Activity; string currentExpression = ExpressionHelper.GetExpressionString(expression, expressionModelItem); //check if there exists expression if (currentExpression != null) { //finally - assign result to default property variable.Default = ExpressionHelper.CreateExpression(type, currentExpression, false, null); } } Editor.ChangeVariableType(this, variable); ImportDesigner.AddImport(type.Namespace, this.Context); } change.Complete(); } } } Type GetVariableType() { return (Type)this.ReflectedObject.Properties[VariableTypeProperty].ComputedValue; } void SetVariableScope(object newScope) { using (ModelEditingScope change = this.ReflectedObject.BeginEdit((string)this.Editor.FindResource("changeVariableScopeDescription"))) { if (!ModelItem.Equals(newScope, this.GetVariableScope())) { ModelItemCollection currentScopeContainer = this.ReflectedObject.Parent.Parent.Properties["Variables"].Collection; currentScopeContainer.Remove(this.ReflectedObject.GetCurrentValue()); ModelItem scope = (newScope as ModelItem) ?? Editor.ScopesList.FirstOrDefault(p => object.Equals(p.GetCurrentValue(), newScope)); ModelItemCollection newScopeContainer = scope.Properties["Variables"].Collection; newScopeContainer.Add(this.ReflectedObject.GetCurrentValue()); Editor.NotifyVariableScopeChanged(this); } change.Complete(); } } object GetVariableScope() { return this.ReflectedObject.Parent.Parent; } void SetVariableValue(object value) { object expression = value is ModelItem ? ((ModelItem)value).GetCurrentValue() : value; this.ReflectedObject.Properties[VariableValueProperty].SetValue(expression); } object GetVariableValue() { return this.ReflectedObject.Properties[VariableValueProperty].ComputedValue; } string GetToolTip() { ModelItem s = this.ReflectedObject.Parent.Parent; IMultiValueConverter converter = (IMultiValueConverter)(this.Editor.FindResource("scopeToNameConverter")); return ScopeToTooltipConverter.BuildToolTip(s, converter, CultureInfo.CurrentCulture); } protected override Type OnGetDynamicPropertyValueEditorType(string propertyName) { var type = this.GetVariableType(); //in case of variables which contain handles - display HandleValueEditor if (typeof(Handle).IsAssignableFrom(type)) { return typeof(HandleValueEditor); } var referenceType = typeof(PropertyValueEditor); var expressionEditorType = typeof(ExpressionValueEditor); //check if there are custom editors on the variable's type var variableOfType = typeof(Variable<>).MakeGenericType(type); //check if there are custom type editors associated with given type - //look for type editor defined for Variable //in search, skip ExpressionValueEditor instance - it will be returned by default for property grid, but for //dataGrid nothing should be used - we use default dg template var customEditorType = TypeDescriptor .GetAttributes(variableOfType) .OfType () .Where(p => { Type currentType = Type.GetType(p.EditorTypeName); return (expressionEditorType != currentType && referenceType.IsAssignableFrom(currentType)); }) .Select(p => Type.GetType(p.EditorTypeName)) .FirstOrDefault(); //return custom editor type (if any) if (null != customEditorType) { return customEditorType; } //otherwise - return default expression value editor return typeof(ExpressionValueEditor); } protected override void OnPropertyChanged(string propertyName) { //this method is called by the thread's dispatcher AFTER all prorties have been updated, so all the property values //are updated, regardless of the editing scope deep if (string.Equals(propertyName, DesignTimeVariable.VariableScopeProperty)) { this.RaisePropertyChangedEvent(ToolTipProperty); this.RaisePropertyChangedEvent(VariableScopeLevelProperty); } else if (string.Equals(propertyName, DesignTimeVariable.VariableNameProperty)) { this.RaisePropertyChangedEvent(AutomationIdProperty); } else if (string.Equals(propertyName, DesignTimeVariable.VariableTypeProperty)) { this.RaisePropertyChangedEvent(VariableValueProperty); } else if (string.Equals(propertyName, DesignTimeVariable.TimestampProperty)) { if (this.variableTypeChanged) { this.variableTypeChanged = false; this.CustomValueEditors.Clear(); this.Editor.UpdateTypeDesigner(this); } } base.OnPropertyChanged(propertyName); } bool ValidateVariableName(object newValue, List errors) { if (!base.IsUndoRedoInProgress && null != this.ReflectedObject.Parent) { VBIdentifierName identifier = newValue as VBIdentifierName; string newName = null; if (identifier != null) { newName = identifier.IdentifierName; } if (!string.IsNullOrEmpty(newName)) { Func checkForDuplicates = new Func (p => string.Equals(p.Properties[VariableNameProperty].ComputedValue, newName) && !object.Equals(p, this.ReflectedObject)); bool duplicates = this.ReflectedObject.Parent.Parent.Properties["Variables"].Collection.Any(checkForDuplicates); if (duplicates) { errors.Add(string.Format(CultureInfo.CurrentUICulture, SR.DuplicateVariableName, newName)); } } else { errors.Add(SR.EmptyVariableName); } } return 0 == errors.Count; } bool ValidateVariableScope(object newValue, List errors) { if (!base.IsUndoRedoInProgress) { ModelItem scope = (newValue as ModelItem) ?? Editor.ScopesList.FirstOrDefault(p => object.Equals(p.GetCurrentValue(), newValue)); string currentName = this.GetVariableNameString(); Func checkForDuplicates = new Func (p => string.Equals(p.Properties[VariableNameProperty].ComputedValue, currentName) && !object.Equals(p, this.ReflectedObject)); bool duplicates = scope.Properties["Variables"].Collection.Any(checkForDuplicates); if (duplicates) { errors.Add(string.Format(CultureInfo.CurrentUICulture, SR.DuplicateVariableName, currentName)); } } return 0 == errors.Count; } #region Internal classes internal sealed class ScopeValueEditor : PropertyValueEditor { public ScopeValueEditor() { this.InlineEditorTemplate = EditorResources.GetResources()["ScopeEditor_InlineEditorTemplate"] as DataTemplate; } } #endregion } sealed class DesignTimeVariableToScopeConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { ModelItem designTimeVariable = value as ModelItem; object result = null; if (null != designTimeVariable && typeof(DesignTimeVariable).IsAssignableFrom(designTimeVariable.ItemType)) { DesignTimeVariable variable = (DesignTimeVariable)designTimeVariable.GetCurrentValue(); result = variable.Editor.ScopesList; } return result; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw FxTrace.Exception.AsError(new NotSupportedException()); } } sealed class ScopeToTooltipConverter : IValueConverter { IMultiValueConverter baseConverter = new BreadCrumbTextConverter(); internal static string BuildToolTip(ModelItem entry, IMultiValueConverter displayNameConverter, CultureInfo culture) { string result = null; if (null != entry && null != displayNameConverter) { StringBuilder sb = new StringBuilder(); int indent = 0; ModelItem currentEntry = entry; while (currentEntry != null) { if (null != currentEntry.Properties["Variables"]) { ++indent; } currentEntry = currentEntry.Parent; } while (entry != null) { if (null != entry.Properties["Variables"]) { if (sb.Length != 0) { sb.Insert(0, "/"); sb.Insert(0, " ", --indent); sb.Insert(0, Environment.NewLine); } var input = new object[] { entry, null != entry.Properties["DisplayName"] ? entry.Properties["DisplayName"].Value : null, (double)short.MaxValue }; sb.Insert(0, displayNameConverter.Convert(input, typeof(string), null, culture)); } entry = entry.Parent; } result = sb.ToString(); } return result; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return BuildToolTip(value as ModelItem, this.baseConverter, culture); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw FxTrace.Exception.AsError(new NotSupportedException()); } } sealed class ScopeComboBox : ComboBox { bool isScopeValid = true; protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); this.Loaded += (s, args) => { //get the binding expression, and hook up exception filter var expr = this.GetBindingExpression(ScopeComboBox.SelectedItemProperty); if (null != expr && null != expr.ParentBinding) { expr.ParentBinding.UpdateSourceExceptionFilter = this.OnUpdateBindingException; } }; } object OnUpdateBindingException(object sender, Exception err) { //if exception occured, the scope as invalid if (err is TargetInvocationException && err.InnerException is ValidationException || err is ValidationException) { this.isScopeValid = false; } return null; } protected override void OnSelectionChanged(SelectionChangedEventArgs e) { //if validation succeeded - update the control state with new selection if (this.isScopeValid) { base.OnSelectionChanged(e); } //otherwise, get the binding expression and update control with current state from the source else { var expr = this.GetBindingExpression(ScopeComboBox.SelectedItemProperty); if (null != expr) { expr.UpdateTarget(); } //the next failed validation pass may set this flag to false, but if validation succeeds, it has to be set to true this.isScopeValid = true; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WindowsImpersonationContext.cs
- Label.cs
- ExplicitDiscriminatorMap.cs
- MatcherBuilder.cs
- X509Utils.cs
- SystemResourceHost.cs
- DomNameTable.cs
- FilterQueryOptionExpression.cs
- TemplateBamlTreeBuilder.cs
- StateRuntime.cs
- CuspData.cs
- DetailsViewUpdatedEventArgs.cs
- StrokeFIndices.cs
- NonVisualControlAttribute.cs
- RegistryPermission.cs
- GifBitmapDecoder.cs
- PerspectiveCamera.cs
- EllipseGeometry.cs
- SectionXmlInfo.cs
- AmbientLight.cs
- ObjectReaderCompiler.cs
- ProfileServiceManager.cs
- CalendarData.cs
- ContentType.cs
- ApplicationDirectory.cs
- ListViewInsertionMark.cs
- FixedSchema.cs
- ListViewGroupCollectionEditor.cs
- CmsUtils.cs
- CopyOfAction.cs
- ConnectionProviderAttribute.cs
- SmtpClient.cs
- FrameworkElementFactory.cs
- WizardStepBase.cs
- CellCreator.cs
- Propagator.JoinPropagator.JoinPredicateVisitor.cs
- SqlMethodTransformer.cs
- ServiceElement.cs
- ExecutionScope.cs
- LocatorManager.cs
- WizardPanel.cs
- LinearKeyFrames.cs
- SqlFunctionAttribute.cs
- Int32RectConverter.cs
- XmlSchemaImporter.cs
- SecurityContext.cs
- TimeEnumHelper.cs
- TerminateSequenceResponse.cs
- ActivityScheduledQuery.cs
- PolyQuadraticBezierSegment.cs
- EdmProviderManifest.cs
- HostedTcpTransportManager.cs
- hebrewshape.cs
- AuthorizationContext.cs
- SelectionEditingBehavior.cs
- SecureUICommand.cs
- ClientConvert.cs
- ISessionStateStore.cs
- TypeContext.cs
- Semaphore.cs
- CodeMethodReturnStatement.cs
- UnitySerializationHolder.cs
- Decimal.cs
- returneventsaver.cs
- XPathNodeList.cs
- ApplicationFileCodeDomTreeGenerator.cs
- FrameworkPropertyMetadata.cs
- IncrementalCompileAnalyzer.cs
- IndicCharClassifier.cs
- HitTestResult.cs
- TextChangedEventArgs.cs
- DependencyObjectProvider.cs
- ChannelSettingsElement.cs
- RegexNode.cs
- SettingsAttributeDictionary.cs
- CompiledXpathExpr.cs
- Decimal.cs
- WebPageTraceListener.cs
- SqlCommandSet.cs
- ScriptControlDescriptor.cs
- X509Certificate.cs
- DrawingGroup.cs
- DATA_BLOB.cs
- DecimalConstantAttribute.cs
- JsonEnumDataContract.cs
- OutputCacheProfileCollection.cs
- StringStorage.cs
- MailDefinition.cs
- WebDescriptionAttribute.cs
- Pointer.cs
- BuildManager.cs
- RegexFCD.cs
- WizardStepBase.cs
- HttpApplicationStateWrapper.cs
- XhtmlBasicImageAdapter.cs
- CodeTypeDeclaration.cs
- ComboBoxRenderer.cs
- ToolStripStatusLabel.cs
- FrameworkElementAutomationPeer.cs
- EventHandlerList.cs