A UI over Windows Workflow - c#

Are there any build in UI capabilities when using Windows Workflow..
Lets say I have a workflow that takes an hour to run where different activities are happening all the time. While it's running I want to see what activity is currently active, what activities have already ran etc..
Do I have to code this UI myself or does WF have built in features that graphically show the status etc of the workflow?

To find out which state a workflow is in, I subscribe to the WorkflowIdled event and do something like this:
private delegate void UpdateDelegate();
void workflowRuntime_WorkflowIdled(object sender, WorkflowEventArgs e)
{
StateMachineWorkflowInstance stateMachineInstance = new StateMachineWorkflowInstance(MyManager.WorkflowRuntime, MyInstance.Id);
UpdateDelegate LclUpdateDelgate = delegate()
{
// Update the workflow state on the form thread
if (stateMachineInstance.CurrentState != null)
LabelWorkflowState.Text = stateMachineInstance.CurrentStateName;
else
LabelWorkflowState.Text = "";
};
this.Invoke(LclUpdateDelgate);
}

There is no built in UI.
But you can create one, either by subscribing to events on the WorflowInstance (see other answer), or by using the Tracking Service.
The former is simple to set up for a quick solution but the latter will work with multiple host processes and long running (unloaded) workflow instances.

Check out the this code sample over at MSDN:
http://msdn.microsoft.com/en-us/library/ms741706.aspx

Related

App not processing events while trying to open database connection

I am writing a Windows Forms app in C# with Visual Studio 2022 on a Windows 10 machine. The app connects to an Azure database, which works fine. My issue is that sometimes it takes several seconds to connect (maybe 10 or so), or if there is an error it goes all the way to the timeout limit (usually 20 to 30 seconds) before coming back with whatever error message there is.
I am trying to provide some visual feedback to the user during this time, but the application does not appear to be processing any events, so whatever type of feedback I'm trying to send does not get done until the operation completes (at which point it is moot).
Any ideas on how to deal with this? Do I need to open the database on a different thread, and if so, will that be an issue throughout the rest of the app whenever I use the database object opened on a different thread?
I'm trying something simple, like gradually adding a row of dots, like so:
private void InitCloudDatabase()
{
Boolean success = true;
WorkingTimer.Enabled = true;
WorkingTimer.Start();
try
{
AzureAgDatabase db = new AzureAgDatabase();
db.OpenConnection();
}
catch
{
success = false;
}
WorkingTimer.Stop();
pbCloudResult.Image = (success) ? Properties.Resources.icons8_done_96 :
Properties.Resources.Red_X___Fail;
}
private void WorkingTimer_Tick(object sender, EventArgs e)
{
lblCloud.Text += " .";
if (lblCloud.Text.Contains(" . . . . . . . . . . ."))
{
lblCloud.Text = "Database Connection (Cloud)";
}
}
I haven't really worked with Windows Forms before, but in most UI based applications, you should reserve the UI Thread for just UI operations and move all time consuming tasks (Compute or I/O) to a different thread to ensure that the UI is still responsive.
In the case of Windows Forms, looks like you have a BackgroundWorker class that you can use to offload the DB operations into. Here is a walkthrough in the official docs that you can refer to.
Another approach would be to use the Task class to run your database code asynchronously, with lesser code compared to the first approach. You would simply wrap statements that take time in a Task.Run call and have follow up statements in a continuation task.

WF4 - Resuming workflows with delay

