This project is read-only.

Close a WindowWorkspace when Cancel is clicked on the SmartPart

Sep 21, 2007 at 5:08 PM
I have code:

LoginCompositeView logineView = workItem.SmartParts.AddNew<LoginCompositeView>();
shell.ShowInDialogWindow(logineView);

loginView is a SmartPart with a Cancel/OK buttons on it.
I want window to be closed when that Cancel is clicked.

ShowInDiaplogWindow method does:
public void ShowInDialogWindow(object part) {
rootWorkItem.Workspaces[WorkspaceNames.ModalWindow].Show(part);
}

How can I let WindowWorkspace know that it is time to go away?

Any ideas?
Sep 22, 2007 at 9:31 AM
Edited Sep 22, 2007 at 9:32 AM
This should work:

Worspaces[WorkspaceNames.ModalWindow].Close(part)
Sep 24, 2007 at 11:54 PM
What you have suggested will work, but, not in my case, since showing view is encapsulated in the shell. I.e. I don't have an access to the workspace.

ShowInDialogWindow is a method on IShell interface. As a result, when view is opened, it does not have a reference to the workspace, in fact view does not even know that it was shown on the workspace.

That is it is possible to place the smartpart on the canvas instead of workspace.

My first guess is that I will have to hack (change) workspace to support that, though I think it is impossible to do, since workspace operates with objects.

I could find workspace in the workitem, but I want to devise a solution that would be free of workspace presence assumption.

Regards,
Roman V. Gavriov
Sep 25, 2007 at 9:25 AM
Every Workspace defined in the shell is accesible from every workitem in the application.

Anyway, I'll tell you how I'm handling showing and closing smart parts in the application I'm developing. I'm not an expert on CAB, I'm pretty new on CAB, so my approach might not be the best approach.

I'm not using WorkItemControllers, instead, I create classes that inherit from WorkItem. Every workitem class in the application inherits from WorkItemBase which in turn inherits from WorkItem.

In the WorkItemBase class, I have defined some helper methods:

ShowSmartPart( workspaceName, smartPart) and ShowSmartPart( workspaceName, smartPart, smartPartInfo) : these methods show the specified smart part on the specified workspace and keep track on which workspace is shown each smart part.

CloseSmartPart( smartPart ): this method closes the smart and removes the smart part from the workitem. It knows on which workspace the smartpart is on.

You could also define the ShowInDialogWindow by calling one of the preceding methods.

Since the container workitem is accesible from everywhere (you could use dependency injection), the CloseSmartPart method is accesible from everywhere.
Sep 27, 2007 at 4:01 AM
FYI: There is a WorkspaceLocatorService for what you are doing, and it is used within SCSF's Presenter base class.

Problem with that approach is that workspace is assumed. Which makes smartpart workspace aware, and coupled. Not necesserely a bad thing, I just want to see if there is another way, a way that would shift the burden of workspace manegment over to the workspace, away form view (smartpart) or view cunsumer (e.g. an action that shew the view).

Regards,
Roman V. Gavrilov
Sep 27, 2007 at 6:46 AM
Edited Sep 27, 2007 at 7:02 AM
Presumably LoginCompositeView is a view and has a presenter. If LoginCompositeView has a presenter, its feasable that when the presenter invokes OnViewSet, the concrete presenter could add an invoker mapped to the cancel buttons click event.

Subsequently, the presenter could also have a method decorated with CommandHandler attribute for the cancel buttons click event

Presenters know about the workitem.

Furthermore, I dont really see the point in making it Workspace agnositc. After all isnt Shell.ShowInDiaplogWindow workspace specific?

EDIT: My point really is that in your implementation of IShell you wrote some code to add a smart part to a workspace. Now you need a way to clean that smart part up. In my (limited) experience WorspacesworkspaceName.Close(part) works fine. Maybe you should modify your ShowInDialogWindow method to use an out parameter OR have it return the name of the workspace that it added the smart part to. The caller of ShowInDialogWindow would hold on to the targetWorkspaceName returned and use that value later to clean up the smart part. Maybe yopu could even write aRemoveSmartPart method in Shell that would take in the smart part to remove, along with the targetWorkspaceName and use the WorkspaceLocatorService to find the target workspace and remove the smart part. The implementation of Shell does know about workspaces because if it didnt it couldnt add the smart part to the window workspace.

ShowInDiaplogWindow1 method does:
public string ShowInDialogWindow(object part) {
string targetWorkspaceName= WorkspaceNames.ModalWindow;
rootWorkItem.WorkspacestargetWorkspaceName.Show(part);
return targetWorkspaceName;
}

ShowInDiaplogWindow2 method does:
public string ShowInDialogWindow(object part, out string targetWorkspaceName) {
targetWorkspaceName= WorkspaceNames.ModalWindow;
rootWorkItem.WorkspacestargetWorkspaceName.Show(part);
return targetWorkspaceName;
}
Sep 28, 2007 at 6:10 PM
Edited Sep 29, 2007 at 5:30 PM


Furthermore, I dont really see the point in making it Workspace agnositc. After all isnt Shell.ShowInDiaplogWindow workspace specific?

Right to the point. Yes, it is not. There is nothing in the method "void IShell.ShowInDialogWindow(object view)" says it has to do anything with workspaces. For all I know I can put it in the Viewbox. This issue is the central point of this discussion - hiding workspace concept in the shell, so View (smartpart) developer can be free of this consideration.

EDIT: My point really is that in your implementation of IShell you wrote some code to add a smart part to a workspace. Now you need a
way to clean that smart part up. In my (limited) experience WorspacesworkspaceName.Close(part) works fine. Maybe you should modify your ShowInDialogWindow method to use an out parameter OR have it return the name of the workspace that it added the smart part to. The caller of ShowInDialogWindow would hold on to the targetWorkspaceName returned and use that value later to clean up the smart part.


Maybe yopu could even write aRemoveSmartPart method in Shell that would take in the smart part to remove, along with the targetWorkspaceName and use the WorkspaceLocatorService to find the target workspace and remove the smart part.

You are right, this would hide the workspace in the shell. Though if an instance of the view is used to locate the workspace - then it essentially makes the view a singleton - which is a restriction for no reason. (EDIT: Not sure why I said that it makes smartpart a singleton, it doesn't make any sense now).
Also, ShowInWindowDialog can return IWorkspace, or (if I want to be really workspace free) an IContainer, instead of name. But problem is the same (as with returning workspace name, or putting RemoveSmartPart method) - view's presenter does not make a call to the
Shell on the first place. To fix that - view should be shown through presenter, i.e.:

workItem.Items.AddNew<LoginPresenter>().ShowIn(shell.GetWindowWorkspace());

Though I don't see how it is better.

My favorite solution (so far) is to have an event on the smartpart event EventHandler Closing - workspace (or soemthing else) can listen for the event (part of "ICanBeClosed" interface) - IoC literaly. This way there is no exposure to workspace in the view or presenter, there is a price, ofcause - RTTI. I.e.
void IWorkspace::Show(object smartPart) {
if (smartPart is ICanBeClosed) { smartPart.Closing += HandleClosingRequest; }
}

I don't see anything wrong with this solution. And I think this whole problem (the way I see it) araises from the fact that workspaces manipulate objects, instead of having ISmartPart interaface dependency. Should we add ISmartPart interface and use it together with SmartPartAttribute (though this would make attribute superfulous). I can probably come up with few more behaviors to add to the ISmartPart.

Feedback?