937 lines
42 KiB
C#
937 lines
42 KiB
C#
|
namespace System.Workflow.ComponentModel.Design
|
||
|
{
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using System.ComponentModel;
|
||
|
using System.ComponentModel.Design;
|
||
|
using System.Workflow.ComponentModel.Serialization;
|
||
|
using System.ComponentModel.Design.Serialization;
|
||
|
using System.IO;
|
||
|
using System.Windows.Forms;
|
||
|
using System.Drawing.Design;
|
||
|
using System.Security.Permissions;
|
||
|
using System.Xml;
|
||
|
using System.Workflow.ComponentModel.Compiler;
|
||
|
using System.Collections.ObjectModel;
|
||
|
|
||
|
#region Class WorkflowDesignerLoader
|
||
|
[PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
|
||
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
||
|
public abstract class WorkflowDesignerLoader : BasicDesignerLoader
|
||
|
{
|
||
|
#region Members, Construction and Dispose
|
||
|
internal const string DesignerLayoutFileExtension = ".layout";
|
||
|
|
||
|
private CustomActivityDesignerAdapter customActivityDesignerAdapter;
|
||
|
private WorkflowDesignerEventsCoordinator eventsCoordinator;
|
||
|
private Hashtable createdServices = null;
|
||
|
private bool loadingDesignerLayout = false;
|
||
|
|
||
|
static WorkflowDesignerLoader()
|
||
|
{
|
||
|
ComponentDispenser.RegisterComponentExtenders(typeof(CustomActivityDesignerAdapter), new IExtenderProvider[] { new CustomActivityPropertyExtender() });
|
||
|
}
|
||
|
|
||
|
protected override void Initialize()
|
||
|
{
|
||
|
base.Initialize();
|
||
|
|
||
|
//PLEASE NOTE THE FOLLOWING CODE IS ADDED TO MAKE THE SPECIFIC DESIGNER TYPE INTERNAL
|
||
|
//This is a work around for invoke workflow so that the ActivityHostDesignerType does not become public
|
||
|
//Please refer to file WorkflowInlining.cs
|
||
|
Type invokeWorkflowType = Type.GetType(InvokeWorkflowDesigner.InvokeWorkflowRef);
|
||
|
if (invokeWorkflowType != null)
|
||
|
TypeDescriptor.AddAttributes(invokeWorkflowType, new DesignerAttribute(typeof(InvokeWorkflowDesigner), typeof(IDesigner)));
|
||
|
|
||
|
//Add all the services, it is important to make sure that if user pushes the services then we honor
|
||
|
//those services
|
||
|
LoaderHost.AddService(typeof(WorkflowDesignerLoader), this);
|
||
|
|
||
|
ServiceCreatorCallback callback = new ServiceCreatorCallback(OnCreateService);
|
||
|
if (LoaderHost.GetService(typeof(IWorkflowCompilerOptionsService)) == null)
|
||
|
LoaderHost.AddService(typeof(IWorkflowCompilerOptionsService), callback);
|
||
|
|
||
|
if (LoaderHost.GetService(typeof(IIdentifierCreationService)) == null)
|
||
|
LoaderHost.AddService(typeof(IIdentifierCreationService), callback);
|
||
|
|
||
|
if (LoaderHost.GetService(typeof(ComponentSerializationService)) == null)
|
||
|
LoaderHost.AddService(typeof(ComponentSerializationService), callback);
|
||
|
|
||
|
LoaderHost.RemoveService(typeof(IReferenceService));
|
||
|
if (LoaderHost.GetService(typeof(IReferenceService)) == null)
|
||
|
LoaderHost.AddService(typeof(IReferenceService), callback);
|
||
|
|
||
|
if (LoaderHost.GetService(typeof(IDesignerVerbProviderService)) == null)
|
||
|
LoaderHost.AddService(typeof(IDesignerVerbProviderService), callback);
|
||
|
|
||
|
//Add all the extenders, the extenders are responsible to add the extended properties which are not
|
||
|
//actual properties on activity
|
||
|
IExtenderProviderService extenderProviderService = GetService(typeof(IExtenderProviderService)) as IExtenderProviderService;
|
||
|
if (extenderProviderService != null)
|
||
|
{
|
||
|
foreach (IExtenderProvider extender in ComponentDispenser.Extenders)
|
||
|
extenderProviderService.AddExtenderProvider(extender);
|
||
|
}
|
||
|
|
||
|
this.customActivityDesignerAdapter = new CustomActivityDesignerAdapter(LoaderHost);
|
||
|
}
|
||
|
|
||
|
public override void Dispose()
|
||
|
{
|
||
|
if (this.eventsCoordinator != null)
|
||
|
{
|
||
|
((IDisposable)this.eventsCoordinator).Dispose();
|
||
|
this.eventsCoordinator = null;
|
||
|
}
|
||
|
|
||
|
if (this.customActivityDesignerAdapter != null)
|
||
|
{
|
||
|
((IDisposable)this.customActivityDesignerAdapter).Dispose();
|
||
|
this.customActivityDesignerAdapter = null;
|
||
|
}
|
||
|
|
||
|
IExtenderProviderService extenderProviderService = GetService(typeof(IExtenderProviderService)) as IExtenderProviderService;
|
||
|
if (extenderProviderService != null)
|
||
|
{
|
||
|
foreach (IExtenderProvider extender in ComponentDispenser.Extenders)
|
||
|
extenderProviderService.RemoveExtenderProvider(extender);
|
||
|
}
|
||
|
|
||
|
if (LoaderHost != null)
|
||
|
{
|
||
|
if (this.createdServices != null)
|
||
|
{
|
||
|
foreach (Type serviceType in this.createdServices.Keys)
|
||
|
{
|
||
|
LoaderHost.RemoveService(serviceType);
|
||
|
OnDisposeService(serviceType, this.createdServices[serviceType]);
|
||
|
}
|
||
|
this.createdServices.Clear();
|
||
|
this.createdServices = null;
|
||
|
}
|
||
|
LoaderHost.RemoveService(typeof(WorkflowDesignerLoader));
|
||
|
}
|
||
|
|
||
|
base.Dispose();
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
#region Public Methods and Properties
|
||
|
public abstract TextReader GetFileReader(string filePath);
|
||
|
|
||
|
public abstract TextWriter GetFileWriter(string filePath);
|
||
|
|
||
|
public abstract string FileName { get; }
|
||
|
|
||
|
public virtual void ForceReload()
|
||
|
{
|
||
|
Reload(ReloadOptions.Force);
|
||
|
}
|
||
|
|
||
|
public override void Flush()
|
||
|
{
|
||
|
base.Flush();
|
||
|
}
|
||
|
|
||
|
public virtual bool InDebugMode
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected virtual TypeDescriptionProvider TargetFrameworkTypeDescriptionProvider
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AddTargetFrameworkProvider(IComponent component)
|
||
|
{
|
||
|
TypeDescriptionProviderService typeDescriptionProviderService = GetService(typeof(TypeDescriptionProviderService)) as TypeDescriptionProviderService;
|
||
|
if (typeDescriptionProviderService != null && component != null)
|
||
|
{
|
||
|
TypeDescriptor.AddProvider(typeDescriptionProviderService.GetProvider(component), component);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void AddActivityToDesigner(Activity activity)
|
||
|
{
|
||
|
if (activity == null)
|
||
|
throw new ArgumentNullException("activity");
|
||
|
|
||
|
IDesignerHost designerHost = GetService(typeof(IDesignerHost)) as IDesignerHost;
|
||
|
if (designerHost == null)
|
||
|
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName));
|
||
|
|
||
|
if (activity.Parent == null && designerHost.RootComponent == null)
|
||
|
{
|
||
|
string fullClassName = activity.GetValue(WorkflowMarkupSerializer.XClassProperty) as String;
|
||
|
string rootSiteName = (!string.IsNullOrEmpty(fullClassName)) ? Helpers.GetClassName(fullClassName) : Helpers.GetClassName(activity.GetType().FullName);
|
||
|
designerHost.Container.Add(activity, rootSiteName);
|
||
|
AddTargetFrameworkProvider(activity);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
designerHost.Container.Add(activity, activity.QualifiedName);
|
||
|
AddTargetFrameworkProvider(activity);
|
||
|
}
|
||
|
|
||
|
if (activity is CompositeActivity)
|
||
|
{
|
||
|
foreach (Activity activity2 in Helpers.GetNestedActivities(activity as CompositeActivity))
|
||
|
{
|
||
|
designerHost.Container.Add(activity2, activity2.QualifiedName);
|
||
|
AddTargetFrameworkProvider(activity2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void RemoveActivityFromDesigner(Activity activity)
|
||
|
{
|
||
|
if (activity == null)
|
||
|
throw new ArgumentNullException("activity");
|
||
|
|
||
|
IDesignerHost designerHost = GetService(typeof(IDesignerHost)) as IDesignerHost;
|
||
|
if (designerHost == null)
|
||
|
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(IDesignerHost).FullName));
|
||
|
|
||
|
designerHost.DestroyComponent(activity);
|
||
|
if (activity is CompositeActivity)
|
||
|
{
|
||
|
foreach (Activity activity2 in Helpers.GetNestedActivities(activity as CompositeActivity))
|
||
|
designerHost.DestroyComponent(activity2);
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
#region Protected Methods and Properties
|
||
|
protected override void PerformLoad(IDesignerSerializationManager serializationManager)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
protected override void PerformFlush(IDesignerSerializationManager serializationManager)
|
||
|
{
|
||
|
SaveDesignerLayout();
|
||
|
}
|
||
|
|
||
|
protected override void OnEndLoad(bool successful, ICollection errors)
|
||
|
{
|
||
|
base.OnEndLoad(successful, errors);
|
||
|
|
||
|
if (successful)
|
||
|
{
|
||
|
//We initialize the events coordinator only once when loading of the designer is complete
|
||
|
ActivityDesigner rootDesigner = ActivityDesigner.GetRootDesigner(LoaderHost);
|
||
|
if (this.eventsCoordinator == null && (rootDesigner == null || rootDesigner.ParentDesigner == null))
|
||
|
this.eventsCoordinator = new WorkflowDesignerEventsCoordinator(LoaderHost);
|
||
|
|
||
|
try
|
||
|
{
|
||
|
this.loadingDesignerLayout = true;
|
||
|
|
||
|
string layoutFileName = DesignerLayoutFileName;
|
||
|
IList layoutErrors = null;
|
||
|
if (File.Exists(layoutFileName))
|
||
|
LoadDesignerLayout(out layoutErrors);
|
||
|
else if (InDebugMode || (ActivityDesigner.GetRootDesigner(LoaderHost) != null && ActivityDesigner.GetRootDesigner(LoaderHost).ParentDesigner != null))
|
||
|
LoadDesignerLayoutFromResource(out layoutErrors);
|
||
|
|
||
|
if (layoutErrors != null)
|
||
|
{
|
||
|
if (errors == null)
|
||
|
errors = new ArrayList();
|
||
|
IList designerErrors = errors as IList;
|
||
|
if (designerErrors != null)
|
||
|
{
|
||
|
foreach (object layoutError in layoutErrors)
|
||
|
designerErrors.Add(layoutError);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
this.loadingDesignerLayout = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected void LoadDesignerLayoutFromResource(Type type, string manifestResourceName, out IList errors)
|
||
|
{
|
||
|
if (type == null)
|
||
|
throw new ArgumentNullException("type");
|
||
|
|
||
|
if (manifestResourceName == null)
|
||
|
throw new ArgumentNullException("manifestResourceName");
|
||
|
|
||
|
if (manifestResourceName.Length == 0)
|
||
|
throw new ArgumentException(SR.GetString(SR.Error_ParameterCannotBeEmpty), "manifestResourceName");
|
||
|
|
||
|
errors = new ArrayList();
|
||
|
|
||
|
Stream stream = type.Module.Assembly.GetManifestResourceStream(type, manifestResourceName);
|
||
|
if (stream == null)
|
||
|
stream = type.Module.Assembly.GetManifestResourceStream(manifestResourceName);
|
||
|
|
||
|
if (stream != null)
|
||
|
{
|
||
|
using (XmlReader layoutReader = XmlReader.Create(stream))
|
||
|
{
|
||
|
if (layoutReader != null)
|
||
|
LoadDesignerLayout(layoutReader, out errors);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected void LoadDesignerLayout(XmlReader layoutReader, out IList layoutLoadErrors)
|
||
|
{
|
||
|
if (layoutReader == null)
|
||
|
throw new ArgumentNullException("layoutReader");
|
||
|
|
||
|
ArrayList errors = new ArrayList();
|
||
|
layoutLoadErrors = errors;
|
||
|
|
||
|
ActivityDesigner rootDesigner = null;
|
||
|
IDesignerHost designerHost = GetService(typeof(IDesignerHost)) as IDesignerHost;
|
||
|
if (designerHost != null && designerHost.RootComponent != null)
|
||
|
rootDesigner = designerHost.GetDesigner(designerHost.RootComponent) as ActivityDesigner;
|
||
|
|
||
|
if (rootDesigner != null)
|
||
|
{
|
||
|
if (rootDesigner.SupportsLayoutPersistence)
|
||
|
{
|
||
|
DesignerSerializationManager serializationManager = new DesignerSerializationManager(LoaderHost);
|
||
|
using (serializationManager.CreateSession())
|
||
|
{
|
||
|
WorkflowMarkupSerializationManager layoutSerializationManager = new WorkflowMarkupSerializationManager(serializationManager);
|
||
|
layoutSerializationManager.AddSerializationProvider(new ActivityDesignerLayoutSerializerProvider());
|
||
|
|
||
|
try
|
||
|
{
|
||
|
new WorkflowMarkupSerializer().Deserialize(layoutSerializationManager, layoutReader);
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
errors.Add(new WorkflowMarkupSerializationException(SR.GetString(SR.Error_LayoutDeserialization), e));
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
if (serializationManager.Errors != null)
|
||
|
errors.AddRange(serializationManager.Errors);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
errors.Add(new WorkflowMarkupSerializationException(SR.GetString(SR.Error_LayoutSerializationPersistenceSupport)));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
errors.Add(new WorkflowMarkupSerializationException(SR.GetString(SR.Error_LayoutSerializationRootDesignerNotFound)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected void SaveDesignerLayout(XmlWriter layoutWriter, ActivityDesigner rootDesigner, out IList layoutSaveErrors)
|
||
|
{
|
||
|
if (layoutWriter == null)
|
||
|
throw new ArgumentNullException("layoutWriter");
|
||
|
|
||
|
if (rootDesigner == null)
|
||
|
throw new ArgumentNullException("rootDesigner");
|
||
|
|
||
|
ArrayList errors = new ArrayList();
|
||
|
layoutSaveErrors = errors;
|
||
|
|
||
|
if (rootDesigner.SupportsLayoutPersistence)
|
||
|
{
|
||
|
DesignerSerializationManager serializationManager = new DesignerSerializationManager(LoaderHost);
|
||
|
using (serializationManager.CreateSession())
|
||
|
{
|
||
|
WorkflowMarkupSerializationManager layoutSerializationManager = new WorkflowMarkupSerializationManager(serializationManager);
|
||
|
layoutSerializationManager.AddSerializationProvider(new ActivityDesignerLayoutSerializerProvider());
|
||
|
|
||
|
try
|
||
|
{
|
||
|
new WorkflowMarkupSerializer().Serialize(layoutSerializationManager, layoutWriter, rootDesigner);
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
errors.Add(new WorkflowMarkupSerializationException(SR.GetString(SR.Error_LayoutSerialization), e));
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
if (serializationManager.Errors != null)
|
||
|
errors.AddRange(serializationManager.Errors);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
errors.Add(new WorkflowMarkupSerializationException(SR.GetString(SR.Error_LayoutSerializationPersistenceSupport)));
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
#region Private Methods and Properties
|
||
|
internal void SetModified(bool modified)
|
||
|
{
|
||
|
if (LoaderHost != null && !LoaderHost.Loading && !this.loadingDesignerLayout)
|
||
|
{
|
||
|
OnModifying();
|
||
|
base.Modified = modified;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal static void AddActivityToDesigner(IServiceProvider serviceProvider, Activity activity)
|
||
|
{
|
||
|
WorkflowDesignerLoader workflowLoader = serviceProvider.GetService(typeof(WorkflowDesignerLoader)) as WorkflowDesignerLoader;
|
||
|
if (workflowLoader == null)
|
||
|
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(WorkflowDesignerLoader).FullName));
|
||
|
|
||
|
workflowLoader.AddActivityToDesigner(activity);
|
||
|
}
|
||
|
|
||
|
internal static void RemoveActivityFromDesigner(IServiceProvider serviceProvider, Activity activity)
|
||
|
{
|
||
|
WorkflowDesignerLoader workflowLoader = serviceProvider.GetService(typeof(WorkflowDesignerLoader)) as WorkflowDesignerLoader;
|
||
|
if (workflowLoader == null)
|
||
|
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(WorkflowDesignerLoader).FullName));
|
||
|
|
||
|
workflowLoader.RemoveActivityFromDesigner(activity);
|
||
|
}
|
||
|
|
||
|
private object OnCreateService(IServiceContainer container, Type serviceType)
|
||
|
{
|
||
|
object createdService = null;
|
||
|
|
||
|
if (serviceType == typeof(ComponentSerializationService))
|
||
|
createdService = new XomlComponentSerializationService(LoaderHost);
|
||
|
else if (serviceType == typeof(IReferenceService))
|
||
|
createdService = new ReferenceService(LoaderHost);
|
||
|
else if (serviceType == typeof(IIdentifierCreationService))
|
||
|
createdService = new IdentifierCreationService(container, this);
|
||
|
else if (serviceType == typeof(IWorkflowCompilerOptionsService))
|
||
|
createdService = new WorkflowCompilerOptionsService();
|
||
|
else if (serviceType == typeof(IDesignerVerbProviderService))
|
||
|
createdService = new DesignerVerbProviderService();
|
||
|
|
||
|
if (createdService != null)
|
||
|
{
|
||
|
if (this.createdServices == null)
|
||
|
this.createdServices = new Hashtable();
|
||
|
object existingService = this.createdServices[serviceType];
|
||
|
this.createdServices[serviceType] = createdService;
|
||
|
if (existingService != null)
|
||
|
{
|
||
|
OnDisposeService(serviceType, existingService);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return createdService;
|
||
|
}
|
||
|
private void OnDisposeService(Type serviceType, object service)
|
||
|
{
|
||
|
if (serviceType == typeof(IReferenceService))
|
||
|
{
|
||
|
ReferenceService refService = service as ReferenceService;
|
||
|
if (refService != null)
|
||
|
{
|
||
|
refService.Dispose();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void LoadDesignerLayoutFromResource(out IList layoutErrors)
|
||
|
{
|
||
|
layoutErrors = null;
|
||
|
|
||
|
IWorkflowRootDesigner rootDesigner = ActivityDesigner.GetSafeRootDesigner(LoaderHost);
|
||
|
if (rootDesigner == null || !rootDesigner.SupportsLayoutPersistence)
|
||
|
return;
|
||
|
|
||
|
Type rootActivityType = rootDesigner.Component.GetType();
|
||
|
string resourceName = rootActivityType.Name + WorkflowDesignerLoader.DesignerLayoutFileExtension;
|
||
|
|
||
|
LoadDesignerLayoutFromResource(rootActivityType, resourceName, out layoutErrors);
|
||
|
}
|
||
|
|
||
|
private void LoadDesignerLayout(out IList layoutErrors)
|
||
|
{
|
||
|
layoutErrors = null;
|
||
|
|
||
|
string layoutFileName = DesignerLayoutFileName;
|
||
|
IWorkflowRootDesigner rootDesigner = ActivityDesigner.GetSafeRootDesigner(LoaderHost);
|
||
|
if (rootDesigner == null || !rootDesigner.SupportsLayoutPersistence || !File.Exists(layoutFileName))
|
||
|
return;
|
||
|
|
||
|
using (TextReader layoutReader = GetFileReader(layoutFileName))
|
||
|
{
|
||
|
if (layoutReader != null)
|
||
|
{
|
||
|
using (XmlReader xmlReader = XmlReader.Create(layoutReader))
|
||
|
LoadDesignerLayout(xmlReader, out layoutErrors);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void SaveDesignerLayout()
|
||
|
{
|
||
|
string layoutFileName = DesignerLayoutFileName;
|
||
|
ActivityDesigner rootDesigner = ActivityDesigner.GetSafeRootDesigner(LoaderHost);
|
||
|
if (String.IsNullOrEmpty(layoutFileName) || rootDesigner == null || !rootDesigner.SupportsLayoutPersistence)
|
||
|
return;
|
||
|
|
||
|
using (TextWriter layoutWriter = GetFileWriter(layoutFileName))
|
||
|
{
|
||
|
if (layoutWriter != null)
|
||
|
{
|
||
|
IList layoutErrors = null;
|
||
|
using (XmlWriter xmlWriter = Helpers.CreateXmlWriter(layoutWriter))
|
||
|
SaveDesignerLayout(xmlWriter, rootDesigner, out layoutErrors);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private string DesignerLayoutFileName
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
string layoutFileName = FileName;
|
||
|
if (!String.IsNullOrEmpty(layoutFileName))
|
||
|
{
|
||
|
layoutFileName = Path.Combine(Path.GetDirectoryName(layoutFileName), Path.GetFileNameWithoutExtension(layoutFileName));
|
||
|
layoutFileName += WorkflowDesignerLoader.DesignerLayoutFileExtension;
|
||
|
}
|
||
|
return layoutFileName;
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
#region Class DesignerVerbProviderService
|
||
|
internal sealed class DesignerVerbProviderService : IDesignerVerbProviderService
|
||
|
{
|
||
|
private List<IDesignerVerbProvider> designerVerbProviders = new List<IDesignerVerbProvider>();
|
||
|
|
||
|
public DesignerVerbProviderService()
|
||
|
{
|
||
|
((IDesignerVerbProviderService)this).AddVerbProvider(new FreeFormDesignerVerbProvider());
|
||
|
}
|
||
|
|
||
|
#region IDesignerVerbProviderService Implementation
|
||
|
void IDesignerVerbProviderService.AddVerbProvider(IDesignerVerbProvider verbProvider)
|
||
|
{
|
||
|
if (!this.designerVerbProviders.Contains(verbProvider))
|
||
|
this.designerVerbProviders.Add(verbProvider);
|
||
|
}
|
||
|
|
||
|
void IDesignerVerbProviderService.RemoveVerbProvider(IDesignerVerbProvider verbProvider)
|
||
|
{
|
||
|
this.designerVerbProviders.Remove(verbProvider);
|
||
|
}
|
||
|
|
||
|
ReadOnlyCollection<IDesignerVerbProvider> IDesignerVerbProviderService.VerbProviders
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this.designerVerbProviders.AsReadOnly();
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
}
|
||
|
#endregion
|
||
|
|
||
|
#region Class WorkflowDesignerEventsCoordinator
|
||
|
//THIS CLASS IS CREATED WITH SOLE PURPOSE OF LISTENING TO COMMON EVENTS AT ONE LOCATION, AND AVOID
|
||
|
//LISTENING TO EVENTS SUCH AS TYPESCHANGED, ACTIVEDESIGNERCHANGED, SELECTIONCHANGED AND COMPONENTCHANGED
|
||
|
//REPEATEDLY
|
||
|
internal sealed class WorkflowDesignerEventsCoordinator : IDisposable
|
||
|
{
|
||
|
private IDesignerLoaderHost serviceProvider;
|
||
|
|
||
|
private bool typeSystemTypesChanged = false;
|
||
|
|
||
|
private EventHandler refreshTypesHandler;
|
||
|
private EventHandler refreshDesignerActionsHandler;
|
||
|
private EventHandler refreshTasksHandler;
|
||
|
|
||
|
public WorkflowDesignerEventsCoordinator(IDesignerLoaderHost serviceProvider)
|
||
|
{
|
||
|
this.serviceProvider = serviceProvider;
|
||
|
|
||
|
this.serviceProvider.LoadComplete += new EventHandler(OnDesignerReloaded);
|
||
|
|
||
|
//Listen to the events so that we are sure that we appropriately refresh the designer actions and tasks when the types
|
||
|
//change
|
||
|
IDesignerEventService designerEventService = this.serviceProvider.GetService(typeof(IDesignerEventService)) as IDesignerEventService;
|
||
|
if (designerEventService != null)
|
||
|
designerEventService.ActiveDesignerChanged += new ActiveDesignerEventHandler(OnActiveDesignerChanged);
|
||
|
|
||
|
ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
|
||
|
if (typeProvider != null)
|
||
|
typeProvider.TypesChanged += new EventHandler(OnTypeSystemTypesChanged);
|
||
|
|
||
|
ISelectionService selectionService = this.serviceProvider.GetService(typeof(ISelectionService)) as ISelectionService;
|
||
|
if (selectionService != null)
|
||
|
selectionService.SelectionChanged += new EventHandler(OnSelectionChanged);
|
||
|
|
||
|
IComponentChangeService componentChangedService = this.serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
|
||
|
if (componentChangedService != null)
|
||
|
componentChangedService.ComponentChanged += new ComponentChangedEventHandler(OnComponentChanged);
|
||
|
|
||
|
IPropertyValueUIService propertyValueService = this.serviceProvider.GetService(typeof(IPropertyValueUIService)) as IPropertyValueUIService;
|
||
|
if (propertyValueService != null)
|
||
|
propertyValueService.AddPropertyValueUIHandler(new PropertyValueUIHandler(OnPropertyGridAdornments));
|
||
|
}
|
||
|
|
||
|
void IDisposable.Dispose()
|
||
|
{
|
||
|
WorkflowView workflowView = this.serviceProvider.GetService(typeof(WorkflowView)) as WorkflowView;
|
||
|
if (workflowView != null)
|
||
|
{
|
||
|
if (this.refreshTypesHandler != null)
|
||
|
workflowView.Idle -= this.refreshTypesHandler;
|
||
|
|
||
|
if (this.refreshDesignerActionsHandler != null)
|
||
|
workflowView.Idle -= this.refreshDesignerActionsHandler;
|
||
|
|
||
|
if (this.refreshTasksHandler != null)
|
||
|
workflowView.Idle -= this.refreshTasksHandler;
|
||
|
}
|
||
|
|
||
|
this.refreshTypesHandler = null;
|
||
|
this.refreshDesignerActionsHandler = null;
|
||
|
this.refreshTasksHandler = null;
|
||
|
|
||
|
IExtendedUIService extUIService = this.serviceProvider.GetService(typeof(IExtendedUIService)) as IExtendedUIService;
|
||
|
if (extUIService != null)
|
||
|
extUIService.RemoveDesignerActions();
|
||
|
|
||
|
IPropertyValueUIService propertyValueService = this.serviceProvider.GetService(typeof(IPropertyValueUIService)) as IPropertyValueUIService;
|
||
|
if (propertyValueService != null)
|
||
|
propertyValueService.RemovePropertyValueUIHandler(new PropertyValueUIHandler(OnPropertyGridAdornments));
|
||
|
|
||
|
IComponentChangeService componentChangedService = this.serviceProvider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
|
||
|
if (componentChangedService != null)
|
||
|
componentChangedService.ComponentChanged -= new ComponentChangedEventHandler(OnComponentChanged);
|
||
|
|
||
|
ISelectionService selectionService = this.serviceProvider.GetService(typeof(ISelectionService)) as ISelectionService;
|
||
|
if (selectionService != null)
|
||
|
selectionService.SelectionChanged -= new EventHandler(OnSelectionChanged);
|
||
|
|
||
|
ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
|
||
|
if (typeProvider != null)
|
||
|
typeProvider.TypesChanged -= new EventHandler(OnTypeSystemTypesChanged);
|
||
|
|
||
|
IDesignerEventService designerEventService = this.serviceProvider.GetService(typeof(IDesignerEventService)) as IDesignerEventService;
|
||
|
if (designerEventService != null)
|
||
|
designerEventService.ActiveDesignerChanged -= new ActiveDesignerEventHandler(OnActiveDesignerChanged);
|
||
|
|
||
|
this.serviceProvider.LoadComplete -= new EventHandler(OnDesignerReloaded);
|
||
|
}
|
||
|
|
||
|
private void OnDesignerReloaded(object sender, EventArgs e)
|
||
|
{
|
||
|
bool refreshTypes = (this.refreshTypesHandler != null);
|
||
|
bool refreshDesignerActions = (this.refreshDesignerActionsHandler != null);
|
||
|
bool refreshTasks = (this.refreshTasksHandler != null);
|
||
|
|
||
|
this.refreshTypesHandler = null;
|
||
|
this.refreshDesignerActionsHandler = null;
|
||
|
this.refreshTasksHandler = null;
|
||
|
|
||
|
if (refreshTypes || refreshTasks || refreshDesignerActions)
|
||
|
{
|
||
|
RefreshTypes();
|
||
|
RefreshDesignerActions();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void OnTypeSystemTypesChanged(object sender, EventArgs e)
|
||
|
{
|
||
|
this.typeSystemTypesChanged = true;
|
||
|
|
||
|
//If the current designer is not active designer then we need to wait for it to be active before we update the types
|
||
|
IDesignerEventService designerEventService = this.serviceProvider.GetService(typeof(IDesignerEventService)) as IDesignerEventService;
|
||
|
if (designerEventService != null && designerEventService.ActiveDesigner == this.serviceProvider.GetService(typeof(IDesignerHost)))
|
||
|
RefreshTypes();
|
||
|
}
|
||
|
|
||
|
private void OnActiveDesignerChanged(object sender, ActiveDesignerEventArgs e)
|
||
|
{
|
||
|
if (e.NewDesigner == this.serviceProvider.GetService(typeof(IDesignerHost)) && this.typeSystemTypesChanged)
|
||
|
RefreshTypes();
|
||
|
else
|
||
|
RefreshTasks();
|
||
|
}
|
||
|
|
||
|
private void OnComponentChanged(object sender, ComponentChangedEventArgs eventArgs)
|
||
|
{
|
||
|
RefreshDesignerActions();
|
||
|
}
|
||
|
|
||
|
private void RefreshTypes()
|
||
|
{
|
||
|
if (this.refreshTypesHandler == null && this.typeSystemTypesChanged)
|
||
|
{
|
||
|
WorkflowView workflowView = this.serviceProvider.GetService(typeof(WorkflowView)) as WorkflowView;
|
||
|
if (workflowView != null)
|
||
|
{
|
||
|
this.refreshTypesHandler = new EventHandler(OnRefreshTypes);
|
||
|
workflowView.Idle += this.refreshTypesHandler;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.typeSystemTypesChanged = false;
|
||
|
}
|
||
|
|
||
|
private void OnRefreshTypes(object sender, EventArgs e)
|
||
|
{
|
||
|
if (this.refreshTypesHandler != null)
|
||
|
{
|
||
|
WorkflowView workflowView = this.serviceProvider.GetService(typeof(WorkflowView)) as WorkflowView;
|
||
|
if (workflowView != null)
|
||
|
workflowView.Idle -= this.refreshTypesHandler;
|
||
|
this.refreshTypesHandler = null;
|
||
|
}
|
||
|
|
||
|
IDesignerHost designerHost = this.serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
|
||
|
Activity rootActivity = (designerHost != null) ? designerHost.RootComponent as Activity : null;
|
||
|
if (rootActivity == null)
|
||
|
return;
|
||
|
|
||
|
//Now Refresh the types as well as the designer actions
|
||
|
ITypeProvider typeProvider = this.serviceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider;
|
||
|
if (typeProvider != null)
|
||
|
{
|
||
|
Walker walker = new Walker();
|
||
|
walker.FoundProperty += delegate(Walker w, WalkerEventArgs args)
|
||
|
{
|
||
|
if (args.CurrentValue != null &&
|
||
|
args.CurrentProperty != null &&
|
||
|
args.CurrentProperty.PropertyType == typeof(System.Type) &&
|
||
|
args.CurrentValue is System.Type)
|
||
|
{
|
||
|
Type updatedType = typeProvider.GetType(((Type)args.CurrentValue).FullName);
|
||
|
if (updatedType != null)
|
||
|
{
|
||
|
args.CurrentProperty.SetValue(args.CurrentPropertyOwner, updatedType, null);
|
||
|
|
||
|
if (args.CurrentActivity != null)
|
||
|
TypeDescriptor.Refresh(args.CurrentActivity);
|
||
|
}
|
||
|
}
|
||
|
else if (args.CurrentProperty == null && args.CurrentValue is DependencyObject && !(args.CurrentValue is Activity))
|
||
|
{
|
||
|
walker.WalkProperties(args.CurrentActivity, args.CurrentValue);
|
||
|
}
|
||
|
};
|
||
|
walker.FoundActivity += delegate(Walker w, WalkerEventArgs args)
|
||
|
{
|
||
|
if (args.CurrentActivity != null)
|
||
|
{
|
||
|
TypeDescriptor.Refresh(args.CurrentActivity);
|
||
|
|
||
|
ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(args.CurrentActivity);
|
||
|
if (activityDesigner != null)
|
||
|
activityDesigner.RefreshDesignerActions();
|
||
|
|
||
|
InvokeWorkflowDesigner invokeWorkflowDesigner = activityDesigner as InvokeWorkflowDesigner;
|
||
|
if (invokeWorkflowDesigner != null)
|
||
|
invokeWorkflowDesigner.RefreshTargetWorkflowType();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
walker.Walk(rootActivity);
|
||
|
}
|
||
|
|
||
|
IPropertyValueUIService propertyValueService = this.serviceProvider.GetService(typeof(IPropertyValueUIService)) as IPropertyValueUIService;
|
||
|
if (propertyValueService != null)
|
||
|
propertyValueService.NotifyPropertyValueUIItemsChanged();
|
||
|
|
||
|
RefreshTasks();
|
||
|
RefreshDesignerActions();
|
||
|
}
|
||
|
|
||
|
private void RefreshDesignerActions()
|
||
|
{
|
||
|
if (this.refreshDesignerActionsHandler == null)
|
||
|
{
|
||
|
WorkflowView workflowView = this.serviceProvider.GetService(typeof(WorkflowView)) as WorkflowView;
|
||
|
if (workflowView != null)
|
||
|
{
|
||
|
this.refreshDesignerActionsHandler = new EventHandler(OnRefreshDesignerActions);
|
||
|
workflowView.Idle += this.refreshDesignerActionsHandler;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void OnRefreshDesignerActions(object sender, EventArgs e)
|
||
|
{
|
||
|
//NOTE: Make sure that we dont invalidate the workflow here. Workflow will be invalidated when'
|
||
|
//the designer actions are refreshed on idle thread. Putting invalidation logic here causes the validation
|
||
|
//to go haywire as before the idle message comes in we start getting to DesignerActions thru the paiting
|
||
|
//logic to show smart tags. This causes problems and ConfigErrors appear everywhere on designer intermittently
|
||
|
|
||
|
//PROBLEM: ConfigErrors appearing on the entire design surface
|
||
|
//This is due to a race condition between the validation triggered during painting
|
||
|
//logic and validation triggered when we try to access the DesignerActions from RefreshTask handler
|
||
|
//In the validation logic we try to get to the types while doing so we Refresh the code compile unit
|
||
|
//in typesystem which in turn triggers CodeDomLoader.Refresh. In this we remove types, call refresh handler
|
||
|
//and add new types. While doing this after the remove types but before addtypes, call is made to the drawing
|
||
|
//logic in which we try to grab the designer actions which triggers another set of validations hence now we
|
||
|
//always call UpdateWindow after invalidatewindow so that the validation will always get triggered on painting thread.
|
||
|
//NOTE: PLEASE DO NOT CHANGE SEQUENCE IN WHICH THE FOLLOWING HANDLERS ARE ADDED
|
||
|
//THE PROBLEM CAN BE ALSO FIXED BY TRIGGERING VALIDATION IN RefreshDesignerActions ITSELF
|
||
|
//FOR NOW THE REFRESH FIX WILL CAUSE MINIMAL IMPACT IN THE LIGHT OF M3
|
||
|
|
||
|
WorkflowView workflowView = this.serviceProvider.GetService(typeof(WorkflowView)) as WorkflowView;
|
||
|
if (this.refreshDesignerActionsHandler != null)
|
||
|
{
|
||
|
if (workflowView != null)
|
||
|
workflowView.Idle -= this.refreshDesignerActionsHandler;
|
||
|
this.refreshDesignerActionsHandler = null;
|
||
|
}
|
||
|
|
||
|
DesignerHelpers.RefreshDesignerActions(this.serviceProvider);
|
||
|
|
||
|
IPropertyValueUIService propertyValueService = this.serviceProvider.GetService(typeof(IPropertyValueUIService)) as IPropertyValueUIService;
|
||
|
if (propertyValueService != null)
|
||
|
propertyValueService.NotifyPropertyValueUIItemsChanged();
|
||
|
|
||
|
RefreshTasks();
|
||
|
}
|
||
|
|
||
|
private void OnSelectionChanged(object sender, EventArgs e)
|
||
|
{
|
||
|
WorkflowView workflowView = this.serviceProvider.GetService(typeof(WorkflowView)) as WorkflowView;
|
||
|
if (workflowView != null)
|
||
|
workflowView.Invalidate();
|
||
|
|
||
|
RefreshTasks();
|
||
|
}
|
||
|
|
||
|
private void RefreshTasks()
|
||
|
{
|
||
|
if (this.refreshTasksHandler == null)
|
||
|
{
|
||
|
//Listen to the next idle event to populate the tasks; this should happen on selection changed as well as active designer changed if the current designer is active
|
||
|
WorkflowView workflowView = this.serviceProvider.GetService(typeof(WorkflowView)) as WorkflowView;
|
||
|
if (workflowView != null)
|
||
|
{
|
||
|
this.refreshTasksHandler = new EventHandler(OnRefreshTasks);
|
||
|
workflowView.Idle += this.refreshTasksHandler;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void OnRefreshTasks(object sender, EventArgs e)
|
||
|
{
|
||
|
WorkflowView workflowView = this.serviceProvider.GetService(typeof(WorkflowView)) as WorkflowView;
|
||
|
if (this.refreshTasksHandler != null)
|
||
|
{
|
||
|
if (workflowView != null)
|
||
|
workflowView.Idle -= this.refreshTasksHandler;
|
||
|
this.refreshTasksHandler = null;
|
||
|
}
|
||
|
|
||
|
ISelectionService selectionService = this.serviceProvider.GetService(typeof(ISelectionService)) as ISelectionService;
|
||
|
IExtendedUIService extendedUIService = this.serviceProvider.GetService(typeof(IExtendedUIService)) as IExtendedUIService;
|
||
|
if (selectionService != null && extendedUIService != null)
|
||
|
{
|
||
|
extendedUIService.RemoveDesignerActions();
|
||
|
|
||
|
//Only if the current designer is active designer we add the designer actions to the task list
|
||
|
IDesignerEventService designerEventService = (IDesignerEventService)this.serviceProvider.GetService(typeof(IDesignerEventService));
|
||
|
if (designerEventService != null && designerEventService.ActiveDesigner == this.serviceProvider.GetService(typeof(IDesignerHost)))
|
||
|
{
|
||
|
foreach (object obj in selectionService.GetSelectedComponents())
|
||
|
{
|
||
|
ActivityDesigner activityDesigner = null;
|
||
|
if (obj is HitTestInfo)
|
||
|
activityDesigner = ((HitTestInfo)obj).AssociatedDesigner;
|
||
|
else if (obj is Activity)
|
||
|
activityDesigner = ActivityDesigner.GetDesigner(obj as Activity);
|
||
|
|
||
|
if (activityDesigner != null)
|
||
|
extendedUIService.AddDesignerActions(new List<DesignerAction>(activityDesigner.DesignerActions).ToArray());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (workflowView != null)
|
||
|
workflowView.Invalidate();
|
||
|
}
|
||
|
|
||
|
private void OnPropertyGridAdornments(ITypeDescriptorContext context, PropertyDescriptor propDesc, ArrayList valueUIItemList)
|
||
|
{
|
||
|
IComponent component = null;
|
||
|
IReferenceService referenceService = this.serviceProvider.GetService(typeof(IReferenceService)) as IReferenceService;
|
||
|
if (referenceService != null)
|
||
|
component = referenceService.GetComponent(context.Instance);
|
||
|
|
||
|
string fullAliasName = string.Empty;
|
||
|
//this attribue is set to overcome issue with the TypedVariableDeclarationTypeConverter
|
||
|
//not returning Name property at all. we alias that property to the VariableDeclaration itself
|
||
|
DefaultPropertyAttribute aliasPropertyNameAttribute = propDesc.Attributes[typeof(DefaultPropertyAttribute)] as DefaultPropertyAttribute;
|
||
|
if (aliasPropertyNameAttribute != null && aliasPropertyNameAttribute.Name != null && aliasPropertyNameAttribute.Name.Length > 0)
|
||
|
fullAliasName = propDesc.Name + "." + aliasPropertyNameAttribute.Name;
|
||
|
|
||
|
if (component != null)
|
||
|
{
|
||
|
ActivityDesigner activityDesigner = ActivityDesigner.GetDesigner(component as Activity);
|
||
|
if (activityDesigner != null)
|
||
|
{
|
||
|
if (!activityDesigner.IsLocked && ActivityBindPropertyDescriptor.IsBindableProperty(propDesc) && !propDesc.IsReadOnly)
|
||
|
valueUIItemList.Add(new PropertyValueUIItem(DR.GetImage(DR.Bind), OnBindProperty, DR.GetString(DR.BindProperty)));
|
||
|
|
||
|
string fullComponentName = referenceService.GetName(component); //schedule1.send1
|
||
|
string fullPropertyName = referenceService.GetName(context.Instance); //schedule1.send1.message
|
||
|
fullPropertyName = (fullPropertyName.Length > fullComponentName.Length) ? fullPropertyName.Substring(fullComponentName.Length + 1, fullPropertyName.Length - fullComponentName.Length - 1) + "." + propDesc.Name : string.Empty;
|
||
|
|
||
|
foreach (DesignerAction action in activityDesigner.DesignerActions)
|
||
|
{
|
||
|
string actionPropertyName = action.PropertyName as string;
|
||
|
if (actionPropertyName == null || actionPropertyName.Length == 0)
|
||
|
continue;
|
||
|
|
||
|
if (actionPropertyName == propDesc.Name || (actionPropertyName == fullPropertyName) || (actionPropertyName == fullAliasName))
|
||
|
{
|
||
|
PropertyValueUIItemHandler propValueUIItemhandler = new PropertyValueUIItemHandler(action);
|
||
|
valueUIItemList.Add(new PropertyValueUIItem(action.Image, propValueUIItemhandler.OnFixPropertyError, action.Text));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void OnBindProperty(ITypeDescriptorContext context, PropertyDescriptor descriptor, PropertyValueUIItem invokedItem)
|
||
|
{
|
||
|
BindUITypeEditor.EditValue(context);
|
||
|
}
|
||
|
|
||
|
#region Class PropertyValueUIItemHandler
|
||
|
private class PropertyValueUIItemHandler
|
||
|
{
|
||
|
DesignerAction action = null;
|
||
|
internal PropertyValueUIItemHandler(DesignerAction action)
|
||
|
{
|
||
|
this.action = action;
|
||
|
}
|
||
|
internal void OnFixPropertyError(ITypeDescriptorContext context, PropertyDescriptor descriptor, PropertyValueUIItem invokedItem)
|
||
|
{
|
||
|
action.Invoke();
|
||
|
}
|
||
|
}
|
||
|
#endregion
|
||
|
}
|
||
|
#endregion
|
||
|
}
|