MDI parent issue with CAB and deckworkspace

Topics: CAB & Smart Client Software Factory
Aug 15, 2006 at 7:16 AM
originally posted by: johnAtWatson

Hello,

I have a root level deckworkspace in the Shell form, with IsMdiContainer = true. When I set the MdiParent = this (Shell Form), it is hidden behind this deckworkspace. When I don't set the MdiParent, it displays both forms, Parent and Child, but separate window instances, not constrained within the same application window. SendToBack, BringToFront have no effect.

The layout of the application includes a Office 2k7 Ribbon Control at the top, status at the bottom, Outlookbar on the left, and a content window on the right where I want Mdi children to display.

Using CAB, what recommendations would you have to display the Mdi Children within the constraints of a content area child deckworkspace, and also be a child of the parent mdi application. Can you have a mdiworkspace within another deck or zone workspace? Or can Mdi only exist at the root form level?

Thanks for anyone's expertise,

John

_layoutWorkspace.Name = WorkspaceNames.LayoutWorkspace;
CustomChildMdiWindow doc = new CustomChildMdiWindow();
//doc.MdiParent = this;
doc.Show();
Aug 15, 2006 at 8:09 PM
originally posted by: askew

The GUI contents of the application live in DLLs that ship with the solution; your modules+views. These are not wired up for the tightly-coupled MDI architecture. Instead, they are loosely-coupled, so much so that these DLLs can be redeployed without recompiling the main executable or the rest of the system.

To reproduce the affect of MDI using CAB, I would use the Event Broker to pass messages through events between the shell and its many modules and their views. The Event Broker is really easy to use; publish & subscribe recipies... you can make your own event-argument classes to allow editing the messages as they flow through the subscribers.

Think of a module as a plugin and you can see more of what CAB is capable of being and what it can't do.

HTH
Sep 4, 2006 at 1:35 AM
originally posted by: repattern

John, you wrote:
The layout of the application includes a Office 2k7 Ribbon Control at the top, status at the bottom, Outlookbar on the left, and a content window on the right where I want Mdi children to display.

So what you need this DeckWorkspace for?
Sep 5, 2006 at 9:05 AM
originally posted by: marianoszklanny

John, if you want to use MDI windows, you should remove the DeckWorkspace in the Shell. Use the DeckWorkspace only to show SmartParts in an overlapped manner with no visible frame.

Also, take into account that if you want to use an MdiWorkspace, you can’t use a separate module to define the layout. To use an MdiWorkspace in the Shell, follow these steps:

1. Create a Smart Client solution without a separate module for the Shell layout.
2. Open the designer for the ShellForm and delete the _leftWorkspace, the _rightWorkspace and the splitContainer1.
3. Set the IsMdiContainer property of the ShellForm to True.
4. In the ShellForm constructor remove the following lines (because the workspaces no longer exist):

_leftWorkspace.Name = WorkspaceNames.LeftWorkspace;
_rightWorkspace.Name = WorkspaceNames.RightWorkspace;


5. Open the file Constants\WorkspaceNames.cs in Infrastructure.Interface project and delete the constant definitions for the right/left workspaces:

public const string LeftWorkspace = "LeftWorkspace";
public const string RightWorkspace = "RightWorkspace";

6. Add a constant definition for the MdiWorkspace:

public const string MdiWindows = "MdiWindows";

7. Open the file ShellApplication.cs in the Shell project and the following lines to the AfterShellCreated method:

// Create the MdiWorkspace and use the Shell as the parent form
MdiWorkspace wsp = new MdiWorkspace(Shell);

// Add the MdiWorkspace to the root WorkItem.
RootWorkItem.Workspaces.Add(wsp, WorkspaceNames.MdiWindows);

8. To show a View in the MdiWorkspace do it as you do with every workspace. For example:

// ModuleController.cs of a business module
private void AddViews()
{
View1 view = WorkItem.SmartParts.AddNew<View1>();
WorkItem.WorkspacesWorkspaceNames.MdiWindows.Show(view);
}

Mariano
http://staff.southworks.net/mariano
Sep 6, 2006 at 2:59 AM
originally posted by: plombaer

Thanks a lot.

I've a small question.
How can I detect that the Mdi window (view) is being closed ?
My guess was this :
Form viewForm = (WorkItem.WorkspacesWorkspaceNames.MdiWindows as MdiWorkspace).Windowsview;
viewForm.FormClosing += new FormClosingEventHandler(viewForm_FormClosing);
void mainForm_FormClosing(object sender, FormClosingEventArgs e)
{
WorkItem.Items.Remove(view);
WorkItem.Terminate();
}
Do you know other ways ?
Maybe with SmartPartClosing but then the event will be executed on every mdi child (view).
Sep 9, 2006 at 7:30 AM
originally posted by: repattern

hmm actually no I don't know

