Adding a form to TabPage inside a TabControl [duplicate] - vb.net

I have a customer which as a Visual Basic Project in single instance mode with a wired presentation logic.
The main form contains a TabControl with mutliple TabPages.
If I click on TabPageA another form is shown in front of the Form and resized to have the same size as the TabPage.
If I click on TabPageB the first form is hidden and another form is displayed.
So basically for the user it looks like you have a TabControl with different TabPages which is not the case.
I tried converting the Forms to UserControls and put them inside the TabPage, but, thanks to the SingleInstance app, this would take a whole lot of refactoring. I tried it but eventually gave up because of many many runtime errors and I don't want to put any more effort in this.
My Ideam was that, at runtime, I could add the forms to the TabPages and let them act like UserControls, is this even possible?

You can turn a Form class back to a child control by setting its TopLevel property to False. It becomes essentially a UserControl with some unused overhead. Make it look similar to this:
Public Class Form1
Public Sub New()
InitializeComponent()
Dim frm As New Form2
frm.TopLevel = False
frm.FormBorderStyle = Windows.Forms.FormBorderStyle.None
frm.Visible = True
frm.Dock = DockStyle.Fill
TabPage1.Controls.Add(frm)
End Sub
End Class

Any window can be hosted in any other window (a Control is a window, technically) using SetParent.
<System.Runtime.InteropServices.DllImport("user32.dll")>
Public Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
End Function
to declare and
SetParent(FormToHost.Handle, ControlToHostForm.Handle)
to use. It may not be ideal but it's okay if you don't want to put any more effort into this, like you say. The forms will maximize and minimize properly, and will not show up in the taskbar, and will close with their containers.

you can use panels. in each tab different panel or panels must be show an the other or others must be hide.

Related

Keep track of Window being Last Focus

The VB.Net program I am creating dynamically created Panels within a TableLayoutPanel and adds form elements to them. I need to keep track of what the last of these Panels to have focus was, and am hitting a bit of a brick wall.
I have tried creating an event class for when the Panel has focus:
Private Sub Self_GotFocus(ByVal sender As Object, ByVal e As EventArgs) Handles Me.GotFocus
GlobalController.Focus_Target = Me.Name
End Sub
The classes for each Panel Inherit from Windows.Forms.FlowLayoutPanel, which I why I have the call being Me.GotFocus. Additionally, the GlobalController class is just a class meant to hold global variables for the program.
Now the issue I am having, is that this event only seems to trigger when I actually am deleting the panel. When the panel is created, if I click on it, or any of it's form elements, the event never gets triggered (I debugged the program with a breakpoint).
I can't exactly figure out why this only triggers when I go to delete the panel, and not at any other time. Is there another event I should be using instead of GotFocus?
Use .Enter event in your panel since GotFocus is related only to focused control (not it's parent), mostly when UICues is set.
See MSDN GotFocus

Sharing Controls from multiple forms/classes

I'm currently stuck in how to share controls between two forms.
This is what i want to do:
- I have several forms that have their own function.
- Now i want to bring them all to gather on one mainform.
Normally i do this by creating the following code:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim f As New Form2
GroupBox1.Controls.Add(f.Get_Groupbox_controls)
End Sub
End Class
This add all the control containing in Form2.Groupbox1 and adds it to Form1.Groupbox1.
Normally this works just fine for me.
Where "Get_Groupbox_controls" is a function that returns Form2.Groupbox1
Or if this doesn't works i display the entire form2 over form1 with a transparancykey. (this isn't a need solution, you have to do a lot of location calculating, but it works)
However now i got a form that has a lot going on. For the mainform i only want to display one Container(groupbox) but when the user clicks "More setting.." then it has to show the entire form with all the control on it.
The problem is when i use the container.controls.add() function i get an exception "Invoke or BeginInvoke cannot be called on a control until the window handle has been created "
The Error is logical because the entire form isn't made yet. But in order for the form to work properly it has to update the "hidden" UI controls (labels/buttons/etc)
So the main question is, how can i "port" a selection of controls from Form1 to form2 and keep all the handlers etc.. on Form1
If you have two forms where you want to place identical looking/functioning GroupBox sections, you may want to consider creating a custom user control that contains the shared functionality and can be placed in each form. User controls can even be added to a form through the form designer in Visual Studio.

vb.net using SetParent API over IsMDIContainer?

