Change order in which a mouse event is handled - vb.net

I hope I can make it clear what my problem is. I have made my own Chart control
Public Class MyChart
Inherits Chart
[...]
End Class
In this class I handle the MouseDown event of the chart and do stuff like zooming, dragging markers and so on.
In the project I am using the chart I also handle the MouseDown event to do some more specific stuff. Now there is this problem:
In the MouseDown event handler in the MyChart class I use the middle mouse button to drag the chart.
However in the project MouseDown event handler I check if the user hit a specific object and want to let him drag this object also with the middle mouse button. The problem is, that the handler in MyChart is executed first so I can't check if the user hit the object (and therefore initiate the dragging of this object).
What I need is that the event handler in the project is executed first and after this the one in MyChart.
To hopefully make it more clear:
(Dummy Code)
Public Class SomeProject
WithEvents Chart as MyChart
Public Sub Chart_MouseDown(sender as object, e as MouseEventArgs) Handles Chart.MouseDown
'This is executed second, but should be executed first.
End Sub
End Class
Public Class MyChart
Inherits Chart
Public Sub MyChart_MouseDown(sender as object, e as MouseEventArgs) Handles Me.MouseDown
'This is executed first, but should be executed second.
End Sub
End Class
Is there any way I can do this?

Try creating your own event:
Public Class MyChart
Inherits Chart
Public Event ChartMouseDown(sender As Object, e As MouseEventArgs)
Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
RaiseEvent ChartMouseDown(Me, e)
MyBase.OnMouseDown(e)
// your second code here...
End Sub
End Class
Then your project code would look like this:
Public Class SomeProject
WithEvents Chart as MyChart
Public Sub Chart_ChartMouseDown(sender as object, e as MouseEventArgs) _
Handles Chart.ChartMouseDown
// your first code here...
End Sub
End Class

Related

Stop raising Click Event in a specific area of a UserControl

