How to have a user control within MainForm call the MainForm Objects? - vb.net

I have a user control that I created with certain buttons, and I placed it within the main form, which already contains things like buttons and panels. I want to control(send messages) to these fields when I press the buttons in the user control, but I can't figure out the OOP implementation required to achieve this.
I was advised to create an Initialize(f as Mainform) in the user control code in order to keep an explicit reference to the main form, but I have not been able to control the fields of the main form.
How can this be achieved? I am using visual basic, btw.

Declare an event in the user control, and then write a handler for that event in the form.
In the control:
Event Zoomed()
In the control, to raise the event (call the handler):
RaiseEvent Zoomed()
and add the handler to the form:
Sub aview_zoomed() Handles aView.Zoomed
...
End Sub

Related

vb winform custom event handler

I am trying to add custom event handler on user control.
if I create user control on the same solution and on the same project, I can add custom event handler on the main form.
AddHandler usercontrol1.button.click, addressof button_clickHandler
when I type in usercontrol1. I can select button from the pop-up code completion
but if I create another project for user control on the same solution, say user control called uc
so after I place it on the main form with name uc1
AddHandler uc1.button.click...
when I type in uc1. I can't see button on the pop-up code completion and when I compile it if I type in
AddHandler uc1.button.click, addressof button_clickHandler2
I get compile error uc1.button is not accessible in this context because it is friend.
does user control custom event only work if the user control created on the same project?
I am thinking just to separate common user control and other common library, in one project, so it can consume by other project, instead of creating the same user control on each project.
I appreciated if you could give some pointer on how to create custom event handler or I just have create user control on the same project to get it to work.
Thank you.
While the simple solution is to just declare the child control(s) Public instead of the default Friend, good practice would be to not expose child controls of a user control anyway, no matter where it's declared. Child controls should be made Private and you should provide pass-throughs for any properties, methods or events you wish to access from the outside. For instance, declare your own ButtonClick event in the user control, handle the Click event of the Button internally and then raise your own event, e.g.
Public Event ButtonClick As EventHandler
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
OnButtonClick(EventArgs.Empty)
End Sub
Protected Overridable Sub OnButtonClick(e As EventArgs)
RaiseEvent ButtonClick(Me, e)
End Sub
Your form will then handle events of the user control and not its child controls. See here for more information about declaring and raising your own events.
BTW, a reason not to make child controls Public is that then any code that has access to the user control has access to EVERY aspect of the child controls, including being able to replace them with new controls. By making them Private and providing pass-throughs, you expose only the specific aspects of the child controls that should be accessible from the outside. It also means that your user control behaves more as an integrated unit, rather than a collection of parts. On the matter of events specifically, it also means that the user control is the sender in each event handler, rather than the individual child control.

Which events are raised when a form is showned after it was hiding (vb.net)

In my vb.net project, I navigate between forms.
I have a main form in which I can display new forms and modify some information in them.
When I closed these new forms, the main form, previously hidden by using the form.hide() method, is displayed by the form.show() method and should consider these modifications.
In order to do that I need to know which event(s) is(are) raised when a form is shown by the form.show() method.
I already try to use the form.show event but it is only raised when the form is firstly showned at the start.
When switching between .Hide() and .Show() the VisibleChanged event is raised.
If you want a more robust method (albeit more code), you can overload your form's Show method.
Public Overloads Sub Show(Optional ByVal getData As Boolean = False)
If getData Then
'get data from other form
End If
MyBase.Show()
End Sub
Your form will act normally, except in the case where you call it from your secondary forms, in which case your extra code is called, like so:
myMainForm.Show(True)
This method would be preferred in cases where you might be show/hide-ing the form, but do not want your extra code to be called every time.

Where should controller-like code be written in my vb.net app?

I am refactoring an existing project that is one large file. All form controls live in a single form, and all event handlers live in the form's code behind.
I am refactoring out a piece of the UI into a User Control. One piece of this UI is an 'Add Contract' button. This goes to my data layer, adds a row to a DataTable, and various grids in other parts of form are updated with the new row.
My question is, where should I put the event handler for the button click in the User Control?
I could leave the event handler code in the parent form, and use AddHandler in the User Control to reference the parent form's sub
I could write all the event handler code in the User Control. In this case, I'd need to access the parent form to get a reference to the data layer.
I come from a web background where I'm used to the 'controller' handling this sort of thing. I suppose my parent form is turning into a kind of controller - but is this a good practice? Should I have a separate class that coordinates user interactions with my model layer, or, once I separate out all the UI into separate user controls, will the main form be a good place for this sort of thing?
Your user control should raise events that the form hosting the user control will handle. If the user control has a reference to the form, then the user control is not reusable in any other context; in other words, the user control is tightly coupled to that one form and form X would break if it tried to use the user control.
Note: If your form is the only thing that will use the user control, then there is not much re-usability value in making it a user control at all. Kind of similar to it is not much use to make an interface if there is only one implementation of said interface. That said from an organization standpoint, user controls can be used to clean up a crowded form. It also has the benefit of allowing for the dynamic loading of content in user controls.
There is nothing wrong with your parent form becoming the controller.
Here is a quick example (in this case the clicking of the button in the user control) of how you can raise events from your user control and subscribe to the event in the form:
Public Class UserControlClass
' Define event that will be raised by user control to anyone interested in handling the event
Public Event UC_Button1Click()
' Mechanism to allow event to be raised by user control
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
RaiseEvent UC_Button1Click()
End Sub
End Class
Now in your form class, you need to add a handler for the event raised by the user control, like this:
AddHandler userControl1.UC_Button1Click, AddressOf Button1_Click
Finally, you would create the method that is referenced in the AddressOf syntax, like this:
Public Sub Button1_Click(ByVal sender As Object, ByVal args As EventArgs)
' Do something here
End Sub