I'm working with a set of custom controls (including a custom form), I have repainted the custom form to give it a metro style look and basically recreated the title bar of the form. Setting this form to be an MDI container causes the whole form to be repainted grey regardless of anything dictated in the OnPaint handler for the form.
I want to create a multi form application where all of the forms that are not the main form, appear inside the main form (the idea of MDI windows). I have also seen a SetParent API that achieves a similar effect without modifying its visuals, however, I have used this before to tie a cmd window to a form and it is not always reliable.
Would it be more efficient to use the MDI feature inside Winforms (if so, how do i overcome the complete recolour issue) or dump MDI and use the SetParent API to modify the child windows' parent?
EDIT: I have decided to go for using the SetParent API, it works everytime as opposed to my previous experiences with the console window. However, I need to create the window before I can set the parent and sometimes the user can see the screen flash briefly before it gets 'hooked' inside my main form. Is there a way to 'hook' it without it being visible to the user?
With MDI Parent Form if your issue is the background, then this is all you have to do, Set the IsMDIContainer property of the form to true, and then loop through each control on MDI Form to let them know this is the MDI Background, you can put this code in the form loading event,
Private Sub FormMDI_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each ctl As Control In Me.Controls
If TypeOf ctl Is MdiClient Then
ctl.BackColor = Me.BackColor
End If
Next ctl
End Sub
It might appear gray when program is not running, but it will show your desired background once the program runs

Inherited panel is making controls disappear randomly

I have a class written that inherits a panel, and enables double buffering to it:
Public Class dblBufferPanel
Inherits Panel
Public Sub New()
'inherit a panel and add double buff to reduce flicker
'this will be used wherever a panel with gradient or bg img is needed
Me.DoubleBuffered = True
Me.ResizeRedraw = True
End Sub
End Class
The problem that I have been facing is that randomly while coding, the controls set within the various panels seem to "vanish" off the panel. Basically, the panel looks "empty" and there is no way to select the control from form design. I can however select them in the properties panel, but altering properties of these controls does nothing. The only solution I have found is that I close VS2010 and restart. Then, if I did not compile after noticing the controls "vanishing", they reappear upon opening the solution.
This seems to happen with any control, comboboxes, labels, listview, etc. What would be causing this?

VB.NET: How can you activate the childform when only the control inside is clicked?

*edit: OK, so this is my real problem, below scenario happens only when the form is MDIChild.. thanks for anyone that could provide me with the code
I have a form with labels, panels, buttons etc. Where I'm having problem is, while form2 is my active window/form and I clicked on a control inside form1, the form1 does not activate itself. What I would like to happen is for form1 to activate even when it's not the form I clicked, only the control inside it (any control)..
I'm thinking that if I clicked a control on the form, there's an event fired on the form. If I could only know of that certain event, that would help - maybe (coz I could just add Me.activate on that event if it exists). I've tried searching for series of events when a control (ex. label) is clicked but to no avail. I hope that someone could help me with this one.
Thanks in advance.
*edit
i will just try to make my question more understandable..
How can I activate the form when only the control is clicked (say, label or textbox)? My forms does not activate or focused when I click inside it except the form itself..
I can do this on one control..
Private Sub Label1_Click - Handles Label1.Click
Me.Activate()
End Sub
But what if I have 20 controls (labels, buttons, textbox, combobox, etc)? See? =)
EDIT: this answer does not apply to MDI applications.
I think what you really want to know is which one of your forms is currently the foreground window (if any). The first thing you need to understand is that a form instance lives inside a window, but the window's behavior is controlled somewhere higher up. Similar to how a form instance is identified by a variable pointing to the instance, a window can be identified by what's known as a window handle.
Knowing this, the proper way to find out whether a form is the "active" form is to:
find out the window handles of the windows containing our instances of Form1 and Form2
find out the window handle of the foreground window (which can be any window)
compare the value found in step 2 to all of the values found in step 1
Perhaps you'd then like to fire an event if the foreground window changes, but I'll leave the actual implementation up to you. There are probably several ways to perform step 1 and 2, but I can't give any solutions off the top of my head. Hopefuly I've put you back on the right track.
EDIT
Alternatively, you can use the form's Containsfocus property. If its value is True, you can safely assume that your form is the foreground window. I didn't find out about this property until after I wrote my own implementation, which I'll show you anyway:
One module containing only a windows API call
Friend Module NativeMethods
Friend Declare Function GetForegroundWindow Lib "user32.dll" () As IntPtr
End Module
Calling this method will return the window handle of the foreground window (if any).
One module containing the extension method for the Form class
Imports System.Runtime.CompilerServices
Public Module FormExtensions
<Extension>
Public Function IsForeground(f As Form) As Boolean
Return (f.Handle = NativeMethods.GetForegroundWindow)
End Function
End Module
Calling this method returns whether the specified form f has the same window handle as the foreground window.
Usage example
You could use a Timer that periodically checks whether a form is the foreground window.
Public Class Form1
Private WithEvents timer As New Timer With {.Enabled = True}
Private Sub timer_Tick(sender As Object, e As EventArgs) Handles timer.Tick
If Me.IsForeground() Then
Console.WriteLine("this instance of Form1 is the foreground window")
End If
End Sub
End Class
Like I said before, you can use Me.ContainsFocus instead of my extension method and it will work just fine.
In non-MDI forms, the form is automatically activated when you click any control inside it.