//*****************************************************************************
// Description.....WF4.5 Message Mediation Library
//
// Author..........Roman Kiss, rkiss@pathcom.com
// Copyright © 2009 ATZ Consulting Inc. (see included license.rtf file)
//
// Date Created: 07/07/09
//
// Date Modified By Description
//-----------------------------------------------------------------------------
// 07/07/09 Roman Kiss Initial Revision
// 10/10/12 Roman Kiss Upadate 4.5
//*****************************************************************************
//
#region Namespaces
using System;
using System.Activities.Presentation;
using System.Activities.Presentation.Hosting;
using System.Activities.Presentation.Toolbox;
using System.Activities.Statements;
using System.Activities.Validation;
using System.Activities.XamlIntegration;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.ServiceModel.Activities;
using System.ServiceModel.Activities.Presentation.Factories;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Xaml;
using System.Xml;
#endregion
namespace ManageableServicesConsole.UserControls
{
public partial class WorkflowDesignerUserControl : System.Windows.Forms.UserControl
{
WorkflowDesigner wd;
bool isdirty = false;
#region Constructor
public WorkflowDesignerUserControl()
{
InitializeComponent();
this.pictureBoxWarning.Visible = false;
DesignerReadOnly = false;
RegisterMetadata();
AddDesigner(null);
this.splitContainer2.SplitterDistance = this.splitContainer2.ClientSize.Height -15;
AddToolBox();
AddPropertyInspector();
}
#endregion
#region Get/Set
public bool IsDirty
{
get { return isdirty; }
set
{
isdirty = value;
this.pictureBoxWarning.Visible = value;
}
}
public TemplateFactoryItem FactoryItem { get; set; }
public bool DesignerReadOnly { get; set; }
public string GetCurrentXmlDocument
{
get { return this.xmlNotepadPanelControl1.XmlNotepadForm.GetCurrentXmlDocument.Replace("dw1DOlxFbXB0eS54YW1sAA==", ""); }
}
public string Xaml
{
get
{
this.xmlNotepadPanelControl1.XmlNotepadForm.LoadXmlDocument(this.wd.Text.Replace("dw1DOlxFbXB0eS54YW1sAA==", ""));
this.buttonRefresh.Enabled = false;
return this.xmlNotepadPanelControl1.XmlNotepadForm.GetCurrentXmlDocument;
}
set
{
this.xmlNotepadPanelControl1.XmlNotepadForm.LoadXmlDocument(value.Replace("dw1DOlxFbXB0eS54YW1sAA==", ""));
this.LoadXaml(value.Replace("dw1DOlxFbXB0eS54YW1sAA==", ""));
}
}
public List<string> ReferencedAssemblies { get; set; }
#endregion
#region Add/Remove ToolboxItem
public void AddToolboxItem(string toolName, string assemblyName)
{
this.AddToolboxItem("Custom", toolName, assemblyName, null, null);
}
public void AddToolboxItem(string categoryName, string toolName, string assemblyName)
{
this.AddToolboxItem(categoryName, toolName, assemblyName, null, null);
}
public void AddToolboxItem(string categoryName, string toolName, string assemblyName, string bitmapName, string displayName)
{
ToolboxItemWrapper item = new ToolboxItemWrapper(toolName, assemblyName, bitmapName, displayName);
ToolboxControl tc = this.elementHost2.Child as ToolboxControl;
var category = tc.Categories.FirstOrDefault(e => e.CategoryName == categoryName);
if (category == null)
tc.Categories.Add(new ToolboxCategory(categoryName) { item });
else
category.Add(item);
}
public void RemoveToolboxItem(string categoryName, string displayName)
{
ToolboxControl tc = this.elementHost2.Child as ToolboxControl;
var category = tc.Categories.FirstOrDefault(e => e.CategoryName == categoryName);
if (category != null)
{
var item = category.OfType<ToolboxItemWrapper>().FirstOrDefault(e => e.DisplayName == displayName);
if (item != null)
category.Remove(item);
}
}
#endregion
#region Grid Elements
private void RegisterMetadata()
{
System.Activities.Core.Presentation.DesignerMetadata designers = new System.Activities.Core.Presentation.DesignerMetadata();
designers.Register();
}
private void AddToolBox()
{
ToolboxControl tc = GetToolboxControl();
Grid.SetColumn(tc, 0);
this.elementHost2.Child = tc;
}
private void AddPropertyInspector()
{
Grid.SetColumn(wd.PropertyInspectorView, 2);
this.elementHost3.Child = wd.PropertyInspectorView;
}
private void AddDesigner()
{
this.wd = new WorkflowDesigner();
UIElement element = this.wd.View;
element.IsEnabled = true;
element.IsHitTestVisible = true;
this.elementHost1.Child = element;
//4.5
this.elementHostOutlineView.Child = this.wd.OutlineView;
}
private void AddDesigner(string xaml)
{
this.wd = new WorkflowDesigner();
this.wd.Context.Items.GetValue<ReadOnlyState>().IsReadOnly = this.DesignerReadOnly;
// 4.5
this.wd.Context.Services.GetService<DesignerConfigurationService>().TargetFrameworkName = new System.Runtime.Versioning.FrameworkName(".NETFramework", new Version(4, 5));
this.wd.Context.Services.GetService<DesignerConfigurationService>().AnnotationEnabled = true;
this.wd.Context.Services.GetService<DesignerConfigurationService>().AutoSurroundWithSequenceEnabled = true;
if (this.FactoryItem != null)
{
this.wd.Context.Items.SetValue(this.FactoryItem);
}
this.wd.ModelChanged += delegate(object source, EventArgs args)
{
Trace.WriteLine("=> WorfklowDesigner model has been changed");
this.wd.Flush();
this.buttonRefresh.Enabled = !string.IsNullOrEmpty(this.wd.Text);
this.IsDirty = true;
//this.xmlNotepadPanelControl1.XmlNotepadForm.LoadXmlDocument(this.wd.Text);
};
if (string.IsNullOrEmpty(xaml))
{
this.xmlNotepadPanelControl1.XmlNotepadForm.LoadXmlDocument(this.DefaultXamlActivity);
}
this.wd.Text = this.GetCurrentXmlDocument;
this.wd.Load();
Grid.SetColumn(this.wd.View, 1);
UIElement element = this.wd.View;
element.IsEnabled = true;
element.IsHitTestVisible = true;
this.elementHost1.Child = element;
this.IsDirty = false;
// 4.5
UIElement elementOV = this.wd.OutlineView;
elementOV.IsEnabled = true;
elementOV.IsHitTestVisible = true;
this.elementHostOutlineView.Child = elementOV;
}
#endregion
#region Events
private void splitContainer2_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
this.splitContainer2.SplitterDistance = this.splitContainer2.ClientSize.Height - 30;
}
#endregion
#region Clicks
private void buttonRefresh_Click(object sender, EventArgs e)
{
this.buttonRefresh.Enabled = false;
if (string.IsNullOrEmpty(this.wd.Text) == false)
{
this.xmlNotepadPanelControl1.XmlNotepadForm.LoadXmlDocument(this.wd.Text);
}
}
private void buttonLoad_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Are you shure to reloaded workflow?", "Load xaml to designer", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning) == MessageBoxResult.Yes)
{
this.LoadXaml(this.GetCurrentXmlDocument);
}
}
private void buttonRun_Click(object sender, EventArgs e)
{
this.worker(this.Xaml);
}
#endregion
#region Tester
private void worker(string xaml)
{
ThreadPool.QueueUserWorkItem(delegate
{
string filename = Guid.NewGuid().ToString();
byte[] buffer = Encoding.UTF8.GetBytes(xaml);
using(var file = MemoryMappedFile.CreateNew(filename, 1000000))
using (var writer = file.CreateViewAccessor())
{
writer.WriteArray<byte>(0, buffer, 0, buffer.Length);
ProcessStartInfo psi = new ProcessStartInfo();
psi.Arguments = string.Format("{0} {1}", filename, buffer.Length);
psi.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
psi.FileName = typeof(WorkflowConsoleXamlTester.Program).Assembly.Location;
Process exeProcess = Process.Start(psi);
exeProcess.WaitForExit();
exeProcess.Close();
}
});
}
#endregion
#region Helpers
private void LoadXaml(string xaml)
{
Dictionary<string, string> namespaces = null;
try
{
if (this.wd != null && !string.IsNullOrEmpty(xaml))
{
// validate new xaml
namespaces = this.GetNamespaces(xaml);
if (IsWorkflowService(xaml))
{
// tbd
}
else
{
var a = ActivityXamlServices.Load(new StringReader(xaml));
ActivityValidationServices.Validate(a);
}
}
// show up
this.AddDesigner(xaml);
this.AddPropertyInspector();
this.buttonRefresh.Enabled = false;
}
catch (Exception ex)
{
StringBuilder sb = new StringBuilder(ex.Message);
// show assemblies:
if (namespaces != null)
{
sb.AppendFormat("\r\n\r\nAssemblies:\r\n");
foreach (KeyValuePair<string, string> item in namespaces)
{
if (item.Value.StartsWith("clr-namespace:") && item.Value.IndexOf("assembly=") > 1)
sb.AppendFormat(" {0}\r\n", item.Value);
}
}
System.Windows.Forms.MessageBox.Show(sb.ToString());
}
}
private ToolboxControl GetToolboxControl()
{
ToolboxControl ctrl = new ToolboxControl();
#region MS Built-in Activity
ToolboxCategory categoryFlowchart = new ToolboxCategory("Flowchart")
{
new ToolboxItemWrapper(typeof(Flowchart)),
new ToolboxItemWrapper(typeof(FlowSwitch<>)),
new ToolboxItemWrapper(typeof(FlowDecision))
};
ToolboxCategory categoryCollection = new ToolboxCategory("Collection")
{
new ToolboxItemWrapper(typeof(AddToCollection<>)),
new ToolboxItemWrapper(typeof(ClearCollection<>)),
new ToolboxItemWrapper(typeof(ExistsInCollection<>)),
new ToolboxItemWrapper(typeof(RemoveFromCollection<>)),
};
ToolboxCategory categoryPrimitives = new ToolboxCategory("Primitives")
{
new ToolboxItemWrapper(typeof(Assign)),
new ToolboxItemWrapper(typeof(Assign<>)),
new ToolboxItemWrapper(typeof(Delay)),
new ToolboxItemWrapper(typeof(InvokeMethod)),
new ToolboxItemWrapper(typeof(InvokeDelegate)),
new ToolboxItemWrapper(typeof(WriteLine)),
};
ToolboxCategory categoryControlFlow = new ToolboxCategory("ControlFlow")
{
new ToolboxItemWrapper(typeof(DoWhile)),
new ToolboxItemWrapper(typeof(System.Activities.Core.Presentation.Factories.ForEachWithBodyFactory<>)),
new ToolboxItemWrapper(typeof(If)),
new ToolboxItemWrapper(typeof(Parallel)),
new ToolboxItemWrapper(typeof(System.Activities.Core.Presentation.Factories.ParallelForEachWithBodyFactory<>)),
new ToolboxItemWrapper(typeof(Pick)),
new ToolboxItemWrapper(typeof(PickBranch)),
new ToolboxItemWrapper(typeof(System.Activities.Core.Presentation.Factories.PickWithTwoBranchesFactory)),
new ToolboxItemWrapper(typeof(Sequence)),
new ToolboxItemWrapper(typeof(Switch<>)),
new ToolboxItemWrapper(typeof(While)),
};
ToolboxCategory categoryMessaging = new ToolboxCategory("Messaging")
{
new ToolboxItemWrapper(typeof(CorrelationScope)),
new ToolboxItemWrapper(typeof(InitializeCorrelation)),
new ToolboxItemWrapper(typeof(Receive)),
new ToolboxItemWrapper(typeof(ReceiveAndSendReplyFactory)),
new ToolboxItemWrapper(typeof(Send)),
new ToolboxItemWrapper(typeof(SendAndReceiveReplyFactory)),
};
ToolboxCategory categoryRuntime = new ToolboxCategory("Runtime")
{
new ToolboxItemWrapper(typeof(Persist)),
new ToolboxItemWrapper(typeof(TerminateWorkflow)),
new ToolboxItemWrapper(typeof(NoPersistScope)),
};
ToolboxCategory categoryTransaction = new ToolboxCategory("Transaction")
{
new ToolboxItemWrapper(typeof(CancellationScope)),
new ToolboxItemWrapper(typeof(CompensableActivity)),
new ToolboxItemWrapper(typeof(Compensate)),
new ToolboxItemWrapper(typeof(Confirm)),
new ToolboxItemWrapper(typeof(TransactionScope)),
new ToolboxItemWrapper(typeof(TransactedReceiveScope)),
};
ToolboxCategory categoryErrorHandling = new ToolboxCategory("Error Handling")
{
new ToolboxItemWrapper(typeof(Rethrow)),
new ToolboxItemWrapper(typeof(Throw)),
new ToolboxItemWrapper(typeof(TryCatch)),
};
ToolboxCategory categoryStateMachine = new ToolboxCategory("State Machine")
{
new ToolboxItemWrapper(typeof(StateMachine)),
new ToolboxItemWrapper(typeof(System.Activities.Core.Presentation.Factories.StateMachineWithInitialStateFactory)),
new ToolboxItemWrapper(typeof(State)),
new ToolboxItemWrapper(typeof(System.Activities.Core.Presentation.FinalState)),
};
#endregion
ctrl.Categories.Add(categoryPrimitives);
ctrl.Categories.Add(categoryControlFlow);
ctrl.Categories.Add(categoryMessaging);
ctrl.Categories.Add(categoryErrorHandling);
ctrl.Categories.Add(categoryFlowchart);
ctrl.Categories.Add(categoryRuntime);
ctrl.Categories.Add(categoryTransaction);
ctrl.Categories.Add(categoryCollection);
ctrl.Categories.Add(categoryStateMachine);
return ctrl;
}
private Dictionary<string, string> GetNamespaces(string xaml)
{
Dictionary<string, string> namespaces = new Dictionary<string, string>();
using (XmlReader xrd = XmlReader.Create(new StringReader(xaml)))
{
XamlXmlReader xxrd = new XamlXmlReader(xrd);
while (xxrd.Read())
{
if (xxrd.Namespace == null) continue;
namespaces.Add(xxrd.Namespace.Prefix, xxrd.Namespace.Namespace);
}
}
return namespaces;
}
private string DefaultXamlActivity
{
get
{
return @"<Activity x:Class='EmptyActivity' mva:VisualBasic.Settings='Assembly references and imported namespaces serialized as XML namespaces' xmlns='http://schemas.microsoft.com/netfx/2009/xaml/activities' xmlns:mva='clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' />";
}
}
#endregion
private bool IsWorkflowService(string xaml)
{
StringReader input = new StringReader(xaml);
using (XmlReader xrd = XmlReader.Create(input))
{
while (xrd.Read())
{
if (xrd.LocalName == "WorkflowService" || xrd.LocalName == "Receive")
return true;
}
}
return false;
}
}
public class TemplateFactoryItem : ContextItem
{
// Properties-
public sealed override Type ItemType
{
get { return typeof(TemplateFactoryItem); }
}
public string ConnectionString { get; set; }
public Type Editor { get; set; }
}
}