I have a base class that checks if user has access to the derived form. I need to block/remove invoke/unsubscribe to all methods/events in derived class from base class, if user doesn't have access to the form.
I tried many things but couldn't find a way to handle this issue.
My approach is close form in base form load event, but if data loading in derived form Load Event, it also raises and closes after data load. This can be leak of some security problems.
I can easly solve this issue by adding some codes to derived form but i have about 450~500 about derived forms.
Or i can define a function to show form, that checks user role in form before showing but because of many derived forms, i can't change.
Public Class AuthBaseForm
Inherits DevExpress.XtraEditors.XtraForm
Property IsAuthorized As Boolean = False
Private Sub InitializeComponent()
Me.SuspendLayout()
'
'StartUpForm
'
Me.ClientSize = New System.Drawing.Size(825, 432)
Me.Name = "AuthBaseForm"
Me.AutoScaleMode = Windows.Forms.AutoScaleMode.Dpi
Me.ResumeLayout(False)
End Sub
Public Sub New()
MyBase.New()
' Here checks if user can access and visible this form
' function return true/false
IsAuthorized = GetUserRoleInForm(Me)
End Sub
Private Sub Form_Load(sender As Object, e As EventArgs) Handles Me.Load
If Not IsAuthorized Then
'Remove Here Derived Class Load Event
'Here, i need to find Derived class load event, and disable to invoke that method
MsgBox("You do not have permissions to show this form!", vbExclamation + vbOKOnly)
Me.Close()
Return
End If
End Sub
End Class
Public Class DetailForm
Inherits AuthBaseForm
Public Sub New()
' This call is required by the designer.
InitializeComponent()
End Sub
Private Sub DetailForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' this generated to test form role auth
MsgBox("If also my base class not authorized, this event is raising :(", vbInformation)
Me.KeyPreview = True
' Fetch data to show
Me.WaitHelper1.SetListingFunction(Sub() Me.GetData())
' Set auto filter rows
rh.devexFunc.SetGridViewFilterTypes(Me.viewSiparisler)
' Set column bolds
rh.devexFunc.SetGridViewFontBold(Me.viewSiparisler, "UNVAN")
End Sub
End Class
I've tried some works but still haven't get succeed.
By Hans Passants' solution, i have revised base onLoad method as below and worked perfectly.
Protected Overrides Sub OnLoad(e As EventArgs)
If Me.IsAuthorized Then
MyBase.OnLoad(e)
Else
Me.Close()
rh.ExclamationMsgBox("You are not allowed to show this form!")
End If
End Sub
Related
I have a usercontrol form named "ucSETTINGS", where there is a textbox and once the button was clicked, the text inside the textbox will be added to the combobox from another usercontrol form name "ucITEMS"
I tried this code but it's not working
(cboCategory is the name of the combobox from ucITEMS, txtNAME is the textbox from ucSETTINGS)
Private Sub btnSAVE_Click(sender As Object, e As EventArgs) Handles btnSAVE.Click
Dim category As New ucITEMS()
category.cboCATEGORY.Items.Add(txtNAME.Text)
End Sub
Can someone help me?
In this sort of situation, the user controls don't know about each other by default and it should stay that way. The source UC just exposes an interface and lets whomever is watching use that as it sees fit. That means raising an event when something happens and exposing required data via properties, e.g.
Public Class SourceControl
Public ReadOnly Property TextBox1Text As String
Get
Return TextBox1.Text
End Get
End Property
Public Event Button1Click As EventHandler
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
OnButton1Click(EventArgs.Empty)
End Sub
Protected Overridable Sub OnButton1Click(e As EventArgs)
RaiseEvent Button1Click(Me, e)
End Sub
End Class
The Text of the TextBox is exposed via a property and, when the user clicks the Button, the UC raises an event.
The destination UC provides an interface for new items to be provided but it adds them to its own ComboBox, e.g.
Public Class DestinationControl
Public Sub AddItemToComboBox1(item As Object)
ComboBox1.Items.Add(item)
End Sub
End Class
The form then plays go-between, handling the event, getting the property and calling the method:
Private Sub SourceControl1_Button1Click(sender As Object, e As EventArgs) Handles SourceControl1.Button1Click
DestinationControl1.AddItemToComboBox1(SourceControl1.TextBox1Text)
End Sub
Obviously you would use something more specific and appropriate than my generic naming.
I have a vb.net application which contains two forms. One is called "MapComponentForm" and another called "ComponentPropertiesForm". In the MapComponentForm I have defined an event which I want fired when the OK button is clicked. If the ComponentPropertiesForm is open, I want it to "hear" this event and act accordingly. Stepping through the code the event seems to fire as expected but the ComponentPropertiesForm seems to be oblivious to this. I've attached the code from the two forms after stripping out the non relevant code in hopes that someone can tell me why my event goes unheeded. I used the information here:
https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/events/walkthrough-handling-events
in constructing my own code.
Thanks for any suggestions.
Public Class MapComponentForm
Public Event PartMapped(ByRef status As Boolean)
Public Sub New(shape As Visio.Shape)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
_shape = shape
End Sub
Private Sub OkButton_Click(sender As Object, e As EventArgs) Handles OkButton.Click
'If the component properties window is open, refresh it
If Application.OpenForms().OfType(Of ComponentPropertiesForm).Any Then
RaiseEvent PartMapped(True)
End If
end sub
end class
Public Class ComponentPropertiesForm
Private WithEvents mPartMap As MapComponentForm
Private Sub ComponentPropertiesForm_Load(sender As Object, e As EventArgs) Handles Me.Load
mPartMap = New MapComponentForm(Nothing)
End Sub
Private Sub mPartMap_PartMapped(ByRef status As Boolean) Handles mPartMap.PartMapped
If status = True Then
MsgBox("something got mapped")
End If
End Sub
end class
I'm creating a decision interface for clinical support with numerous amounts of combo boxes with boolean values 'Yes|No". However I want it so if the user choses either yes or no, a button can be clicked at the bottom and then another windows form appears and says whether they have cancer or not.
For example, if the user clicks 'yes' in the comboBox and then clicks the 'submit' button, another form will appear and the text box will say whether they have cancer or not. Would anyone be able to supply an example of how this would work? I have the form with the combo boxes, a button that links to another form, and a textbox inside the second form....but I can't get the information between the two forms.
The code I have at the moment is
Private Sub submit_Click(sender As Object, e As EventArgs) Handles submit.Click
If (RectalBleeding.SelectedItem = "Yes") Then Outcome.OutcomeBox.Text = "you have cancer" End If Outcome.Show()
End Sub
Particular combo box im trying to link is called 'RectalBleeding'. The button on the decision interface form is called 'submit' the second form is called 'outcome'. The box inside outcome is called 'outcomeBox' I want it so that if 'Yes' was chosen in the comboBox, the user clicks 'submit' second form appears and in the text box it says "you have cancer"
Thanks!
You can use public properties and constructors to pass values between two forms. Below is some code that uses these tools for your purpose.
Here is the code for the main form:
Public Class Form1
Private frm As Outcome
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddDecision()
End Sub
Private Sub AddDecision()
RectalBleeding.Items.Add("Yes")
RectalBleeding.Items.Add("No")
End Sub
Private Sub Submit_Click(sender As Object, e As EventArgs) Handles Submit.Click
If RectalBleeding.Text = "Yes" Then
frm = New Outcome("You have cancer")
Else
frm = New Outcome("You don't have cancer")
End If
frm.Show()
End Sub
End Class
and here for the outcome form
Public Class Outcome
Private _Decision As String
Public Property Decision() As String
Get
Return _Decision
End Get
Set(ByVal value As String)
_Decision = value
End Set
End Property
Private Sub Outcome_Load(sender As Object, e As EventArgs) Handles MyBase.Load
FillTextBox()
End Sub
Public Sub New(ByVal results As String)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.Decision = results
End Sub
Private Sub FillTextBox()
outcomeBox.Text = Me.Decision
End Sub
End Class
On every DataGridView1_SelectionChanged event I need to run a Private Sub OnSelectionChanged() of the form that is loaded into Panel1 (see the image http://tinypic.com/r/2nu2wx/8).
Every form that can be loaded into Panel1 has the same Private Sub OnSelectionChanged() that initiates all the necessary calculations. For instance, I can load a form that calculates temperatures or I can load a form that calculates voltages. If different element is selected in the main form’s DataGridView1, either temperatures or voltages should be recalculated.
The problem is - there are many forms that can be loaded into Panel1, and I’m struggling to raise an event that would fire only once and would run the necessary Sub only in the loaded form.
Currently I’m using Shared Event:
'Main form (Form1).
Shared Event event_UpdateLoadedForm(ByVal frm_name As String)
'This is how I load forms into a panel (in this case frm_SCT).
Private Sub mnu_SCT_Click(sender As Object, e As EventArgs) Handles mnu_SCT.Click
frm_SCT.TopLevel = False
frm_SCT.Dock = DockStyle.Fill
Panel1.Controls.Add(frm_SCT)
frm_SCT.Show()
Var._loadedForm = frm_SCT.Name
RaiseEvent event_UpdateLoadedForm(Var._loadedForm)
End Sub
‘Form that is loaded into panel (Form2 or Form3 or Form4...).
Private WithEvents myEvent As New Form1
Private Sub OnEvent(ByVal frm_name As String) Handles myEvent.event_UpdateLoadedForm
‘Avoid executing code for the form that is not loaded.
If frm_name <> Me.Name Then Exit Sub
End Sub
This approach is working but I’m sure it can be done way better (I'd be thankful for any suggestions). I have tried to raise an event in the main form like this:
Public Event MyEvent As EventHandler
Protected Overridable Sub OnChange(e As EventArgs)
RaiseEvent MyEvent(Me, e)
End Sub
Private Sub DataGridView1_SelectionChanged(sender As Object, e As EventArgs) _
Handles DataGridView1.SelectionChanged
OnChange(EventArgs.Empty)
End Sub
but I don't know to subscribe to it in the loaded form.
Thank you.
Taking into account Hans Passant’s comments as well as code he posted in related thread I achieved what I wanted (see the code below).
Public Interface IOnEvent
Sub OnSelectionChange()
End Interface
Public Class Form1
' ???
Private myInterface As IOnEvent = Nothing
' Create and load form.
Private Sub DisplayForm(frm_Name As String)
' Exit if the form is already displayed.
If Panel1.Controls.Count > 0 AndAlso _
Panel1.Controls(0).GetType().Name = frm_Name Then Exit Sub
' Dispose previous form.
Do While Panel1.Controls.Count > 0
Panel1.Controls(0).Dispose()
Loop
' Create form by its full name.
Dim T As Type = Type.GetType("Namespace." & frm_Name)
Dim frm As Form = CType(Activator.CreateInstance(T), Form)
' Load form into the panel.
frm.TopLevel = False
frm.Visible = True
frm.Dock = DockStyle.Fill
Panel1.Controls.Add(frm)
' ???
myInterface = DirectCast(frm, IOnEvent)
End Sub
Private Sub DataGridView1_SelectionChanged(sender As Object, e As EventArgs) _
Handles DataGridView1.SelectionChanged
' Avoid error if the panel is empty.
If myInterface Is Nothing Then Return
' Run subroutine in the loaded form.
myInterface.OnSelectionChange()
End Sub
End Class
One last thing – it would be great if someone could take a quick look at the code (it works) and confirm that it is ok, especially the lines marked with “???” (I don’t understand them yet).
I am experiencing a strange behaviour when using RightToLayout layout:
My form automatically closes.
I have created a simple project to reproduce the problem:
Create a new VB.NET project in VS2012 and add forms "Form1" and "Form2" to it.
Set "Form1" to be the start form.
Then add the following code to "Form1":
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Me.Hide()
Dim f As New Form2
f.ShowDialog()
MessageBox.Show("After dialog closed.")
modControls.setFormRTL(Me) 'This line causes the Form2 to automatically close. Why??? This line should only be processed AFTER the dialog has been shown and closed
End Sub
End Class
Add the following code to "Form2":
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles Me.Load
modControls.setFormRTL(Me)
End Sub
End Class
Add a module with the name "modControls" to the project.
Add the following code to it:
Module modControls
Public Sub setFormRTL(ByVal uForm As Form)
uForm.RightToLeft = RightToLeft.Yes
End Sub
End Module
Without the setFormRTL, my project works perfectly fine, but with it, "Form2" automatically closes down. You can see this because the messagebox is shown.
When I remove the line
modControls.setFormRTL(Me)
from Form1 load, it works fine again.
Yes, I really mean from "Form1", not from "Form2"!!!
Now this is really strange because it should not matter at all because this line is not processed before the dialog is closed.
I hope somebody understands what I mean.
Can anybody shed some light on what might be happening here?
Yes, you'll get unexpected behavior if you set the RightToLeft property anywhere other than a control's constructor (in VB.NET parlance, that's the New method).
In fact, the constructor is where you should set all of the properties of a form or control object. If you come from VB 6, it might seem logical to do it in the Load event handler, but that's not idiomatic .NET and, as you've discovered, can cause problems when initializing certain properties.
The technical reason for this is that certain properties (like RightToLeft) can actually only be set on the native window (which is how the Form objects used in the .NET world are implemented behind the scenes) at the time that it is created. When you attempt to change the property, the framework code actually has to destroy and then re-create the native window with the new property values.
Change the code to look like this instead:
Public Class Form1
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
modControls.SetFormRtl(Me)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Me.Hide()
Dim f As New Form2
f.ShowDialog()
MessageBox.Show("After dialog closed.")
End Sub
End Class
Public Class Form2
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
modControls.SetFormRtl(Me)
End Sub
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles Me.Load
End Sub
End Class
Speaking of non-idiomatic .NET code:
Methods should all be Pascal cased by convention. That means your setFormRTL method should be named SetFormRtl.
A helper function that sets the properties of an object just seems wrong to me. If anything, that's just bad OO design. If you want this method to be available for all of your Form objects, derive a custom form class and add this method (or even do the desired initialization in the constructor). Either way, all forms that you derive from this custom form object will inherit the functionality. Example:
Public Class MyCustomForm : Inherits System.Windows.Forms.Form
Public Sub New()
MyBase.New()
Me.SetRtl()
End Sub
Public Sub SetRtl()
Me.RightToLeft = RightToLeft.Yes
End Sub
End Class
Public Class Form1 : Inherits MyCustomForm
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Me.Hide()
Dim f As New Form2
f.ShowDialog()
MessageBox.Show("After dialog closed.")
End Sub
End Class
Public Class Form2 : Inherits MyCustomForm
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles Me.Load
End Sub
End Class
can you try this? all i am doing here is setting the RTL before the form is displayed.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Me.Hide()
Dim f As New Form2
modControls.setFormRTL(f)
f.ShowDialog()
MessageBox.Show("After dialog closed.")
modControls.setFormRTL(Me)
End Sub
End Class
and remove code form load event of form 2