Problem
A UserControl raises by default the Click Event when a mouse button is pressed. Is there a way to prevent the event from raising when clicking on a specific area of the UserControl?
Code
Suppose that we have this specific UserControl. There is a red rectangle: I want to raise the click event only in the white area.
I've tried to override the OnMouseClick sub:
Public Class UserControl1
Dim noClickArea As New Rectangle(100, 100, 50, 50)
'Draw the red rectangle
Private Sub UserControl1_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint
Using gr As Graphics = Me.CreateGraphics
gr.Clear(Color.White)
gr.FillRectangle(Brushes.Red, noClickArea)
End Using
End Sub
'This aims to prevent the mouseClick event on noClickArea
Protected Overrides Sub OnMouseClick(e As MouseEventArgs)
If Not noClickArea.Contains(e.Location) Then
MyBase.OnMouseClick(e)
End If
End Sub
End Class
Here is a test Form that use this UserControl and show a message box on click:
Public Class Form1
Private Sub UserControl11_Click(sender As Object, e As EventArgs) Handles UserControl11.Click
MessageBox.Show("Click")
End Sub
End Class
Result
Overriding OnMouseClick don't produce the expected result:
How can I achieve the result I want?
You're overriding OnMouseClick, but you have subscribed to the Click event in your Form.
OnMouseClick is called after OnClick, so you suppress MouseClick, but the Click event has already been raised.
Override OnClick instead. Or subscribe to the MouseClick event in your Form.
Note that EventArgs of the OnClick method is actually a MouseEventArgs object, so you can cast EventArgs to MouseEventArgs:
Protected Overrides Sub OnClick(e As EventArgs)
If noClickArea.Contains(CType(e, MouseEventArgs).Location) Then Return
MyBase.OnClick(e)
End Sub
Then, override OnPaint instead of subscribing to the Paint event in your UserControl.
Also, do not use Me.CreateGraphics in that event or method override, it doesn't make sense.
Use the Graphics object provided by the PaintVentArgs:
Protected Overrides Sub OnPaint(e As PaintEventArgs)
e.Graphics.Clear(Color.White)
e.Graphics.FillRectangle(Brushes.Red, noClickArea)
MyBase.OnPaint(e)
End Sub
As a suggestion (since I don't know what is the real use case), if you want to fill the whole Control's background with a color, set the Background Color of the Control in the Designer instead of using Graphics.Clear() in that context.

Unable to handle event in another class

I am kinda new to visual basic and was wondering if it is possible to trigger events in a class, based on action with in form.
So the following is my problem:
I have a form called Main, with a picture box called picPID
And a class called add_new
What I want to do is:
when the right mousebutton is clicked, the code for the event handling is placed within the class called add_new
I thought i could just declare it in the following way:
Sub meMouseDown(sender As Object, e As MouseEventArgs) Handles Main.picPID.MouseDown
But I get an error saying i have to declare it withEvents, I tried to declare the picturebox as:
Public shared withEvents as picturebox
but it dident help, any sugestions? It is not a problem having the code within the Main form, but it would result in a lot of code, so I was hoping to split it up.
So you have the class with an eventhandler:
Public Class add_new
Public Sub PictureBoxEventHandler(sender As Object, e As MouseEventArgs)
'Your Implementation
End Sub
End Class
Then you need an instance of this class within the form containing the picturebox:
Public Class Form1
Private add_New_Command As New add_new ' hold a reference to the command
'constructor
Public Sub New()
InitializeComponent()
' and add the handler to the event of the picture box ... hook it up
AddHandler PictureBox1.MouseDown, AddressOf add_New_Command.PictureBoxEventHandler
End Sub
End Class

In a VB.NET Windows Forms application: How to preserve MVC when handling Events?

I'm relatively new to Windows Forms development and my first real application has reached a point where a lot of code starts to build up in my main Form file, so I decided to restructure my project using the MVC pattern.
One major problem I have is dealing with the different control events of the form. I have several buttons, textfields, comboboxes and also a tabcontroll element which again contains different input elements and so far, every procedure for handling clicks, updates and other changes is defined in my main class.
For example:
Private Sub btnOk_Click(sender As Object, e As EventArgs) Handles btnOk.Click
some code...
End Sub
So my question is: what would be the best way to handle these events outside of my main form? I'm more familiar with building GUIs in Java where you can use ActionListeners to achieve this but I have found nothing similar for my work with Windows Forms.
To subscribe to a Control event outside of your main form class, make your control public, so you can access from another class). This can be done using the Modifier property at design-time. Then, use the AddHandler keyword to subscribe to any event programmatically.
After researching a bit more, I found that there is probably not THE correct answer to this problem but I found 2 approaches which provide a solution in the way I was looking for. In both cases, I use a controller class which is responsible for handling any user interaction from my main form.
The first approach makes use of what DmitryBabich suggested, adding a handler to the object and referencing it to a method of my controller class:
in Form1:
Dim ctrl as new Controller(Me)
AddHandler Button1.Click, AddressOf ctrl.doSomething
Controller class:
Public Class Controller
Private myForm As Form1
Public Sub New(ByVal f As Form1)
myForm = f
End Sub
Public Sub doSomething(sender As Object, e As EventArgs)
MsgBox("Button clicked.")
End Sub
End Class
For an example this simple it is not necessary to pass an instance of Form1 over to the controller but if for example I'd like to access the values of other control elements as well, I can address them by using this instance of Form1.
For example:
Public Sub doSomething(sender As Object, e As EventArgs)
MsgBox("You clicked the button, by the way: The value of TextField1 is " & myForm.TextField1.text)
End Sub
The other approach is almost identical except that here the controller knows all the relevant user control objects of the form and can handle their events directly, meaning that in the main form I have to do nothing more than create an instance of the controller. In the controller however, I have to assign every user control I want to access to its own variable as soon as the main form is loaded:
in Form1:
Dim ctrl as new Controller(Me)
Controller class:
Public Class Controller
WithEvents myForm As Form1
WithEvents button1 As Button
WithEvents button2 As Button
Public Sub New(ByVal f As Form1)
myForm = f
End Sub
Public Sub formLoad() Handles myForm.Load
button1 = myForm.Button1
button2 = myForm.Button2
End Sub
Private Sub b1Click() Handles button1.Click
MsgBox("You clicked button1!")
End Sub
Private Sub b2Click() Handles button2.Click
MsgBox("Button #2 was clicked!")
End Sub
End Class

Passing event to the parent form

