One of the goals of my blog is to experiment with integrating .NET into Office. Lately, the emphasis has been to show Silverlight in Access. Another area of interest is evaluating how Windows Workflow 4.0 could be used in Access to create workflow solutions as well as enable a declarative development environment. This blog, and accompanying CodePlex code download, refines the Silverlight and web browser control concept and introduces a simple Windows Workflow 4.0 containing two custom activities.
The Silverlight and web browser control concept is refined by showing how to create a simple Access HTML editor containing an embedded Silverlight Treeview control. An HTML Editor can be created primarily by using a contentEditable attribute and calling an HtmlDocument execCommand() method or using mshtml.IHTMLTxtRange methods to style a span element. An embedded Silverlight Treeview control can be displayed by creating an HtmlDocumentEvent.onclick delegate and setting the Dashboard.TreeviewPage.Display style to none or block. Here is an overview of how this works. You can go to http://desktopweb.codeplex.com/SourceControl/list/changesets for a complete sample.
HTML Editor with Embedded Silverlight
HTML formatting
Commands
Dashboard.HtmlDocument.execCommand("Bold");
Dashboard.HtmlDocument.execCommand("Italic");
Style a span element
mshtml.IHTMLTxtRange rng =
(mshtml.IHTMLTxtRange)Dashboard.HtmlDocument.selection.createRange();
…
rng.pasteHTML("<span style='color:" + Dashboard.ColorCombo.Text + ";'>" + text + "</span>");
//Reselect text
rng.moveStart("character", -text.Length);
rng.select();
…
TreeviewPage
Create event delegates after HTML document is complete
void MyDocumentTasks_onDocumentComplete(object sender, EventArgs e)
{
Dashboard.HtmlDocumentEvent.onclick += new mshtml.HTMLDocumentEvents2_onclickEventHandler(HtmlDocumentEvent_onclick);
…
//Initially hide the Treeview
Dashboard.TreeviewPage.Display = "none";
}
Toggle TreeviewPage display
bool HtmlDocumentEvent_onclick(mshtml.IHTMLEventObj pEvtObj)
{
if ("popup" == pEvtObj.srcElement.id.ToString())
{
if(Dashboard.TreeviewPage.Display == "none")
Dashboard.TreeviewPage.Display = "block";
else
Dashboard.TreeviewPage.Display = "none";
}
return true;
}
Invoke Windows Workflow 4.0 in Access
Adding Windows Workflow 4.0 (WF4) enables workflow and declarative development into Access. To experiment with WF4 in Access, a simple project budget workflow was created containing an If activity and two custom activates; ValidValueActivity and EmailActivity. An If activity executes ValidValueActivity if the budget threshold is less than 1000; otherwise, EmailActivity is executed. To show how a custom activity could be designed for Access, each activity sets the Cost Textbox BorderColor. In addition, the ValidValueActivity adds an item to the Silverlight TreeviewPage control.
Note
An assembly reference must be added to a workflow xaml file; otherwise, a cannot create unknown type XamlObjectWriterException is thrown. You will need to append assembly=MyDataAddin to the xmlns:local Activity attribute.
Default Activity Element
<Activity xmlns:local="clr-namespace:MyDataAddin" …
Change to
<Activity xmlns:local="clr-namespace:MyDataAddin;assembly=MyDataAddin" …
Example Workflow
Dashboard_onAfterUpdate
The onAfterUpdate event delegate Invokes the example XAML workflow.
void Dashboard_onAfterUpdate(object sender, EventArgs e)
{
int value;
Int32.TryParse(Dashboard.TreeviewCheckbox.Value.ToString(), out value);
String fullFilePath =
@"C:\Projects\desktopWeb\MyDataAddin\WorkflowLibrary\ExampleWorkflow.xaml";
Activity wf = (Activity)ActivityXamlServices.Load(fullFilePath);
IDictionary<String, Object> output = WorkflowInvoker.Invoke(
wf, new Dictionary<String, Object>
{
{"ArgBudget", Convert.ToInt32(Dashboard.Cost.Value)},
});
MessageBox.Show(output["ResultString"].ToString(), "Windows Workflow");
}
Code Activities
public sealed class EmailActivity : CodeActivity, ISimpleActivity
{
public OutArgument<Int32> ResultCode { get; set; }
public OutArgument<String> ResultString { get; set; }
protected override void Execute(CodeActivityContext context)
{
//This example returns -1 for failure
//A production application would send email to the manager
ResultCode.Set(context, -1);
ResultString.Set(context, "Email sent to your manager");
Dashboard.Cost.BorderColor = VB.Information.RGB(255, 0, 0);
}
}
public sealed class ValidValueActivity : CodeActivity, ISimpleActivity
{
public OutArgument<Int32> ResultCode { get; set; }
public OutArgument<String> ResultString { get; set; }
protected override void Execute(CodeActivityContext context)
{
//This example returns 1 for success
ResultCode.Set(context, 1);
ResultString.Set(context, "Valid value");
Dashboard.Cost.BorderColor = VB.Information.RGB(0, 0, 255);
Dashboard.TreeviewPage.AddRootItem(Dashboard.Title.Value.ToString());
}
}