Закладки

Закладки - это механизм, позволяющий действиям пассивно ожидать ввода, не останавливая поток рабочего процесса. Когда действие сообщает об ожидании внешнего воздействия, оно может создать закладку. Это сообщает среде выполнения, что выполнение действия не должно считаться завершенным даже в случае возвращения управления из выполняющегося в данный момент метода (создавшего закладку Bookmark).

Основные сведения о закладках

Закладка Bookmark представляет точку, с которой может быть продолжено выполнение (и через которую могут быть переданы входные данные) в экземпляре рабочего процесса. Обычно закладке Bookmark присваиваются имя и внешний код (ведущего приложения или расширения), используемый для продолжения работы с точки закладки с соответствующими данными. При возобновлении закладки Bookmark среда выполнения рабочего процесса планирует делегат BookmarkCallback, который был связан с этой закладкой Bookmark на момент ее создания.

Параметры закладки

В классе BookmarkOptions указывается тип создаваемой закладки Bookmark. Возможны следующие (не исключающие друг друга) значения: None, MultipleResume и NonBlocking. При создании закладки None, которая будет возобновлена ровно один раз, рекомендуется использовать вариант по умолчанию Bookmark. При создании закладки MultipleResume, которая может быть возобновлена несколько раз, следует использовать вариант Bookmark. При создании закладки NonBlocking, которая может быть не продолжена вообще, следует использовать параметр Bookmark. В отличие от закладок, созданных с использованием параметров BookmarkOptions по умолчанию, закладки типа NonBlocking не мешают завершению работы действия.

Возобновление закладок

Закладки могут возобновляться кодом извне рабочего процесса с использованием одного из перегруженных методов ResumeBookmark. В этом примере создается действие ReadLine. При выполнении действие ReadLine создает Bookmark, регистрирует обратный вызов и ждет возобновления чтения с закладки Bookmark. После возобновления чтения с закладки действие ReadLine присваивает данные, переданные с закладкой Bookmark, своему аргументу Result.

public sealed class ReadLine : NativeActivity<string>  
{  
    [RequiredArgument]  
    public  InArgument<string> BookmarkName { get; set; }  
  
    protected override void Execute(NativeActivityContext context)  
    {  
        // Create a Bookmark and wait for it to be resumed.  
        context.CreateBookmark(BookmarkName.Get(context),
            new BookmarkCallback(OnResumeBookmark));  
    }  
  
    // NativeActivity derived activities that do asynchronous operations by calling
    // one of the CreateBookmark overloads defined on System.Activities.NativeActivityContext
    // must override the CanInduceIdle property and return true.  
    protected override bool CanInduceIdle  
    {  
        get { return true; }  
    }  
  
    public void OnResumeBookmark(NativeActivityContext context, Bookmark bookmark, object obj)  
    {  
        // When the Bookmark is resumed, assign its value to  
        // the Result argument.  
        Result.Set(context, (string)obj);  
    }  
}  

В следующем примере создается рабочий процесс, использующий действие ReadLine для получения имени пользователя и его отображения в окне консоли. Ведущее приложение выполняет действительную работу по сбору входных данных и передает их в рабочий процесс, возобновляя закладку Bookmark.

Variable<string> name = new Variable<string>  
{  
    Name = "name"  
};  
  
Activity wf = new Sequence  
{  
    Variables =  
    {  
        name  
    },  
    Activities =  
    {  
        new WriteLine()  
        {  
            Text = "What is your name?"  
        },  
        new ReadLine()  
        {  
            BookmarkName = "UserName",  
            Result = name  
        },  
        new WriteLine()  
        {  
            Text = new InArgument<string>((env) => "Hello, " + name.Get(env))  
        }  
    }  
};  
  
AutoResetEvent syncEvent = new AutoResetEvent(false);  
  
// Create the WorkflowApplication using the desired  
// workflow definition.  
WorkflowApplication wfApp = new WorkflowApplication(wf);  
  
// Handle the desired lifecycle events.  
wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e)  
{  
    // Signal the host that the workflow is complete.  
    syncEvent.Set();  
};  
  
// Start the workflow.  
wfApp.Run();  
  
// Collect the user's name and resume the bookmark.  
// Bookmark resumption only occurs when the workflow  
// is idle. If a call to ResumeBookmark is made and the workflow  
// is not idle, ResumeBookmark blocks until the workflow becomes  
// idle before resuming the bookmark.  
wfApp.ResumeBookmark("UserName", Console.ReadLine());  
  
// Wait for Completed to arrive and signal that  
// the workflow is complete.  
syncEvent.WaitOne();  

При выполнении действие ReadLine создает закладку Bookmark с именем UserName и ждет возобновления чтения с этой закладки. Узел собирает необходимые данные и возобновляет чтение с закладки Bookmark. Рабочий процесс возобновляется, отображает имя и затем завершается. Следует заметить, что для возобновления закладки не требуется наличие кода синхронизации. Закладка Bookmark может быть возобновлена только при простое рабочего процесса; если рабочий процесс не простаивает, вызов ResumeBookmark блокируется, пока рабочий процесс не перейдет в состояние простоя.

Результат возобновления закладки

ResumeBookmark возвращает значение перечисления BookmarkResumptionResult, сообщая о результате выполнения запроса возобновления закладки. Возможны следующие возвращаемые значения: Success, NotReady и NotFound. Ведущие приложения и расширения могут использовать эти значения для определения дальнейших действий.