Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
делегату нужно подсунуть отдельно созданную активити, а жутко не хотелось процесс дробить на несколько файлов;Зачем? Не понимаю вас.
не уверен, работают ли закладки во вложенных процессах, вроде как запускает отдельный процесс.Аналогично: о каких вложенных процессах идет речь, если делегат выполняется в основном?
CREATE VIEW Tasks WITH SCHEMABINDING
AS
SELECT
b.Employee,
t.Card AS CardID,
t.InstanceID As WWFID,
i.Description as [Digest],
i.CardTypeID AS CardTypeID,
t.Status,
d.CreationDateTime,
COUNT_BIG(*) AS cBig
FROM dbo.[dvtable_{39857033-BDD0-4771-8654-482957FD1338}] as t
INNER JOIN dbo.[dvtable_{E6CEA68A-49EE-4E5C-8F54-E73EFB7EA78F}] as b on b.InstanceID = t.InstanceID
INNER JOIN dbo.dvsys_instances as i on i.InstanceID = t.Card
INNER JOIN dbo.dvsys_instances_date as d on d.instanceid = i.InstanceID
WHERE (i.Deleted IS NULL or i.Deleted = 0) and i.template = 0
GROUP BY
b.Employee,
t.Card,
t.InstanceID,
i.Description,
i.CardTypeID,
t.Status,
d.CreationDateTime
GO
CREATE UNIQUE CLUSTERED INDEX IDX_Tasks ON Tasks(Employee, CardID, WWFID);
Что бы сделать механизм получения списка доступных команд в WF 3.5(4) нужно потратить пару недель (при этом документооборот у вас будет задаваться в разных местах код — это прямой путь к ошибках).Я это сделал за день… что я сделал не так?)
public class ButtonActivity : NativeActivity {
[DisplayName("Код кнопки")]
public string Code {get; set;}
[DisplayName("Текст кнопки")]
public string Text {get; set;}
/* Один из недостатков стандартного дизайнера - невозможность понять, какой аргумент является входным, а какой выходным, без подглядывания в документацию. Поэтому я придумал вот так их маркировать */
[DisplayName("[IN] Актор")]
[RequiredArgument]
public InArgument<string> Actor {get; set;}
protected bool CanInduceIdle { get { return true; } }
protected override void CacheMetadata(NativeActivityMetadata metadata) {
base.CacheMetadata(metadata);
metadata.RequireExtension<ButtonsExtension>();
metadata.RequireExtension<ActorsService>();
if (string.IsNullOrEmpty(Code)) metadata.AddValidationError("Не указан код кнопки");
if (string.IsNullOrEmpty(Text )) metadata.AddValidationError("Не указан текст кнопки");
}
protected override void Execute(NativeActivityContext context) {
var bm = context.CreateBookmark(context.ActivityInstanceId);
context.GetExtension<ButtonsExtension>().RegisterButton(context.ActivityInstanceId, Code, Text, Actor.Get(context), bm);
context.GetExtension<ActorsService>().Link(context.WorkflowInstanceId, context.ActivityInstanceId, Actor.Get(context));
}
private void OnFinish(NativeActivityContext context) {
context.GetExtension<ButtonsExtension>().UnregisterButton(context.ActivityInstanceId);
context.GetExtension<ActorsService>().Unlink(context.WorkflowInstanceId, context.ActivityInstanceId);
}
protected override void Cancel(NativeActivityContext context) {
base.Cancel(context);
OnFinish(context);
}
protected override void Abort(NativeActivityAbortContext context) {
base.Abort(context);
OnFinish(context);
}
private void OnResume(NativeActivityContext context, Bookmark bm, object value) {
OnFinish(context);
if (value is Exception) throw (Exception)value;
}
}
public class ButtonsExtension : PersistenceParticipant {
const string qname = "{my-namespace}Buttons";
private List<ButtonInfo> activeButtons = new List<ButtonInfo>();
public void RegisterButton(string activityInstanceId, string code, string text, string actor, Bookmark bm) {
activeButtons.Add(new ButtonInfo { ActivityInstanceId = activityInstanceId, Code = code, Text = text, Actor = actor, Bookmark = bm });
}
public void UnregisterButton(string activityInstanceId) {
activeButtons.RemoveAll(b => b.ActivityInstanceId == activityInstanceId);
}
public IEnumerable<ButtonInfo> GetActiveButtons() {
return activeButtons;
}
protected override void CollectValues(out IDictionary<XName, object> readWriteValues, out IDictionary<XName, object> writeOnlyValues) {
readWriteValues = new Dictionary<XName, object> { { qname, activeButtons } };
writeOnlyValues = null;
}
protected override void PublishValues(IDictionary<XName, object> readWriteValues) {
activeButtons = (List<ButtonInfo>)readWriteValues[qname];
}
}
public class ActorsService; // Этот класс просто работает с БД, его реализация не интересна
public class ButtonInfo {
public string ActivityInstanceId {get; set;}
public string Code {get; set;}
public string Text {get; set;}
public string Actor {get; set;}
public Bookmark Bookmark {get; set;}
}
public class ObserveAndExecuteActivity<T> {
public ActivityFunc<ChangesDetectionContext, IEnumerable<T>> Selector {get; set;}
public ActivityAction<T> Trigger {get; set;}
public ActivityAction<T> Body {get; set;}
private Variable<ChangesDetectionContext> cdContext = new Variable<ChangesDetectionContext>("cdContext");
private Variable<Bookmark> selectionBookmark = new Variable<Bookmark>("selectionBookmark");
private Variable<Dictionary<T, ActivityInstance>> triggerInstances = new Variable<Dictionary<T, ActivityInstance>>("triggerInstances", new Dictionary<T, ActivityInstance>());
protected override void CacheMetadata(NativeActivityMetadata metadata) {
base.CacheMetadata(metadata);
metadata.RequireExtension<ObserverService>();
metadata.AddImplementationVariable(cdContext);
metadata.AddImplementationVariable(triggerInstances);
metadata.AddImplementationVariable(selectionBookmark);
}
protected override void Execute (NativeActivityContext context) {
StartSelector(context);
}
private void StartSelector(NativeActivityContext context) {
var cdctx = new ChangesDetectionContext();
cdContext.Set(context, cdctx);
context.ScheduleFunc(Selector, cdctx, OnSelectorComplete);
}
private void OnSelectorComplete(NativeActivityContext context, ActivityInstance instance, IEnumerable<T> value) {
if (instance.State == ActivityInstanceState.Cancelled) return;
selectionBookmark.Set(context, context.CreateBookmark(context.ActivityInstanceId, OnReselect));
context.GetExtension<ObserverService>().SetDeps(context.WorkflowInstanceId, context.ActivityInstanceId, cdContext.Get(context).Detect());
cdContext.Set(context, null);
var triggers = triggerInstances,Get(context);
foreach (var v in value.Except(triggers.Keys).ToList())
triggers.Add(v, context.ScheduleAction(Trigger, v, OnTriggerComplete);
foreach (var v in triggers.Keys.Except(values).ToList()) {
context.CancelChild(triggers[v]);
triggers.Remove(v);
}
}
private void OnReselect(NativeActivityContext, Bookmark bm, object value) {
selectionBookmark.Set(context, null);
StartSelector(context);
}
private void OnTriggerComplete(NativeActivityContext context, ActivityInstance instance) {
if (instance.State == ActivityInstanceState.Cancelled) return;
context.CancelBookmark(selectionBookmark.Get(context));
selectionBookmark.Set(context, null);
context.CancelChildren();
var v = triggerInstances.Get(context).Single(pair => pair.Value == instance).Key;
triggerInstances.Set(context, null);
context.GetExtension<ObserverService>().Unregister(context.WorkflowInstanceId, context.ActivityInstanceId);
context.ScheduleAction(Body, v, OnBodyComplete);
}
protected override void Cancel(NativeActivityContext context) {
base.Cancel(context);
context.GetExtension<ObserverService>().Unregister(context.WorkflowInstanceId, context.ActivityInstanceId);
}
protected override void Abort(NativeActivityAbortContext context) {
base.Abort(context);
context.GetExtension<ObserverService>().Unregister(context.WorkflowInstanceId, context.ActivityInstanceId);
}
}
Workflow в Document Approval System