В данном примере, для наглядности, давайте создадим приложение с GUI:
Кнопки соответствуют событиям, прямоугольники показывают состояние двери и замка (красный - закрыто, зеленый открыто).
Для взаимодействия с программным окружением используются следующие Activity:
1. СallExternalMethodActivity – используется для вызова метода внешнего по отношению к WF (основные свойства InterfaceType и MethodName)
2. EventDrivenActivity – используется для перехвата событий из кода внешнего по отношению к WF
3. HandleExternalEventActivity – помещается в EventDrivenActivity и ожидает события (основные свойства InterfaceType и EventName)
К событиям передаваемым из внешнего окружения в WF предъявляются следующие требования:
1. Событие должно быть потомок EventHandler
2. В качестве T должен быть любой класс потомок ExternalDataEventArgs
Кстати, конструктор ExternalDataEventArgs принимает Guid потока которому предназначается сообщение.
Для взаимодействия с WF объекты должны являться, во-первых, наследниками интерфейса помеченного атрибутом [ExternalDataExchange].
Введем два интерфейса:
[ExternalDataExchange]
public interface IDoor
{
void OpenLock();
void OpenDoor();
void CloseDoor();
string GetKey();
}
[ExternalDataExchange]
public interface IVisitor
{
event EventHandler<ExternalDataEventArgs> TestKey;
event EventHandler<ExternalDataEventArgs> Open;
event EventHandler<ExternalDataEventArgs> Close;
}
* This source code was highlighted with Source Code Highlighter.
Во-вторых, если ссылка на вызывающий событие объект будет передаваться в WF объект должен быть сериализуемым.
Кстати, если методо вызываемый из WF возвращает значение, то его можно непосредственно в дизайнере привязать к полю WF, использовав для этгого свойство ReturnValue:
Добавив везде где это надо вместо CodeActivity вызов внешних методов и перехват внешних событий, получим конечный автомат вида:
Реализация интерфейса IDoor может иметь вид:
#region IDoor Members
public void OpenLock()
{
if (Dispatcher.Thread != Thread.CurrentThread)
{
Dispatcher.Invoke(new NoParamHandler(OpenLock), new object[] { });
}
else
{
rcDoorlock.Fill = new SolidColorBrush(Color.FromRgb(0, 255, 0));
}
}
public void OpenDoor()
{
if (Dispatcher.Thread != Thread.CurrentThread)
{
Dispatcher.Invoke(new NoParamHandler(OpenDoor), new object[] { });
}
else
{
rcDoor.Fill = new SolidColorBrush(Color.FromRgb(0, 255, 0));
}
}
private delegate void NoParamHandler();
public void CloseDoor()
{
if (Dispatcher.Thread != Thread.CurrentThread)
{
Dispatcher.Invoke(new NoParamHandler(CloseDoor), new object[] { });
}
else
{
rcDoorlock.Fill = new SolidColorBrush(Color.FromRgb(255, 0, 0));
rcDoor.Fill = new SolidColorBrush(Color.FromRgb(255, 0, 0));
}
}
public string GetKey()
{
if (Dispatcher.Thread == Thread.CurrentThread)
{
return tbKey.Text;
}
else
{
return (string)Dispatcher.Invoke(new Func<string>(GetKey), new object[] { });
}
}
#endregion
* This source code was highlighted with Source Code Highlighter.
Ну и в завершении как же создать host для WF. На самом деле все достаточно просто:
- WorkflowRuntime workflowRuntime;
- WorkflowInstance instance;
- StateMachineWorkflowInstance machine;
-
- private void Window_Loaded(object sender, RoutedEventArgs e)
- {
- workflowRuntime = new WorkflowRuntime();
- workflowRuntime.WorkflowStarted += delegate(object s, WorkflowEventArgs e1) { MessageBox.Show("Рабочий поток начал работу"); };
- workflowRuntime.WorkflowCompleted += delegate(object s, WorkflowCompletedEventArgs e1) { MessageBox.Show("Рабочий поток закончил работу"); };
- workflowRuntime.WorkflowTerminated += delegate(object s, WorkflowTerminatedEventArgs e1)
- {
- MessageBox.Show(e1.Exception.Message);
- };
- ExternalDataExchangeService externalDataExchangeService = new ExternalDataExchangeService();
- workflowRuntime.AddService(externalDataExchangeService);
- externalDataExchangeService.AddService(this);
-
- instance = workflowRuntime.CreateWorkflow(typeof(Workflow1));
- machine = new StateMachineWorkflowInstance(workflowRuntime, instance.InstanceId);
- instance.Start();
-
- }
* This source code was highlighted with Source Code Highlighter.
В строках 7-13 мы создаем среду выполнения WF и подписываемся на основные ее обработчики.
В строках 14-16 создаем сервис для взаимодействия с WF, регистрируем его в среде выполнения, и добавляем объект методы которого необходимо вызывать и события обрабатывать (в данном случае это текущая форма).
В строках 18,20 создается WF и запускается на выполнение.
В строке 19 получаем ссылку на WF в виде StateMachine которую можно использовать для проверки текущего состояния конечного автоамта, принудительного перевода из состояния в состояние и т.д.
Комментариев нет:
Отправить комментарий