Thursday, October 11, 2007

How to terminate a work item when its smart part closes?

I've been google-ing around for a solution to this, but had no luck. It seems that either the designers of the Composite UI Application Block (CAB) have entirely overlooked a pretty common situation or I am missing something obvious... The problem is quite simple: you have a WorkItem with a single view. When the WorkItem is run, it displays its view control (a smart part) in an MDI workspace - which means the control is automatically put inside an mdi child window. So, when the window is closed, you'd naturally want the WorkItem terminated.

Well, CAB doesn't do this for you, and rightly so because the WorkItem is not a part of the window even though its SmartPart is. You have to do this yourself. The most logical solution could be to handle the SmartPartClosed event on the MDI workspace and close your WorkItem at the moment the smart part is closed... Yeah, but there is no SmartPartClosed event, only SmartPartClosing! You could add it yourself, as John Luif did, or you could look for a workaround...

Since I don't like changing code published by others, I tried the latter option. If I try to terminate my work item from the SmartPartClosing event, the WindowWorkspace throws an exception because terminating the WorkItem kills everything inside it, probably including the smart part and maybe even the workspace itself. So when the SmartPartClosing event handler returns to the workspace, the workspace is not in its previous state anymore... (Note that I'm assuming that this behavior is not a bug - which it could be). But wait, there's a workaround for this one also: the SmartPartClosing event is cancelable. So, if I cancel the smart part close and terminate the WorkItem instead... Like this:

void containerWorkspace_SmartPartClosing(object sender, WorkspaceCancelEventArgs e)
{
if(e.SmartPart == mySmartPart)
{
// cancel the closing operation and terminate the workitem instead
e.Cancel = true;
this.Terminate();
}
}

Nice one: that is, ugly but working. Or is it? When the user tries to close the main MDI form, this triggers closing of all child forms, but this gets canceled at the first window. What now?

Well... I did this -
 protected override void OnClosing(CancelEventArgs e)
{
//base.OnClosing(e);
WorkItem.Terminate();
}

- in the MDI form. Even uglier, but it seems to work. Now, if I could figure out the reason why CAB works this way (there may well be one) I'd know if this solution is right.