I have a little problem here. I'm trying to transfer/pass/raise the events of an owned form to his parent. Lets look at my example:
Lets say i have a form that initialize a CustomPanel (simply a class that inherits from System.Windows.Forms.Panel). It also have an event handler (it could be an other event, not necessarily a click event):
Public Sub New()
Me.Size = New Size(1000,1000)
Dim pnl1 As New CustomPanel()
pnl1.Location = New Point(0,0)
pnl1.size = New Size(100,100)
Me.Controls.Add(pnl1)
End Sub
Private Sub form1_Click(sender As Object, e As EventArgs) Handles Me.Click
MsgBox("I got it!")
End Sub
I did something similar and when I clicked on the CustomPanel (pnl1) the parent container (form1) did not receive a click event ... which is understandable. I tried to look in the properties of the CustomPanel (pnl1) if i could find something interesting like "click through" or "raise event to parent" (I was desperate here) but without success. I said alright, I will handle the events that I need to pass to parent in the CustomPanel class but I cant find a solution here neither:
Imports System.Windows.Forms
Public Class CustomPanel
Inherits Panel
Public Sub New()
End Sub
Private Sub CustomPanel_Click(sender As Object, e As EventArgs) Handles Me.Click
'What to put here?
'Me.Parent.?
End Sub
End Class
I just want to know if its possible to throw/raise/pass events to the parent. One thing is sure, its that i shouldn't have to and i cannot add anything else to the parent form. The reason is simple, i could have over 100 controls in this parent form and they could be added dynamically. And on top of that, these controls could also have their own controls inside! So i could have something like:
pnl99 call parent click -> pnl98 call parent click -> ... until the parent of the control really handle the click event ... -> form1 perform click event
Maybe its hard to understand but if you can help me I would appreciate.
Using a custom event, that the form owning the panel subscribes to. Raise Event
Public Sub New()
Me.Size = New Size(1000,1000)
Dim pnl1 As New CustomPanel()
pnl1.Location = New Point(0,0)
pnl1.size = New Size(100,100)
Addhandler pnl1.MyClickEvent, AddressOf pl_Click
Me.Controls.Add(pnl1)
End Sub
Private Sub pl_Click()
MsgBox("I got it!")
End Sub
Custom panel:
Public Class CustomPanel
Inherits Panel
Public Event MyClickEvent
Private Sub CustomPanel_Click(sender As Object, e As EventArgs) Handles Me.Click
RaiseEvent MyClickEvent()
End Sub
End Class
On the child form
Imports System.Windows.Forms
Imports STAS_PLC_Link_Lib
Public Class ChildForm
Public Event MyClick()
'.....rest of code
On the parent form
Public Class ParentForm
Private Sub GetSomeClick() Handles ChildFor.MyClick
System.Console.WriteLine("test")
End Sub
end Class

Handling Event - form/control not updating?

First off, I do not work with winform development full time so don't bash me too bad...
As the title somewhat depicts, I am having an issue refreshing the controls on a form after an event has been raised and captured.
On "Form1" I have a Dockpanel and am creating two new forms as shown below:
Public Sub New()
InitializeComponent()
dpGraph.DockLeftPortion = 225
dpGraph.BringToFront()
Dim frmT As frmGraphTools = New frmGraphTools()
Dim frmG As frmGraph = New frmGraph()
AddHandler frmT.UpdateGraph, AddressOf frmG.RefreshGraph
frmT.ShowHint = DockState.DockLeft
frmT.CloseButtonVisible = False
frmT.Show(dpGraph)
frmG.ShowHint = DockState.Document
frmG.CloseButtonVisible = False
frmG.Show(dpGraph)
End Sub
Within the frmGraphTools class I have the following delegate, event, and button click event defined:
Public Delegate Sub GraphValueChanged(ByVal datum As Date)
Public Event UpdateGraph As GraphValueChanged
Private Sub btnSaveMach_Click(sender As Object, e As EventArgs) Handles btnSaveMach.Click
RaiseEvent UpdateGraph(dtpJobDate.Value.ToString())
End Sub
Within the frmGraph class I have the following Sub defined:
Public Sub RefreshGraph(ByVal datum As Date)
CreateGraph(datum)
frmGraphBack.dpGraph.Refresh()
End Sub
I have a ZedGraph control on the frmGraph form that is supposed to be refreshed/redrawn upon the button click as defined on frmGraphTools. Everything seems to working, the RefreshGraph Sub within frmGraph is being executed and new data is pushed into the ZedGraph control however, the control never updates. What must be done to get the frmGraph form or the ZedGraph control to update/refresh/redraw properly?
Pass the reference to RefreshGroup method from the correct instance of frmGraph
AddHandler frmT.UpdateGraph, AddressOf frmG.RefreshGraph
also this call should be flagged by the compiler because you are passing a string instead of a Date
RaiseEvent UpdateGraph(dtpJobDate.Value.ToString())
probably you have Option Strict Off