I'm trying to automatically resume workflows when the delay is over (using a delay activity)
This is done automatically if you use WorkflowServiceHost, but I'm using WorkflowApplication.
There are a few codes on the internet that handle this, here is a sample
I'm using WorkflowApplication to achieve these goals:
A user create a task, and this task follow a workflow
User design it's own workflow using a rehosted designer, and his workflow definition is saved in the database.
Each workflow definitions can have different versions saved in the database to allow the user to modify its workflows, and the code use the correct version when an action is done on a task and it needs to resume bookmarks
A task can be started using a workflow, so in the task table I store which workflow definition and which version is used for this task.
The problem I've now is when using delay activity
Using the code linked above, when a runnable instance is detected I need to create a WorkflowApplication and use the LoadRunnableInstance method to load the workflow:
if (hasRunnableWorkflows)
{
Console.WriteLine("Found runnable workflows");
WorkflowApplication app = new WorkflowApplication(...);
app.InstanceStore = store;
app.LoadRunnableInstance();
}
Problem is:
To call LoadRunnableInstance, I need to create the WorkflowApplication and so I need to give the root activity to the WorkflowApplication CTor
To create the the root activity, I need to know which workflow (& version) I need to load from database
To know which workflow to load, I need the task ID
To know the task ID, I need to know the Workflow ID, which is only available after the call to LoadRunnableInstance
So ... I need to break this loop :)
Does someone know a way to have the Workflow ID before loading the workflow ?
The ControllingWorkflowApplications sample from the Microsoft wcf and wf samples shows that the system has to maintain it's list of workflow id's to know what workflows to load from the instance store. In that example, they also keep the path the workflow xaml file which should be able to handle your versions. That example isn't the easiest to follow but an extension to the WorkflowAppication that inherits from PeristenceIOParticipant is added to WorkflowApplication. This class extracts and defines the additional data that will be saved with the workflow. For your purposes that would be the id.
instance.Extensions.Add(() => new WorkflowDefinitionExtension(originalPath, connectionString)); //inherits from PeristenceIOParticipant
This worked for me.
When the Delay activity is hit by the workflow runtime, event PersistableIdle is fired and if it returns PersistableIdleAction.Persist
then the Delay activity will be automatically resumed. If event handler returns PersistableIdleAction.Unload then the Delay activity won't be resumed
automatically.
Here is the Sample,
Workflow Definition:
Variable<string> name = new Variable<string>
{
Name = "name"
};
wf = new Sequence
{
Variables =
{
name
},
Activities =
{
new WriteLine()
{
Text = "Workflow Triggered"
},
new Delay()
{
Duration = TimeSpan.FromSeconds(10)
},
new WriteLine()
{
Text = "Activity1 Completed"
},
}
};
WorkflowApplication:
WorkflowApplication wfApp = new WorkflowApplication(wf);
wfApp.PersistableIdle = delegate (WorkflowApplicationIdleEventArgs e)
{
return PersistableIdleAction.Persist;
};
// Start the workflow.
wfApp.Run();

C#: Periodically update GUI based on backgroundtask

I have a GUI that is for all intents and purposes really basic. A listview, an html form, and that's really it.
I want the user to have the following behavioral ability:
1 - Click a checkbox that says "Real-time". When clicked, a background thread will run once every 10 seconds.
2 - If there is a new file created (this is easy, to observe a new file) I want an alert displayed in my main gui. Where it is displayed for now is arbitrary (in a label, for example).
The main issue is I cannot figure out how to do this in a multi-threaded example. My goal is exactly in line with multithreading: do tasks 1 and 2, without locking task 1. Meaning, while the update check is running, the user can interact with the GUI as if nothing was going on in the background.
If you need more details to better answer this please let me know.
Thanks!
Here are a couple sites I found useful for implementing a background worker when I needed to perform database operations while still allowing the GUI to be responsive:
http://msdn.microsoft.com/en-us/library/zw97wx20.aspx
http://www.codeproject.com/KB/cs/AsynchronousCodeBlocks.aspx
Use events from the thread to tell the UI that something's changed:
// Just detected that that a new file has been created
if (this.FileCreated_Event != null)
{
this.FileCreate_Event(this, new FileEventArgs(newFileName));
}
where FileCreated_Event and FileEventArgs are declared appropriately.
Then in the UI when you receive the event you have the following:
this.fileChecker.FileCreated_Event += this.FileCreated_Event;
and:
private void FileCreated_Event(object sender, TrackStatusEventArgs e)
{
if ((sender as Control).InvokeRequired)
{
(sender as Control).Invoke(action);
}
else
{
action();
}
}
where action is the thing you want to do.
Try this tutorial. At the end I'm sure you'll be able to use threads. You must be careful though, because you'll have to manage those threads which can be a daunting task. I've never met a programmer who liked to debug multiple threads...

