I am creating an application which requires dynamically loaded controls (to be precise buttons). These buttons are exactly the same, therefore the problem is not creating controls programatically, but making them work somehow. Each button should open a form, the form is being based on some data from the button. I'd like to have all the buttons use one event handler and open forms accordingly to the data it contains. Is there any way to do so? I don't know the types of these forms yet, therefore I can't use pre-defined "select case" or anything that would limit possibilities.
Another problem is that I would like to have some of the forms (modules) being "installed" independently. Is there any way to make that possible? I believe that could be completed using dlls, but I'm not sure. Is there any information on that, I've been looking for that for a while, but found nothing.
Regarding your first problem: You can create buttons in code; the answers to the following question should be enough to get you started (it's C#, but the principle is the same):
How to add Buttons in WinForm in Runtime?
In a nutshell:
Read your button configuration data from the database (or configuration file or whatever),
add the buttons to your user interface (see above),
use AddHandler to add an event handler to each of the buttons. For example:
AddHandler myButton.Click, Sub(sender, e)
' Do something
End Sub
(Regarding your second question: 1. It is unclear to me what you are asking and 2. you shouldn't ask two questions in the same SO question. I suggest that you open a new SO question for that and try to explain your requirement more clearly.)
Maybe i have not understand well your answer... But for your buttons:
1) Create a custom control, inheriting the Button control, and add the properties used for the creation of your forms.
2) In the Sub referenced by your eventHandler, the first argument is the control (the button) who raises the event, so you can use it's own properties to create your forms...
Adding to Heinzi's post:
Keep a list of the button names you created for use with AddHandler().
This code isn't exactly on point but it shows how the AddHandler() can be used at runtime:
' hook TextChanged/CheckedChanged for dirty logic
Dim chk As CheckBox
Dim rdo As RadioButton
For Each c As Control In FormDataControls
If c.Name.StartsWith("chk") Then
chk = c
AddHandler chk.CheckedChanged, AddressOf SetDirty
ElseIf c.Name.StartsWith("rdo") Then
rdo = c
AddHandler rdo.CheckedChanged, AddressOf SetDirty
Else
AddHandler c.TextChanged, AddressOf SetDirty
End If
Next
FormDataControls is my list of controls to target. In my case I use the Tag property to designate data controls.
Related
I am new to VB and Visual Studio and my question is maybe stupid.
I would like to make a click event for each element inside a form to do the same thing (e.g me.close()).
Is there a way to include all the elements of the form in a single event call or should I have to make a click event for every element that has the same code inside?
If your event is too big then you can write a public/private sub() and then call it from elsewhere. But if your code is only like a small event e.g. me.close() then writing at two or three places doesn't make the program too long, but if you have controls in hundreds then you can write an event like
E.g. for each control in panel/canvas etc (specify collection) and call
Me.close
Few years ago I used to program with Visual Basic 6, I was able to create objects with the same name, then differ them by the index.
for example, we can create TextBox1 and another TextBox1 but with a different index.
now this feature is not available anymore!
Currently, I'm using Visual Studio 2012.
Is there anyway to manipulate VS2012 to enable that feature again, or is there something similar to it, because it was really helpful.
The easier way to accomplish a similar thing today is to place all of these controls in a common parent control. This parent could be a groupbox, a panel, or even the form itself.
So if, say, all of the checkboxes on your form need to be indexed, with no exception, you don't have to do anything special. If just one checkbox is different, you need that checkbox to have a different parent control than your indexed checkboxes. In this case, you could layer a panel control under the checkbox group, or you can layer a panel control under the single checkbox that is different. Either will work.
Later on, you will still not be able to access these checkboxes by index, but you will be able to treat them as a collection. Here's how you can do that:
For Each box As CheckBox In Me.Controls.OfType(Of Checkbox)()
'Do something with each checkbox
Next
Or if you want to know which ones are checked:
Dim checkedBoxes As IEnumerable(Of Checkbox) = Me.Controls.OfType(Of Checkbox)().Where(Function(b) b.Checked)
If you really want an array of the checkboxes, you can use this technique to get one. Just put code like this in your form's load event:
Dim checkBoxes() CheckBox = Me.Controls.OfType(Of CheckBox)().OrderBy(Function(b) b.Name).ToArray()
It's horrible painful now.
MSDN covers this subject now: http://msdn.microsoft.com/en-us/library/aa289500%28v=vs.71%29.aspx
Long live VB6!
I'm working in a windows application. using VB.NET 1.1
I have an empty form, and I want to generate my design in load session (not in form_load event! but in my form's constructor)
So I know I must generate my components in constructor, but I don't know how to generate button events. I mean I haven't any button in design mode, and these are generating in run-time mode. so how I set button events in this session?
And if you have a better solution for run-time design generation, give it to me. thanks ;)
A few things.
You may add controls at practically any point. It can be in the constructor, the Load, in response to another event, or when a custom method is called.
You can wire up events by using AddHandler myButton.Click, AddressOf Button_Click. You'll have to define the Button_Click event handlder and it will need to have the appropriate signature, which for a button click is (sender as object, e as EventArgs).
When in doubt, temporarily add a real control to you form and go to the hidden designer code (MyForm.vDesigner.vb) and see what is generated as a sample. Copy that code and move it into the main populating code. Then delete the control.
Good luck!
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.
I have a listbox control (in a WinForms application) that lists a bunch of statistics about records selected from a database.
Is there an easy way using VB .NET to take the contents of this listbox and send it all to the printer, or at least have one of those standard windows print dialogs come up, prompting the user for which printer to send the listbox contents to? Doesn't have to be fancy or anything.
Thanks!
You can take a look here:
https://stackoverflow.com/questions/5776452/how-to-print-in-vb-net/5780300#5780300
The first answer has a solution for printing a panel in Winforms that should be applicable to your situation.
EDIT WITH UPDATE:
Take a look at this MSDN article:
http://msdn.microsoft.com/en-us/library/system.drawing.printing.printdocument.print.aspx
If you can't use the method shown in the other question, you can always handle the PrintPage event of the PrintDocument object. Particularly look at the pd_PrintPage sub in that example, as it is the sub that handles the PrintPage event. You should be able to modify that sub to use the contents of your ListBox. You will iterate through your ListBox and "draw" each string onto the ev.Graphics object. The only tricky part is deciding how much will fit on one page, but the example covers that also.