By Ivan George Borges - 12/11/2006
Hiya.I am shamelessly trying to copy "someone's" idea of a MainForm. My intention is to get rid of the MenuStrip and use the ThemedToolStrip instead. So far, so good. But now I got to the "Window" item, which will show the opened MDI windows list. Now I would need to have a "Window" ToolStripDropDownButton to behave in the same way as the MenuStrip MdiWindowListItem. Would that be too difficult to implement? Cheers.
|
By Trent L. Taylor - 12/11/2006
I am shamelessly trying to copy "someone's" idea of a MainForm. I wonder where I have seen that done before Now I would need to have a "Window" ToolStripDropDownButton to behave in the same way as the MenuStrip MdiWindowListItem. Would that be too difficult to implement? It really isn't too difficult. We actually use a list instead of updating the DropDown menu, which is easier and takes less time. In either case, you just need to "wrap" the loading and closing of your forms. We have a menu system that wraps all of our menu calls and we create a handler when the form is created. Also, when the form is created we add it to the list and pass along the window handle. When the forms "FormClosed" event fires, we then remove the item from the list. The above is a screen shot from our medical system and shows how we implement the Windows Panel. Ours is a little more complicated because we actually have a legacy VFP session within the MDI environment as well as the .NET forms. So both of them have to show up in this panel which is a little more cumbersome. But for .NET only forms, this is much easier because you are directly in control of the forms. One other option is to just monitor the MDIChildren property of the MDI form or client. The MDI client or form has a property called MdiChildren which is a list of all of the visible forms: Me.MdiChildren In any case, there are a number of ways to monitor the forms and place them in a collection and deal with them. If this doesn't get you started let me know and I will give you some more snippets.
|
By Ivan George Borges - 12/11/2006
I see you copied from the same person!!! Yeah, I found your main form pretty sharp, so I'm trying the same. I got the idea, will work on it. If I feel like completely lost, I will cry for help. I'm looking for the proper way to "wrap" the loading and closing of the forms ... just need to find a nice peace of paper. Thanks Trent.
|
By Trent L. Taylor - 12/11/2006
If I feel like completely lost, I will cry for help. Sounds good. just need to find a nice peace of paper. I don't know that one exists. Here is a sample method to load up all of your client forms in the MDI. Declare the form collection
''' <summary> ''' Collection of all of the forms ''' </summary> ''' <remarks></remarks> Private _Forms As New System.Collections.Generic.Dictionary(Of Integer, System.Windows.Forms.Form) Create a reusable method to load a child form
''' <summary> ''' A reusable method that allows forms to be launched. This will reside in your ''' MDI form. ''' </summary> ''' <param name="FormType"></param> ''' <remarks></remarks> Public Sub LoadForm(ByVal FormType As System.Type) '-- Establish Locals Dim loForm As System.Windows.Forms.Form '-- Create the form loForm = CType(Activator.CreateInstance(FormType), Form) '-- Associate the new form with the MDI form loForm.MdiParent = Me '-- Add a handler to the form close AddHandler loForm.FormClosed, AddressOf HandleFormClosed '-- This is a good place to update your open form collection _Forms.Add(loForm.Handle.ToInt32(), loForm)
'-- Update the list or menu '-- Show the form loForm.Show() End Sub Create a handler method that is used to trap the FormClosed event. This will be assigned in the LoadForm() method
''' <summary> ''' Handles the closing of the form ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub HandleFormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) '-- Establish Locals Dim loForm As System.Windows.Forms.Form '-- The sender will be the form. See if the form is in the collection If _Forms.ContainsKey(CType(sender, Form).Handle.ToInt32()) Then '-- Get the form reference loForm = _Forms(CType(sender, Form).Handle.ToInt32()) '-- Remove the handler RemoveHandler loForm.FormClosed, AddressOf HandleFormClosed '-- Remove from the collection _Forms.Remove(CType(sender, Form).Handle.ToInt32()) '-- Update your list or menu End If End Sub Sample method showing how to call the LoadForm method
''' <summary> ''' Just a sample of how to call the LoadForm method ''' </summary> ''' <remarks></remarks> Private Sub SampleLoadingForm() LoadForm(GetType(MyForm)) End Sub
|
By Ivan George Borges - 12/11/2006
wow ... thanks Trent. I had the LoadForm already, but the Handler got me stuck.I will try to populate a list just like you did. You have put the Themed Containers in a docked form on the left, is that it?
|
By Trent L. Taylor - 12/11/2006
You have put the Themed Containers in a docked form on the left, is that it? That's it. Just to improve performance on the ThemedContainer, set the MinimizeBodyBehavior to Snap instead of Scroll if you are going to allow the container to be opened and closed.
|
By Michael Reese - 12/15/2006
Hey Trent,Nice, I have been attempting to do the same. Would be nice to have the sample code in a small project Michael
|
By Ivan George Borges - 12/15/2006
Can't believe it, Trent ... I did it!!!It is even activating the item when clicked in the ListView. I can go and enjoy my Friday night now. THANKS A LOT.
|
By Trent L. Taylor - 12/15/2006
This form looks very familiar ... I just can't understand what it says Good job, I really like the way it looks!
|
By Trent L. Taylor - 12/15/2006
Seriously...it looks great!
|
By Michael Cobb - 6/14/2007
This is a good thread. This may be slightly off topic but I wasn't sure where to post this question. I have a main MDI form with the following method that is used to launch a child form. Private Sub LaunchForm(ByVal FormType As System.Type, Optional ByVal AllowMultiple As Boolean = True) '-- Look to see if the form is already loaded - bring to front If AllowMultiple = False Then For Each loCurForm As Form In Me.MdiChildren If Not loCurForm.InvokeRequired Then ' Can access the form directly If loCurForm.GetType() Is FormType Then If loCurForm.WindowState = FormWindowState.Minimized Then loCurForm.WindowState = FormWindowState.Maximized End If loCurForm.BringToFront() Exit Sub End If End If Next End If '-- Establish Locals Me.Cursor = Cursors.WaitCursor Dim loForm As Form loForm = CType(Activator.CreateInstance(FormType), Form) '-- Set the MDI loForm.MdiParent = Me '-- Show the form loForm.Show() Me.Cursor = Cursors.Default End Sub The child form has a control which needs to open a new child form in the main MDI form. Any ideas about how to accomplish this? Thanks for looking!
|
By Trent L. Taylor - 6/14/2007
I think that the best thing to do would be to expose the MDI client...or....if your main form just has the MDIContainer property set you can reference it directly. When the form is launched it will have a reference to the parent form in the ParentForm property which you can type and reference. You may need to make your LauncForm method public or Friend so it can be accessed though.DirectCast(Me.ParentForm, MainForm).LaunchForm(GetType(MyChildForm)) If you are using an MDIClient control and manually adding it to the form, then you can just expose it through a public property and basically do the same thing: DirectCast(Me.ParentForm, MainForm).MDIClientProperty.LaunchForm(GetType(MyChildForm))
|
By Michael Cobb - 6/15/2007
Thanks Trent. This works perfectly!
|
By Trent L. Taylor - 6/15/2007
Glad it worked for you
|
By StarkMike - 6/21/2007
Hi guys,A couple of questions.... I am using a picture that you used earlier in the post... how did you create that MDI with that control panel on the left? am i correct in assuming that if the user were to click or double click on the name of a form in the list in the control panel it would show that form? and second, using the code you provided earlier in this post... how would I create navigation buttons to utilize this code... lets say that I wanted navigation buttons in the MDI to be able to navigate through all the child forms... yknow the basics... first, previous, next, last. This is a really cool concept! I'm eager to implement it.
|
By Trent L. Taylor - 6/22/2007
Well, basically this is just a docked Panel on the main form which we custom render and then add the logic we need for MDI Window Activation. One thing that you can do is create an MDIClient class and then add that class as a control to the main form rather than setting the MdiContainer property....it just gives you more flexibility.This entire explanation would be more of a tutorial rather than a quick post here...and in fact, this is one of the very things that we cover during class. I know you guys haven't had a chance to make it to class in the past, but if it were at all possible, I think that you guys would gain a lot of first hand experience on items just like this if you were able to make it to the next class
|
By Teddy Jensen - 7/11/2007
Ivan,Your main form looks really good. I too was first thinking of a toolstrip dropdown that would show the open windows. Now i have decided to use a panel like yours and the one from Practice Studio, so i can use it to show some more info. I do however have issues with this (read - it doesn't look the way i want it) Can you describe how you did your panel and lists? TIA. /Teddy
|
By Trent L. Taylor - 7/11/2007
Really all you need to do is set the MdiParent property on the parent form to False. Drop a FlowLayoutPanel (or ThemedPanel) on the form and dock it left. Next, in your main form, define an MdiClient class (it is a control) as a private and manually add it to the form. This MdiClient will be where all of there client forms will appear, but the panels docking will be left intact. Private _MdiClient As New MdiClient() Public Sub New() _MdiClient.BackColor = Color.White Me.Controls.Add(_MdiClient) End Sub
|
By Teddy Jensen - 7/11/2007
Hi Trent,Thanks - i got it now. My problem was that i set the text of an employee form to the name of the employee after it is loaded from a browsedialog. So i wanted the new text of the form to be renamed/refreshed in the list. The rest was just cosmetic customations of the properties. /Teddy
|
By Ivan George Borges - 7/11/2007
Hi Teddy.I'm glad Trent could help you, he got all this from me... oh, wait, I think the orther of the words are not set properly...
|
By Edhy Rijo - 3/30/2008
H all,I am using the LoadForm method posted here to load the forms, but I would like to automate this method by passing the form name stored in a Tag property of a menu item or a DevExpress RibbonControl Item. The item will have the name of the form as string like this "frmProducers" but the LoadForm method is expecting a System.Type parameter instead of string, how can I either convert the Item.Tag string containing the form name as a System.Type expected by the LoadForm method posted here? Private Sub LoadForm(ByVal FormType As System.Type)'-- Establish LocalsDim loForm As System.Windows.Forms.Form'-- Create the form loForm = CType(Activator.CreateInstance(FormType), System.Windows.Forms.Form)'-- Associate the new form with the MDI formloForm.MdiParent = Me'-- Add a handler to the form closeAddHandler loForm.FormClosed, AddressOf HandleFormClosed'-- This is a good place to update your open form collection_Forms.Add(loForm.Handle.ToInt32(), loForm) '-- Update the list or menu'-- Show the Form loForm.Show() End Sub The whole idea is to either type the form name in the Item.Tag property or read it from a database to load all the Items and update the Item.Tag which will make a generic single call to the LoadForm. Thanks.
|
By StrataFrame Team - 3/31/2008
You can use System.Type.GetType(typeNameAsString) to convert a string to a System.Type. You'll need to store more than just "frmFormName" in the tag of the form, however, because the Type.GetType() static method requires the full name of the class. Type.GetType("MyNamespace.frmMyFormName") That will be what you'll have to give it. Also, it might be the case that that method will not be able to resolve the name because your form type exists in another assembly. If that's the case, then you'll need to give it the fully qualified assembly name. It's basically the full name with a comma and the assembly name right after it like this: "MyNamespace.frmMyFormName, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" That's the difference between the Type.GetType() static method and the GetType() keyword (the keyword turns blue when you type it). If you use the keyword, it will always resolve because the reference is resolved and at compile-time. So, you might want to create a method that will resolve the names for you and uses the keyword to get the type. Like this: Public Shared Function ResolveFormType(ByVal formName As String) As Type Select Case formName Case "frmForm1" Return GetType(frmForm1)
Case "frmForm2" Return GetType(frmForm2)
Case "frmForm3" Return GetType(frmForm3)
End Case End Function If you use this method, then the string can be any arbitrary value, as long as it's unique and you can assign it a type to return from the method.
|
By Edhy Rijo - 3/31/2008
Ben Chase (03/31/2008)
You'll need to store more than just "frmFormName" in the tag of the form, however, because the Type.GetType() static method requires the full name of the class. Type.GetType("MyNamespace.frmMyFormName") Hi Ben, Thanks for the explanation. Using Type.GetType("MyNamespace.frmMyFormName") does give me the results I was looking for.If I were to use the ReolveForm solution, I would then have to make an entry in the Case statement for every form I add to the project and all I am trying to do is to have all forms identified in a Item.Tag so I don't have to manually remember to keep adding it to the Case statement. Thanks again!!!
|
By Chan - 4/8/2008
Hi,
I tried the code snippet and convert it to C# as below. I face problem that, the value of loForm.handle is changed in HandleFormClosed event handler. Any ideas? Thank you
private void LaunchForm(System.Type FormType)
{
//-- Establish Locals
Form loForm;
//-- Create the form
loForm = (Form)Activator.CreateInstance(FormType);
//-- Set the MDI parent
loForm.MdiParent = this;
int lnHandle = (int)loForm.Handle;
loForm.FormClosed += this.HandleFormClosed;
_Forms.Add(lnHandle, loForm);
imgWindows.Images.Add(loForm.Text, loForm.Icon);
lvWindows.Items.Add(lnHandle.ToString(), loForm.Text, imgWindows.Images.Count - 1);
//-- Show the form
loForm.Show();
}
private void HandleFormClosed(object sender, FormClosedEventArgs e)
{
System.Windows.Forms.Form loForm;
loForm = (Form)sender;
int lnHandle = (int)loForm.Handle;
if (_Forms.ContainsKey(lnHandle))
{
loForm = _Forms[lnHandle];
loForm.FormClosed -= HandleFormClosed;
imgWindows.Images.RemoveByKey(loForm.Text);
lvWindows.Items.RemoveByKey(lnHandle.ToString());
_Forms.Remove(lnHandle);
}
}
|
By Chan - 4/8/2008
Hi,
May I know what control/container are you using to drop window and user panel on? I tried to use flowlayout but its docking cause themetoolstrip unable to dock to top with full screen width.
Please advice.
Thank you
|
By Trent L. Taylor - 4/8/2008
Handle the FormClosing event instead of the FormClosed event...that way you will still have a handle.
|
By Mike Tomlin - 4/15/2008
I'm trying the VB version of this technique and I too am getting back a different handle to that which the child window was assigned on creation. I've tried changing to formclosing but the handle still changes. Any thoughts?Thanks Mike
|
By Trent L. Taylor - 4/15/2008
The form handle won't change after it has been assigned. If you are running in an MDI environment, then you can handle the OnParentChanged event and save off the handle at that point (I recommend against this). You should ALWAYS be able to reference the Me.Handle of the form and it will return the handle to which it is presently assigned, which is the only one that you should ever deal with. This is standard WinForms logic...once a handle is assigned it should never be changed unless the parent changes...that may be the ONLY time that it would change. Now it is another thing entirely if the handle has already been released. In that case you just need to handle an event further up the chain to perform your closing logic.
|
By Edhy Rijo - 4/15/2008
Just to confirm,I'm also getting back a different handle to than which the child window was assigned on creation. And also I've tried changing to formclosing but the handle still changes.
|
By Trent L. Taylor - 4/15/2008
OK...different than what? You have mentioned that you are getting back a different handle...but what are you comparing the handle to?
|
By Trent L. Taylor - 4/15/2008
Oh....nevermind, you are using that older logic on the window handles being stored off in the collection...gotcha. I will see if I can reproduce.
|
By Trent L. Taylor - 4/15/2008
Since we no longer use this logic I hadn't noticed that Vista changes the handle several times through the life of the form. So to get around this, if you still intend to use window handle, then you will need to override the OnHandleChanged method to trap that event so that you can update your collection logic.Overrides Protected Sub OnHandleChanged(...) '-- Add your logic to update the collections End Sub However, I would recommend against using the window handle at this point and add a Guid property to your BaseForm that uniquely identifies the form: Public Class MyBaseForm Inherits MicroFour.StrataFrame.UI.Windows.Forms.StandardForm Private _FormId As String = System.Guid.NewGuid().ToString() Public Readonly Property FormId As String Get Return _FormId End Get End Property End Class Then you can enumerate the Forms collection of the MDI to find your form and then activate it (this code would be referencing the MDI form):
For each f as Form In Me.MdiChildren If DirectCast(f, MyBaseForm).FormId = MyLookupId Then '-- You found the form End If Next If you take this approach you will be much safer across multiple platforms and won't be reliant upon the window handle.
|
By Edhy Rijo - 4/15/2008
Trent L. Taylor (04/15/2008)
For each f as Form In Me.MdiChildren If DirectCast(f, MyBaseForm).FormId = MyLookupId Then '-- You found the form End If Next If you take this approach you will be much safer across multiple platforms and won't be reliant upon the window handle. Trent, I hate to ask, but using the GUID logic, where is the MyLookupID value coming from?
|
By Trent L. Taylor - 4/15/2008
You would be passing it into some method. If you look further up the food-chain on this thread, you will see that they have a collection that stores off the open forms. So when the form is loaded, you would add this guid to the collection with probably a title or something else so that it could be identified in the list (if you are using the panel on the left approach).
|
By Teddy Jensen - 4/15/2008
In case anyone wants a ToolStripDropDownButton instead of a windowslist in a sidepanel or on a menu you can use this approach.On the toolstrip i have a button called tsbVinduer so my code on the main form is Private Sub tsbVinduer_DropDownOpening(ByVal sender As Object, ByVal e As System.EventArgs) Handles tsbVinduer.DropDownOpening tsbVinduer.DropDownItems.Clear() For Each f As Form In Me.MdiChildren Dim item As ToolStripMenuItem = New ToolStripMenuItem(f.Text) item.Tag = f AddHandler item.Click, AddressOf item_Click tsbVinduer.DropDownItems.Add(item) Next End Sub Private Sub item_Click(ByVal sender As Object, ByVal e As EventArgs) Dim item As ToolStripItem = TryCast(sender, ToolStripItem) If item IsNot Nothing Then Dim f As Form = TryCast(item.Tag, Form) If f IsNot Nothing Then f.Activate() End If End If End Sub It gives me this result: /Teddy
|
By Edhy Rijo - 4/16/2008
Hi Teddy,Thanks for sharing this approach, it definitely provide ideas on how to get similar results in different ways which is very good, specially when learning .NET.
|
By Paul Chase - 4/16/2008
Just to add another option to this thread you can also handle the Mdi Client Control Added and Removed on your Main MDI Form.#Region " MDI Client Handled Events"Protected Sub MDIClient_ControlAdded(ByVal sender As Object, ByVal e As Windows.Forms.ControlEventArgs)'--> Cast To My Base Class so we get custom propertiesDim loChild As Payroll.Base.WindowsForms.DevExMaintFormBase = CType(e.Control, System.Windows.Forms.Form)' do anything you need to do -add handlers update custom lists etcEnd SubProtected Sub MDIClient_ControlRemoved(ByVal sender As Object, ByVal e As Windows.Forms.ControlEventArgs)'--> Cast To Base Class so we get custom properties Dim loChild As Payroll.Base.WindowsForms.DevExMaintFormBase = CType(e.Control, System.Windows.Forms.Form) ' do anything you need to do - remove handlers update custom lists etc End Sub#End Region
|
By Keith Gordijn - 10/27/2008
Trent L. Taylor (06/14/2007)
I think that the best thing to do would be to expose the MDI client...or....if your main form just has the MDIContainer property set you can reference it directly. When the form is launched it will have a reference to the parent form in the ParentForm property which you can type and reference. You may need to make your LauncForm method public or Friend so it can be accessed though. DirectCast(Me.ParentForm, MainForm).LaunchForm(GetType(MyChildForm)) If you are using an MDIClient control and manually adding it to the form, then you can just expose it through a public property and basically do the same thing: DirectCast(Me.ParentForm, MainForm).MDIClientProperty.LaunchForm(GetType(MyChildForm))
Hi Trent,
My project follows the ideas outlined in this topic by following the StrataFlix example and I would also like to use the LaunchDialog method of the mainform from a "Setup and Configuration" form (strangely also very similar to the PracticeStudio.NET screen shot earlier in this topic) to open a maintenance form as a child form in the main mdi form.
Unfortunately my still limited knowledge of C# wont let me alter the above VB code to a C# version so any help on doing this would be great.
Cheers,
Keith
|
By Keith Gordijn - 10/27/2008
Hooray, I've had some success! Maybe I should get up at 2am more often.
So, now my question is, is this the best way of doing this?
private void tlmSecurity_ItemClicked(object sender, ThemedLinkMenuClickEventArgs e)
{
if (e.Item.Key.Equals("SecurityEditor", StringComparison.OrdinalIgnoreCase))
{
MainForm loForm;
loForm = (MainForm)this.ParentForm;
loForm.LaunchDialog(typeof(SecurityDialog));
}
}
Cheers,
Keith
|
By Trent L. Taylor - 10/28/2008
That will work fine
|
By lastcanary - 6/25/2010
Hi, I would like to use a tabbed form interface similar to the practice studio. Is this a control contained in Strataframe? Could you please help me to create a similar one?
|
By Ivan George Borges - 6/27/2010
Hiya.Nope, this is not a StrataFrame control. This is deeply and specificaly built into PracticeStudio. Iwill see if I can get some hints on how to accomplish this and pass them to you.
|
By Russell Scott Brown - 6/27/2010
Thanks. I would be interested in this too.
|