I'm developing an application and I'm trying to detect when the workstation gets locked, for example by the user pressing the Windows + L keys.
I know that the lock event has the value
WTS_SESSION_LOCK 0x7
But i don't know how to use it. I've searched the web but found nothing.
You should use the SystemEvents class in the Microsoft.Win32 namespace, especially the SystemEvents.SessionSwitch event.
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; // Subscribe to the SessionSwitch event
static void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
if (e.Reason == SessionSwitchReason.SessionLock)
// Add your session lock "handling" code here
}
Update
If you need to have this event activated from the program startup in a Winforms application:
static class Program
{
[STAThread]
private static void Main()
{
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; // Subscribe to the SessionSwitch event
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
static void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
if (e.Reason == SessionSwitchReason.SessionLock)
// Add your session lock "handling" code here
}
}
Finnallly managed to do it on VB :D
First you need to import the libs:
Imports System
Imports Microsoft.Win32
Imports System.Windows.Forms
Then you add the handler:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddHandler SystemEvents.SessionSwitch, AddressOf SessionSwitch_Event
End Sub
Finnally you create the sub that captures it:
Private Sub SessionSwitch_Event(ByVal sender As Object, ByVal e As SessionSwitchEventArgs)
If e.Reason = SessionSwitchReason.SessionLock Then
MsgBox("Locked")
End If
If e.Reason = SessionSwitchReason.SessionUnlock Then
MsgBox("Unlocked")
End If
End Sub
Last you remove the handler:
Private Sub closing_event(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
RemoveHandler SystemEvents.SessionSwitch, AddressOf SessionSwitch_Event
End Sub
Related
I have a code that has a text box and a button, when i press the button, the code update the text box and after words sleep for 5 seconds, in those seconds the ui is freezing
I tried with delegates, and threading but nothing works
This is the code with delegates:
MainWindow.vb
Class MainWindow
Delegate Sub MySubDelegate(ByVal x As String)
Private m_engine As Engine
Public Sub New()
m_engine = New Engine(AddressOf WriteToLog)
InitializeComponent()
Me.DataContext = m_engine.GetViewModel()
End Sub
Public Sub WriteToLog(str As String)
Dim vv As ViewModel = CType(DataContext, ViewModel)
vv.Log = str
End Sub
Private Sub clicked(sender As Object, e As RoutedEventArgs)
m_engine.TimingRecord()
End Sub
End Class
Engine.vb
Private m_viewModel As New ViewModel
Private _msd As MainWindow.MySubDelegate
Public Sub New()
End Sub
Sub New(msd As MainWindow.MySubDelegate)
_msd = msd
End Sub
Public Function GetViewModel() As ViewModel
Return m_viewModel
End Function
Public Sub TimingRecord()
_msd("aaaaa")
SetText()
End Sub
Public Sub SetText()
Thread.Sleep(5000)
End Sub
viewModel.vb
Public Class ViewModel
Implements INotifyPropertyChanged
Private m_log As String
Public Property Log As String
Get
Return m_log
End Get
Set(value As String)
m_log = value
End Set
End Property
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
This is the code with thread:
MainWindow.vb
Delegate Sub MySubDelegate(ByVal x As String)
Private m_engine As Engine
Public Sub New()
m_engine = New Engine(AddressOf WriteToLog)
InitializeComponent()
Me.DataContext = m_engine.GetViewModel()
End Sub
Public Sub WriteToLog(str As String)
Me.Dispatcher.Invoke(Sub() CType(DataContext, ViewModel).Log = str)
'Dim vv As ViewModel = CType(DataContext, ViewModel)
'vv.Log = str
End Sub
Private Sub clicked(sender As Object, e As RoutedEventArgs)
m_engine.TimingRecord()
End Sub
Engine.vb
Public Class Engine
Private m_viewModel As New ViewModel
Private m_thread As Thread
Private _msd As MainWindow.MySubDelegate
Public Sub New(msd As MainWindow.MySubDelegate)
_msd = msd
End Sub
Public Function GetViewModel() As ViewModel
Return m_viewModel
End Function
Public Sub TimingRecord()
m_thread = New Thread(AddressOf DoRecordThread)
m_thread.IsBackground = True
m_thread.Start("aa")
SetText()
End Sub
Public Sub SetText()
Thread.Sleep(5000)
End Sub
Private Sub DoRecordThread(str As String)
_msd(str)
'm_viewModel.Log = str
End Sub
End Class
The ViewModel Stay The same. I'm using wpf so i bind the Log into the textbox and with simple code it works.
Thank you all in advance.
Thread.Sleep causing the issue. It blocks the UI thread that makes the UI frozen.
Have the long running task in different thread and once completed Update the UI(TextBox) with Application.Current.Dispatcher.
Sample Code to update the UI from background thread with Dispatcher :
Application.Current.Dispatcher.Invoke(new Action(() => { Textbox1.Text = result; }))
This is not a right way but I hope this is what you are looking for.
Update
Also, there is another way, you can use builtin BackgroundWorker.
//Add the namespace
using System.ComponentModel;
//Declare
private readonly BackgroundWorker worker = new BackgroundWorker();
//Initialize
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
//method declaration
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
worker.ReportProgress(0, "Process started");
// run all background tasks here
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//Progress update with e.UserState.ToString();
}
private void worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
//update ui once worker complete his work
}
//Invoke
worker.RunWorkerAsync();
The problem solved by put the thread.sleep but very foolish of me in the viewmodel class i accidently delete the property changed now it is working perfectly thank you all for helping
I found this very interessting Code here. I tried to translate it to VB.NET, but I am not able to. I want to remove all Handlers for the event 'click' of a known button.
Can anybody help me and translate it to VB.NET?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
button1.Click += button1_Click;
button1.Click += button1_Click2;
button2.Click += button2_Click;
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello");
}
private void button1_Click2(object sender, EventArgs e)
{
MessageBox.Show("World");
}
private void button2_Click(object sender, EventArgs e)
{
RemoveClickEvent(button1);
}
private void RemoveClickEvent(Button b)
{
FieldInfo f1 = typeof(Control).GetField("EventClick",
BindingFlags.Static | BindingFlags.NonPublic);
object obj = f1.GetValue(b);
PropertyInfo pi = b.GetType().GetProperty("Events",
BindingFlags.NonPublic | BindingFlags.Instance);
EventHandlerList list = (EventHandlerList)pi.GetValue(b, null);
list.RemoveHandler(obj, list[obj]);
}
}
}
This is a direct translation into VB syntax, as per the OPs request.
Imports System.Reflection ' Required if not already in your code
Imports System.ComponentModel
Partial Public Class Form1
Inherits Form
Public Sub New()
InitializeComponent()
AddHandler button1.Click, AddressOf button1_Click
AddHandler button1.Click, AddressOf button1_Click2
AddHandler button2.Click, AddressOf button2_Click
End Sub
Private Sub button1_Click(sender As Object, e As EventArgs)
MessageBox.Show("Hello")
End Sub
Private Sub button1_Click2(sender As Object, e As EventArgs)
MessageBox.Show("World")
End Sub
Private Sub button2_Click(sender As Object, e As EventArgs)
RemoveClickEvent(button1)
End Sub
Private Sub RemoveClickEvent(b As Button)
Dim f1 As FieldInfo = GetType(Control).GetField("EventClick", BindingFlags.Static Or BindingFlags.NonPublic)
Dim obj As Object = f1.GetValue(b)
Dim pi As PropertyInfo = b.GetType().GetProperty("Events", BindingFlags.NonPublic Or BindingFlags.Instance)
Dim list As EventHandlerList = DirectCast(pi.GetValue(b, Nothing), EventHandlerList)
list.RemoveHandler(obj, list(obj))
End Sub
End Class
It works fine, provided of course the form has button1 and button2 dropped onto it.
The thing that makes people reject your question (aside from #phaedra 's perfectly valid comments) is that there is little point in this code. The function RemoveHandler can be used instead.
After a while of searching the internet, I found this piece of code that triggers upon a LINQ-based change to the Database. It trigger only once and doesn't mention or show what was changed/deleted/added, or what table was CRUDed.
static class GlobalNotifications
{
public static event OnChangeEventHandler OnChange;
public static void InitializeNotifications(string connectString)
{
// Initialize notifications
SqlDependency.Start(connectString);
// Create and register a new dependency
SqlDependency dependency = new SqlDependency();
dependency.OnChange += new OnChangeEventHandler(NotificationCallback);
System.Runtime.Remoting.Messaging.CallContext.SetData("MS.SqlDependencyCookie", dependency.Id);
}
internal static void NotificationCallback(object o, SqlNotificationEventArgs args)
{
OnChange.Invoke(o, args);
}
}
This is how I'm using it:
public partial class Nawa : Form
{
public Nawa()
{
InitializeComponent();
}
private void Nawa_Load(object sender, EventArgs e)
{
GlobalNotifications.InitializeNotifications("Server=GENISYSSERVER; Trusted_Connection=no;database=Maple_DBv1; user id=sa; password=Wc123Wc123");
GlobalNotifications.OnChange += new System.Data.SqlClient.OnChangeEventHandler(GlobalNotifications_OnChange);
}
void GlobalNotifications_OnChange(object sender, System.Data.SqlClient.SqlNotificationEventArgs e)
{
MessageBox.Show("Test");
}
private void button1_Click(object sender, EventArgs e)
{
using (DataClasses1DataContext dbcontext = new DataClasses1DataContext("Server=GENISYSSERVER; Trusted_Connection=no;database=Maple_DBv1; user id=sa; password=Wc123Wc123")) {
OrderFood random = dbcontext.OrderFoods.FirstOrDefault(id => id.ID == 10);
if (random != null) {
if (random.MenuID == 4)
random.MenuID = 1;
else
random.MenuID = 4;
dbcontext.SubmitChanges();
}
}
}
}
Can someone help in this regard? How to get more details of what was changed, type of change, Table(s) changed, and why does it fire only once. Also, how can it understand LINQ changes only? It doesn't trigger on direct changes etc.
Reference:
Extemporaneous Mumblings
A SQLDependency will only fire once, you need to recreate the dependency after it has fired.
The OnChange event fires once and then gets consumed, so you need to hook up the event again after it fires.
Dan Miser - SqlDependency
I don't have any C# code to hand to demonstrate how to deal with this but I'm sure some VB.NET should work well enough for you to come up with your own solution.
Private _permissionsDependency As SqlDependency
Private Sub doSubscribe()
_permissionsDependency = New SqlDependency(cmd.InnerCommand)
RemoveHandler _permissionsDependency.OnChange, AddressOf User_OnChange
AddHandler _permissionsDependency.OnChange, AddressOf User_OnChange
End Sub
Private Sub User_OnChange(ByVal sender As Object, ByVal e As System.Data.SqlClient.SqlNotificationEventArgs)
If _permissionsDependency IsNot Nothing Then RemoveHandler _permissionsDependency .OnChange, AddressOf User_OnChange
Select Case e.Info
Case SqlNotificationInfo.Delete
RaiseEvent UserDeleted(Me)
Case SqlNotificationInfo.Update
populateUser()
RaiseEvent UserUpdated(Me)
Case Else
End Select
End Sub
As you can see you can find out what happened by looking at e.Info, which will allow for you to know what happened (in my example I'm only looking for deletes and updates).
I want, that if a cell/row goes to edit mode, then, if the user attempts to select a different row, it should try to commit that row, if the row is not committed sucessfully, it should decline the selection request and the editing row should remain selected and in edit mode.
Do you have experience with a good helper for it? any good workaround?
NOTE: I've been struggling with this issue for a long time and already got some experience, so please post only working examples, not random thoughts.
The code bellow is includes extension from here (code normalized to fit StackOverflow screen witdh, sorry).
Imports System.ComponentModel
Imports System.Windows.Threading
Namespace Components
Public NotInheritable Class DataGridSelectionChangingBehavior
Public Shared Function GetEnableSelectionChanging(
ByVal element As DataGrid) As Boolean
If element Is Nothing Then Throw New ArgumentNullException("element")
Return element.GetValue(EnableSelectionChangingProperty)
End Function
Public Shared Sub SetEnableSelectionChanging(
ByVal element As DataGrid, ByVal value As Boolean)
If element Is Nothing Then Throw New ArgumentNullException("element")
element.SetValue(EnableSelectionChangingProperty, value)
End Sub
Public Shared ReadOnly EnableSelectionChangingProperty As _
DependencyProperty =
DependencyProperty.RegisterAttached("EnableSelectionChanging",
GetType(Boolean),
GetType(DataGridSelectionChangingBehavior),
New FrameworkPropertyMetadata(False,
New PropertyChangedCallback(
AddressOf EnableSelectionChanging_PropertyChanged)))
Public Shared Sub AddSelectionChangingHandler(
ByVal element As DataGrid, handler As SelectionChangingEventHandler)
If element IsNot Nothing Then _
element.AddHandler(
DataGridSelectionChangingBehavior.SelectionChangingEvent, handler)
End Sub
Public Shared Sub RemoveSelectionChangingHandler(
ByVal element As DataGrid, handler As SelectionChangingEventHandler)
If element IsNot Nothing Then _
element.RemoveHandler(
DataGridSelectionChangingBehavior.SelectionChangingEvent, handler)
End Sub
Public Shared ReadOnly SelectionChangingEvent As RoutedEvent =
EventManager.RegisterRoutedEvent("SelectionChanging",
RoutingStrategy.Bubble,
GetType(SelectionChangingEventHandler),
GetType(DataGridSelectionChangingBehavior))
Private Shared Sub EnableSelectionChanging_PropertyChanged(
ByVal sender As Object, ByVal e As DependencyPropertyChangedEventArgs)
Dim dataGrid = DirectCast(sender, DataGrid)
If CBool(e.NewValue) Then
AddHandler dataGrid.PreparingCellForEdit,
AddressOf DataGrid_PreparingCellForEdit
AddHandler dataGrid.SelectionChanged,
AddressOf DataGrid_SelectionChanged
Else
RemoveHandler dataGrid.PreparingCellForEdit,
AddressOf DataGrid_PreparingCellForEdit
RemoveHandler dataGrid.SelectionChanged,
AddressOf DataGrid_SelectionChanged
RecentColumn.Remove(dataGrid)
End If
End Sub
Private Shared Sub DataGrid_SelectionChanged(
ByVal sender As Object, ByVal e As SelectionChangedEventArgs)
If e.RemovedItems.Count = 0 Then Exit Sub
Dim dataGrid = DirectCast(sender, DataGrid)
Dim removed = e.RemovedItems(0)
Dim row = dataGrid.GetContainerFromItem(Of DataGridRow)(removed)
Dim scea As New SelectionChangingEventArgs(row,
DataGridSelectionChangingBehavior.SelectionChangingEvent, dataGrid)
dataGrid.RaiseEvent(scea)
If scea.Cancel Then
RemoveHandler dataGrid.SelectionChanged,
AddressOf DataGrid_SelectionChanged
Dim operation = dataGrid.Dispatcher.BeginInvoke(
Sub()
dataGrid.SelectedItem = removed
Dim column As DataGridColumn = Nothing
If RecentColumn.TryGetValue(dataGrid, column) Then
Dim cellsPanel =
row.GetVisualDescendant(Of DataGridCellsPanel)().
Children.Cast(Of DataGridCell)()
Dim recentCell =
If(cellsPanel.SingleOrDefault(
Function(cell) cell.Column Is column),
cellsPanel.FirstOrDefault)
If recentCell IsNot Nothing Then
recentCell.IsEditing = True
Keyboard.Focus(recentCell)
End If
End If
End Sub,
DispatcherPriority.ContextIdle)
AddHandler operation.Completed,
Sub(s, ea) AddHandler dataGrid.SelectionChanged,
AddressOf DataGrid_SelectionChanged
End If
End Sub
Private Shared m_RecentColumn As Dictionary(Of DataGrid, DataGridColumn)
Public Shared ReadOnly Property RecentColumn() As Dictionary(Of DataGrid,
DataGridColumn)
Get
If m_RecentColumn Is Nothing Then m_RecentColumn =
New Dictionary(Of DataGrid, DataGridColumn)()
Return m_RecentColumn
End Get
End Property
Private Shared Sub DataGrid_PreparingCellForEdit(
ByVal sender As Object, e As DataGridPreparingCellForEditEventArgs)
Dim dataGrid = DirectCast(sender, DataGrid)
RecentColumn(dataGrid) = e.Column
End Sub
End Class
Public Delegate Sub SelectionChangingEventHandler(
ByVal sender As Object, ByVal e As SelectionChangingEventArgs)
Public Class SelectionChangingEventArgs : Inherits RoutedEventArgs
Public Sub New(ByVal row As DataGridRow, routedEvent As RoutedEvent)
MyBase.New(routedEvent)
m_CurrentRow = row
End Sub
Public Sub New(ByVal row As DataGridRow,
ByVal routedEvent As RoutedEvent,
ByVal source As Object)
MyBase.New(routedEvent, source)
m_CurrentRow = row
End Sub
Private m_CurrentRow As DataGridRow
Public ReadOnly Property CurrentRow() As DataGridRow
Get
Return m_CurrentRow
End Get
End Property
Public ReadOnly Property Item() As Object
Get
If CurrentRow IsNot Nothing Then Return CurrentRow.Item
Return Nothing
End Get
End Property
Public Property Cancel As Boolean
End Class
End Namespace
Usage:
<DataGrid Name="dg"
src:DataGridSelectionChangingBehavior.EnableSelectionChanging="True"
src:DataGridSelectionChangingBehavior.SelectionChanging="dg_SelectionChanging">
Code behind (pseudu):
Private Sub dg_SelectionChanging(ByVal sender As Object,
ByVal e As SelectionChangingEventArgs)
If e.CurrentRow.IsEditing Then
Dim item = TryCast(e.CurrentRow.Item, MyEntityType)
If item IsNot Nothing AndAlso item.IsValid Then
Dim dataGrid = DirectCast(sender, DataGrid)
Dim committed = dataGrid.CommitEdit(DataGridEditingUnit.Row, True)
If committed Then Exit Sub
End If
e.Cancel = True
End If
End Sub
Note: visual studio might not show the event in the intellisense and might even generate a design-time error, but it should compile and work perfect.
FYI: code formatted modified to fit SO screen.
I need your help to clarify whether form work exactly like object?
If I create an object,obj2, from another object,obj1. the obj2 will be disposed on obj1 dispose.
However it is not so with forms.
check out the case & pseudo code give below.
I have three forms; form1, form2 & form2.
form1 is the startup form.
form1 will create &s how a form2 and from2 will create & show form3 using a button in each form.
if I close form2, after opening all the 3 forms, I am able to work in form1 and form3.
my question is even though form3 is created from form2, why it is not disposed on form2 close?
Form1
Public Class Form1
Private Sub cmdOpenForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdOpenForm2.Click
Dim frm As New Form2
With frm
''/.MdiParent = frmMain
.Show()
.BringToFront()
End With
End Sub
Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
''//frmMain.tsStatus.Text = "Form1 disposed"
End Sub
End Class
Form2
Public Class Form2
Private Sub cmdRandomColor_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdRandomColor.Click
Randomize()
Label1.ForeColor = Color.FromArgb(Rnd() * 255, Rnd() * 255, Rnd() * 255, Rnd() * 255)
End Sub
Private Sub Form2_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
frmMain.tsStatus.Text = "Form2 disposed"
End Sub
Private Sub cmdOpenForm3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdOpenForm3.Click
Dim frm As New Form3
With frm
''//.MdiParent = frmMain
.Show()
.BringToFront()
End With
End Sub
End Class
Form3
Public Class Form3
Private Sub cmdRandomColor_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdRandomColor.Click
Randomize()
Label1.ForeColor = Color.FromArgb(Rnd() * 255, Rnd() * 255, Rnd() * 255, Rnd() * 255)
End Sub
Private Sub Form3_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
frmMain.tsStatus.Text = "Form3 disposed"
End Sub
End Class
Any Help will be greatly appreciated.
EDIT
thank you all for the solution
Sorry to mention, I am not looking for a solution how to do dispose form3 on form2 close.
my interest is what is happening behind... Is there any possibility that form3 instance created from2 get GC collect and i get a memory error.
since i am getting protect memory access exception in my real application, which is not properly designed, and it too big to refactor now.
my question is where the form3 instance created? Is it in Form2 instance or somewhere else.
since i can able to access form3 instance after form2 disposed. i doubt it is created in somewhere else
There's nothing automatic happening in Dispose calls on forms related to new forms you create yourselves.
If you want a form to automatically dispose of a form it creates, you have to add code yourself to do this. Either find the .Dispose method added by the designer, and add it there, or implement the FormClosed event on the form.
That form2 "creates" form1 does not make any kind of relationship between the two.
Automatic disposal is available as an option. The form must be an "owned" form. The easiest way to do this is to use the Form.Show(owner) overload:
private void button1_Click(object sender, EventArgs e) {
new Form3().Show(this);
}
Or you can do it afterwards with the Form.AddOwnedForm() method. Beware that this has side-effects, an owned form is always shown in front of the owner. And it will get minimized and restored along with the owner. If you don't want this, you can keep explicit track of the lifetime of the form and dispose it yourself:
private Form3 mForm3;
private void button1_Click(object sender, EventArgs e) {
if (mForm3 == null) {
mForm3 = new Form3();
mForm3.FormClosed += (s, ea) => mForm3 = null;
mForm3.Show();
}
else {
mForm3.WindowState = FormWindowState.Normal;
mForm3.Focus();
}
}
protected override void OnFormClosed(FormClosedEventArgs e) {
if (mForm3 != null) mForm3.Dispose();
}
The framework is still holding on to your form object, until it gets closed. You can get a reference to it using My.Application.OpenForms.
If i create an object,obj2, from another object,obj1. the obj2 will be disposed on obj1 dispose.
Not necessarily. If some other object, say obj3 has a reference to obj2, then obj2 will stick around even after obj1 has been garbage collected.
In this case, the window manager has a reference to form3, so it won't be garbage collected even when form2 is.
You have to use the Form-Constructor that takes a Win32-Window-Handle as a parameter. You can pass a reference of form2 to form3 then and it works as you expected.
Private Sub cmdOpenForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdOpenForm2.Click
Dim frm As New Form2(Me)
With frm
.Show()
.BringToFront()
End With
End Sub
If you change the form variables to instance variables, and include this in the Show method, it will work
Code for Form1
public partial class Form1 : Form
{
Form2 f;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
f = new Form2();
f.Show(this);
}
private void button2_Click(object sender, EventArgs e)
{
f.Close();
f = null;
}
}
Code for Form2
public partial class Form2 : Form
{
Form3 f;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
f = new Form3();
f.Show(this);
}
}