How do I manage threads in a C# web app?

I built a little web application that displays charts. I was thinking that it might be useful for the superuser of the app to do a complete data refresh, however this process takes around 10 minutes to complete. I was thinking perhaps the user could click a button that would start off a new thread to do a data refresh and subsequent clicks would kill the thread and restart the data population process. The user would then be free to browse about the site and view the charts as their data is populated.
Is there a simple method of accomplishing something like this?
You can twist ASP.NET to do this sort of thing, but it violates a few good general rules for ASP.NET development -- and could really cause problems in a server farm.
So, the most obvious route is to do this work in a web service. You can have the method return a chunk of HTML if you want. You could also add status methods to see how the thread is progressing.
Other options include: Handing the intense processing off to a database server (sounds like this might be a good use of OLAP) or, another cheap trick might be to set up the click to fire off a scheduled task that runs on the server. Can you provide some additional detail about the environment? Single server? Data storage platform, version of .net?
Ok, I didn't use either answer so here is what I did. I decided that it would be better if subsequent clicks would terminate instead of the currently executing one. Thanks for your answers guys.
//code behind
protected void butRefreshData_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(DataRepopulater.DataRepopulater.RepopulateDatabase));
t.Start();
}
//DataRepopulater.cs
namespace DataRepopulater
{
public static class DataRepopulater
{
private static string myLock = "My Lock";
public static void RepopulateDatabase()
{
if(Monitor.TryEnter(myLock))
{
DoWork();
Monitor.Exit(myLock);
}
}
}

Create thread just like if it were a separated application in C#

I've been having a bunch of exceptions when trying to use a WebBrowser on a multithread application. COM component, protected memory and other exceptions everywhere I do stuff with the WebBrowser. I just gave up and went back to my single thread version which works fine. I would post code but it's hard to localize the cause of the problem when I get exceptions at so many spots. So, if as a single thread application it runs fine, and if when I run several instances of the same application it also works fine, there should be a way to simulate several applications running from a single application without having to actually make a separated application that I would run from the main application. My question, then, is how can I make Windows treat my threads as if they were different instances? This should eliminate the problem, since, as I said, when they ARE different instances I don't get any exception. Hope I'm being clear enough.
WebBrowser is a COM component under the hood, Internet Explorer. Like many COM components, it requires a 'single threaded apartment'. You have to create one to make it a hospitable home for the component. Basically two essential requirements: the thread needs to be initialized as an STA and it needs to pump a message loop.
Here's one that uses the plumbing provided by Windows Forms:
private void runBrowserThread(Uri url) {
var th = new Thread(() => {
var br = new WebBrowser();
br.DocumentCompleted += browser_DocumentCompleted;
br.Navigate(url);
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
var br = sender as WebBrowser;
if (br.Url == e.Url) {
Console.WriteLine("Natigated to {0}", e.Url);
Application.ExitThread();
}
}
Beware that the DocumentCompleted event gets raised on that worker thread. I arbitrarily used that event to also make the thread terminate.
I think your issue may have something to do with the way Microsoft.NET handles UI controls. Basically, any method for a control must be called from the thread that created it (perhaps even the main UI thread exclusively). Otherwise, you will get a bunch of access-related exceptions. I believe you will need to use the InvokeRequired property and Invoke method to call into the control, which also means that you will have to define a delgate function that wraps each method you want to call. Using the WebBroweser.Url property as an example, you could write something like this:
public delegate void SetWebAddressDelegate ( WebBrowser browser, Uri newUrl);
public void SetWebAddress ( WebBrowser browser, Uri newUrl )
{
if (browser.InvokeRequired)
browser.Invoke(new SetWebAddressDelegate(SetWebAddress), browser, newUrl);
else
browser.Url = newUrl;
}
It sounds like you might be sharing a single WebBrowser instance across threads. If each thread has its own instance, and the threads aren't communicating with each other, I would expect that to be equivalent to running multiple instances of the process.

Categories