edit replaced stupid answer with something far smarter ;)
Sep 9, 2006 at 8:52 AM
originally posted by: repattern

plombaer seems to be adding views to the Items collection (like in on of the samples) whereas marianoszklanny adds 'em to the SmartParts collection of the WorkItem.

anyone got any info on these different approaches (or doesn't it matter all that much)?
Sep 9, 2006 at 9:31 AM
originally posted by: marianoszklanny

Hi,
Using the SmartPartClosing event you can get the actual view being closed by accessing the SmartPart property of the WorkspaceCancelEventArgs. Of course, as you said, the event will be fired for every child view. If you need to know when a particular view (a particular instance) is being closed, you might want to use the approach you mentioned.

Mariano
http://staff.southworks.net/mariano
Sep 9, 2006 at 9:46 AM
originally posted by: marianoszklanny

In practice, you can use any of the two approaches. But I recommend you to store SmartParts in the WorkItem.SmartParts collection, mainly to keep things more organized. Leave the Items collections for objects that have no specific collection in the WorkItem.

The main difference between the Items and the SmartParts collection is that the Items collection works with all kind of objects. The SmartParts collection filters the objects that do not contain the SmartPart attribute.

Mariano
http://staff.southworks.net/mariano
Oct 7, 2006 at 3:56 AM
originally posted by: owtuv

Mariano,

<< WorkItem.WorkspacesWorkspaceNames.MdiWindows.Show(view); >>

How do we configure child Mdi windows to open maximized ?

Also, the Smartpart view doesn't seem to resize when contained in a MdiWorkspace.

Regards,
Ole Willy Tuv
Oct 18, 2006 at 8:27 PM
originally posted by: surajguptha

marianoszklanny ,
Thanks. It is a very useful writeup about using MDI in SCSF.
Mar 27, 2007 at 1:37 AM
Edited Mar 27, 2007 at 1:50 AM

gdngenericuser wrote:
originally posted by: plombaer

Thanks a lot.

I've a small question.
How can I detect that the Mdi window (view) is being closed ?

Do you know other ways ?
Maybe with SmartPartClosing but then the event will be executed on every mdi child (view).


In the following example I only want a form loaded once - if the form is already loaded I want to ensure its WindowState is normal (in case the user minimized it). Note: WorkItem.Items.Removed will only notify us about the Views presenter being removed - note about the view; a presenters view could be left dangling which caused me problems when I first used this approach. After the example I show the files/source to add WindowState (e.g., maximize form) - I saw a question wanting to know how to do this.

private void AddViews()
{
    WorkItem.Items.Removed += new EventHandler<DataEventArgs<object>>(Items_Removed);
}
void Items_Removed(object sender, DataEventArgs<object> e)
{
    if (e.Data is TeamContactViewPresenter)
        WorkItem.Items.Remove( WorkItem.Items.Get<TeamContactView>("TeamView"));
}
[CommandHandler(CommandNames.ViewTeam)]
public void ViewTeamHandler(object sender, EventArgs e)
{
    TeamContactView teamView = WorkItem.Items.Get<TeamContactView>("TeamView");
    IWorkspace mainWorkspace = WorkItem.Workspaces["mainWorkspace"];
    WindowSmartPartInfo formInfo = new WindowSmartPartInfo();
 
    // Only display view if not already loaded
    if (teamView == null){
        teamView = WorkItem.Items.AddNew<TeamContactView>("TeamView");
        formInfo.Title = "Team Contact Manager";
    } else {
        // In case form was minimized - restore to normal
        formInfo.WindowState = FormWindowState.Normal;
    }
    mainWorkspace.Show(teamView, formInfo);
}

Note: To get WindowState I made the following changes to CAB (I'll later move these into a derived class so I can easily upgrade).

CAB\CompositeUI.WinForms
- Workspaces\WindowSmartPartInfo.cs - ADDED all of the following
        private FormWindowState _windowState = FormWindowState.Normal;
        /// <summary>
        /// Gets/Sets the window state (Normal, Minimized, Maximized)
        /// </summary>
        [DefaultValue(FormWindowState.Normal)]
        [Category("Layout")]
        public FormWindowState WindowState
        {
            get { return _windowState; }
            set { _windowState = value; }
        }
- Workspaces\WIndowWorkspace.cs - ADDED form.WindowState line
protected void SetWindowProperties(Form form, WindowSmartPartInfo info)
{
    form.Text = info.Title;
    form.Width = info.Width != 0 ? info.Width : form.Width;
    form.Height = info.Height != 0 ? info.Height : form.Height;
    form.ControlBox = info.ControlBox;
    form.MaximizeBox = info.MaximizeBox;
    form.MinimizeBox = info.MinimizeBox;
    form.Icon = info.Icon;
    form.Location = info.Location;
    form.WindowState = info.WindowState;
 
}