Access event in a user control created in code behind?

I'm trying to create a user control in my code behind, and then respond to events in that control. Presumably because the control doesn't exist at compile time, Visual Studio can't compile the handler subroutine I created to catch my control's event. Importantly, I want to decide the type of control at runtime (which is why I'm not just hard-coding it).
[before going on, the controls work correctly, including events and event handlers when used in the 'normal' way of creating the controls in XAML. I want to create the control instances in code behind so I can avoid duplicating pages that are 99% identical]
This 'works' (but doesn't give me the flexibility I need):
Public WithEvents AnswerPanel As MyControls.ScrollerControl
... (and the initialisation in the New() sub):
AnswerPanel = New MyControls.ScrollerControl
ItemStack3.Children.Add(AnswerPanel)
AddHandler AnswerPanel.GuessMade, AddressOf CheckAnswer
... (this is the handler sub responding to a custom event in the ScrollerControl)
Public Sub CheckAnswer(answer As String) Handles AnswerPanel.GuessMade
With the code above everything works as I expect: the control is created at runtime and its event is handled correctly.
What I want to achieve is to be able to choose a different user control when I initialise my control (e.g. ScrollerControl2, ScrollerControl3, etc.) I can create the controls this way by changing the first line to:
Public WithEvents AnswerPanel As UserControl
But once that change is made I can no longer reference the custom event in my handler as (presumably) the compiler sees it as a generic UserControl, which doesn't include my custom GuessMade event. The compiler errors on the event name and tells me it doesn't exist.
I'm sure I'm doing something wrong here. I think it's a theory/concept issue rather than my code.
Am I on the right track or going about this in the wrong way?
If I am reading this right, you have a user control that fires an event and you want the parent page to catch that even? If so, you need to raise the event, which will cause the event to bubble to the the parent. IE:
Partial Class user_controls_myControl
Inherits System.Web.UI.UserControl
Public Event DataChange As EventHandler
End Class
This creates a control with a public event called DataChange. Now, if you look at the code in the parent page that instantiates the user control, you will see that it has an event called "OnDataChange". Just like an onCLick event, you can assign this a method in the parent page. Now, you just need to raise the event in the user control. This can be added in some event in the control, like a button click or radio button change event:
RaiseEvent DataChange(Me, New EventArgs)
This takes two objects, the sender and event arguments. Typically I pass ME, which is the user control. This is great because you can use reflection to get all the controls public properties. You can also use this to cast objects to your control type. I rarely pass event arguments but you certainly could.
I answered a similar question here: Handling events of usercontrols within listview
If this is not what you had in mind, let me know
EDIT: To add a user control dynamically and attach the event:
First, in the page that will be using the control, you will need to add a place holder:
<asp:PlaceHolder ID="placeholder1" runat="server"></asp:PlaceHolder>
as well as a reference to the user control at the head of the page (depending on how the page is setup, you may not need this. If you get a page directive error, remove it):
<%# Reference="" Control="~/user_controls/myControl.ascx"%>
In the parent page, you can then create a user control and add it to the place holder. You must declare the user control with events like this:
Private WithEvents myNewControl As New user_controls_myControl
then, in some method you can add it to the page like this:
Dim getPh As New PlaceHolder
'create an instance of the user control
newMyControl = CType(LoadControl("~/user_controls/myControl.ascx"), user_controls_myControl)
'get a handle on the place holder
getPh = me.placeHolder1
'add the user control to the place holder
getPh.Controls.Add(newMyControl)
Then, make sure you have event method:
Protected Sub myEvent(ByVal sender As Object, ByVal e As EventArgs) Handles myNewControl.DataChange
End Sub
So, if you added the RaiseEvent to the user control like I suggested earlier, this should work for you.
I have an answer to this now. As I suspected I was sort of thinking about the problem from the wrong angle.
In a nutshell I was trying to raise an event from my user controls, but I needed to be raising the events in the base class and calling that from my user controls.
So my base class (which my user controls inherit from), now contains the following:
Public Event GuessMade(answer As String)
Protected Sub RaiseGuessEvent(answer As String)
RaiseEvent GuessMade(answer)
End Sub
Then, in my user control(s), when I need to raise the event, I simply call the RaiseGuessEvent sub like this:
Me.RaiseGuessEvent(CurrentValue)
And additionally, I had to remove the event from my subclasses/user controls, of course.

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.