Access event in a user control created in code behind? - vb.net

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.

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.

How to have a user control within MainForm call the MainForm Objects?

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

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

vb.net winform from a usercontrol call a function on the parent form

I don't know how to put it right, but I have a vb.net winform app in which I want to use a customcontrol so I can re-use the logic on multiple forms. I know how to set values in this control from the parent (using properties in the control). But now I want to call a specifiek function on the parent form. Im my case LoadData() which is a procedure of the parentform. How can I do this?
I know I can reference the parent form by using Me.ParentForm in the usercontrol. But I cannot call the LoadData() procedure in the parentform.
Any help? This is a winforms app, not a ASP.NET app.
T.I.A.
[Edit]
I could solve my problem using this example found right here. This is working fine
First, a UserControl is for reusing GUI logic, so I hope that is what you meant. If you are trying to reuse non-GUI logic you might want to create some stand-alone classes for that.
Second, it is generally bad design to call back up to the parent form in the way you describe because it makes the UserControl less reusable and it creates an overly tight binding between the two. You should, if at all possible, push the data down into the UserControl instead.
If you can find no way for the Form to push the data down (perhaps because it is based upon a UI interaction within the UserControl), you have a couple of other options. The first is to wrap up the data-loading behavior into an object that can be passed to the UserControl during initialization, and the the UserControl can access the LoadData method on it as needed. Another approach is to have the UserControl define a set of Events that can be used to request external data from the form. I like to use the "Query" prefix on these kinds of events. So when a fetch button is tapped on your UserControl, it raises the "QueryData" event, and the form that is handling that event responds by populating a data container of some sort that is part of the custom EventArgs.
Either of these can be expanded upon if you need more assistance.
Upon re-reading the question, I it looks like perhaps my approach is over kill. I was under the impression that the LoadData was a method in the Form that loaded data into the UserControl. If it is just a simple call then focus on the event portion of my answer and ignore the data container portion.
I would add an event to your control and handle it on the form the control is part of.
In your control, put something like this:
Public Event LoadData(ByVal sender As Object, ByVal e As System.EventArgs)
And in your form, you can have something like this:
Private Sub UserControl1_LoadData(sender As Object, e As EventArgs) Handles UserControl1.LoadData
'...Your code here
End Sub

Should I rename my button event handler name?

When using Visual Studio (though ideally this can apply to the generic case) and double click on a button I've created, the event handler code that is auto generated uses the following signature:
Protected Sub btnSubmitRequest_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSubmitRequest.Click
End Sub
Is it best practice to leave the name of this method as is, or should it be renamed to something a little more descriptive, such as SubmitNewEmployeeRequest?
Create another method called SubmitNewEmployeeRequest. In btnSubmitRequest_Click, call SubmitNewEmployeeRequest. That is the most logical separation of duties.
Also, if you change the name of the button in the IDE before creating the handlers, the handlers get better default names. The name of your button would currently be btnSubmitRequest, you could change it to be more specific as btnSubmitNewEmployeeRequest and then generate the handler.
You should name your controls, and keep the naming consistent between the control and handlers.
I would generally name them within the context of usage, that is if your in the
Employee Request form, then the button need only be named SubmitRequest.
Do Stuff to Directory components form, then the button should probably be more descriptive like SubmitNewEmployeeRequest.
Well, personally I leave it so that I can see quickly that it is an event handler, specifically a click event handler. However I would be inclined to just have one line of code there that calls (in this case, your) SubmitNewEmployeeRequest because this may also be called from some context menu as well, or fired in response to some other event.