I have a VSTO addin for outlook 2013. I'm trying to register an event with an event handler for a Form closing event.
Here is my code from class Form1:
public delegate void MyEventHandler();
private event MyEventHandler Closing;
private void OtherInitialize()
{
this.Closing += new MyEventHandler(this.Form1_Closing);
}
Also from class Form1:
public Form1()
{
InitializeComponent();
OtherInitialize();
}
private void Form1_Closing(object sender, CancelEventArgs e)
{
// Not sure what to put here to make the application exit completely
// Looking for something similar to Pytthon's sys.exit() or
// Applicaton.Exit() in Forms Applicatons, I tried
// Applicaton.Exit() it did not work
}
When I run this I get the error and warning:
The warning:
Form1.Closing hides inherited member System.Windows.Forms.Form.Closing. Use the new keyword if hiding was intended
The error:
No overload for Form1_Closing matches delegate System.EventHandler
What do these errors/warnings mean? How can I properly register the Form1_Closing event handler for when the form is closed with either the X button or form.Close() Right now I'm able to call form.Close() but it doesn't seem to trigger the Form1_Closing event.
There is no need to declare the Closing event because the parent class provides the event out of the box. Moreover, you can simply set the event handler without declaring the delegate class (latest .net versions):
public Form1()
{
InitializeComponent();
OtherInitialize();
}
private void OtherInitialize()
{
Closing += Form1_Closing;
}
private void Form1_Closing(object sender, CancelEventArgs e)
{
// Not sure what to put here to make the application exit completely
// Looking for something similar to Pytthon's sys.exit() or
// Applicaton.Exit() in Forms Applicatons, I tried
// Applicaton.Exit() it did not work
}
Related
This question already has an answer here:
Events raised from a ShowDialog Form aren't raised all the way to a calling vb6 app via com interop?
(1 answer)
Closed 9 months ago.
I have written a COM Interop visible class library in C#. If i open up the vb6 object browser and look at the members exposed, am seeing an event for each and every single exposed member.
In my interop I have a form with one button, So once the user clicks on the button, the event needs to be invoked but it is not happening even though i have invoked the com visible event on button click. But Alternatively, if i call an public C# function from vb6 and inside the function have invoked the com visibile event, then the event is getting triggered in vb6.0
Below is my C# code
public partial class Form1 : Form, EventsInf
{
public delegate void GetData_delegate(string serviceid);
public event GetData_delegate GetData;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Button click entered");
GetData?.Invoke("test");
}
public void raiseevent()
{
MessageBox.Show("Event raised from function");
GetData?.Invoke("test");
}
public void show()
{
Form1 f1 = new Form1();
f1.ShowDialog();
}
My Interface:
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface Interface
{
void GetData(string serviceid);
}
My EventsInf:
[ComVisible(true)]
public interface EventsInf
{
void raiseevent();
}
VB6.0 Code:
Private WithEvents test As ClassLibrary5.Form1
Private obj As ClassLibrary5.Class1
Private Sub Form_Load()
Set obj = New ClassLibrary5.Class1
Set test = New ClassLibrary5.Form1
test.raiseevent
Me.Visible = False
obj.Show
End Sub
Private Sub test_GetData(ByVal serviceid As String)
End Sub
Please refer to the screenshot, where i have converted the C# dll to tlb and added it as reference to my vb6 project. Now on executing the vb 6 project, winform's(form window) gets launched. But, the breakpoint is not getting hit after pressing the 'click me' button.
In C# you have two different things named GetData. This seems like a mistake.
There is the event ... GetData in the Form class.
And there is the regular function GetData in the interface
Interface.
And the form doesn't implement that interface anyway. (And why is it even needed?)
So I think your test_GetData doesn't really exist as far as VB6 is concerned. In the IDE you should see test in the left dropdown IIRC, and GetData plus any other event in the right dropdown. But it actually just says "General" on the left.
Did you have to type in Private Sub test_GetData ... by hand?
Root cause:
I have writted 'f1.ShowDialog();' inside my class where f1 is the form object.
Fix:
By rewritting the form code with 'this.Show();' inside a public function resolved this issue.
C# code:
private void button1_Click(object sender, EventArgs e)
{
GetData?.Invoke("test");
}
public void raiseevent()
{
this.Show();
MessageBox.Show("Event raised from function");
}
VB6.0
Private WithEvents test As ClassLibrary5.Form1
Private Sub Form_Load()
Set test = New ClassLibrary5.Form1
test.raiseevent
Me.Visible = False
End Sub
Private Sub test_GetData(ByVal serviceid As String)
End Sub
You really ought to follow the standard convention for exposing events. If you want to raise an event that provides text data and raise that event when the user clicks the Button then it ought to look like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public event EventHandler<DataAvailableEventArgs> DataAvailable;
protected virtual void OnDataAvailable(DataAvailableEventArgs e)
{
DataAvailable?.Invoke(this, e);
}
}
public class DataAvailableEventArgs : EventArgs
{
public string Data { get; }
public DataAvailableEventArgs(string data)
{
Data = data;
}
}
You then raise the event by calling the OnDataAvailable method and passing a DataAvailableEventArgs object, e.g.
OnDataAvailable(new DataAvailableEventArgs("test"));
You can do that from the Click event handler of a Button or a RaiseDataAvailable method or wherever. The event handler will then be like any other, i.e. the sender parameter will be the object that raised the event and the e parameter will contain the data, e.g.
Dim data As String = e.Data
If you really want to define your own delegate (maybe COM requires that; not sure) then you can do this:
public delegate void DataAvailableEventHandler(object sender, DataAvailableEventArgs e);
and this:
public event DataAvailableEventHandler DataAvailable;
Suppose If I have a button on a custom made user control that removes the control from the form (Lets call it formX) it is placed in.
private void btnClose_Click(object sender, EventArgs e)
{
this.ParentForm.Controls.Remove(this);
}
Now upon closing this UserControl I want a method in the formX to be called.
I tried doing something like this :
discount.ControlRemoved += new ControlEventHandler(discount_ControlRemoved);
void UserControl_ControlRemoved(object sender, ControlEventArgs e)
{
CallMethod();
}
However this does not work, when removing the userControl from formX the event is not even called in the debugger.
How do I do this?
The event you should be using is the ControlRemoved event on the parent container, likely the Form in this case. You could do this several ways, some may be better than others depending upon what all you want to do, but the following should at least do what you are requesting:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.ControlRemoved += new ControlEventHandler(Form1_ControlRemoved);
}
void Form1_ControlRemoved(object sender, ControlEventArgs e)
{
if (e.Control.Name == "NameOfUserControl") CallMethod();
}
private void CallMethod()
{
// Do stufff...
}
}
This assumes that you have named your User Control instance "NameOfUserControl". There are various ways you could check for the control being removed to be the correct one. You can also make this a bit more dynamic by doing this in the control itself while using delegates to call back to the parent form, etc... This is just a basic example.
Basically I have two main components to my program.
1) I have my main window which contains my dynamically created user controls.
2) The two different types of user controls.(ctr1 and ctr2)
I want to be able to press a button on ctr1, have it bubble up an event and have the main window handle the event which will create another instance of ctr2. The problem I am having is that I honestly can't find any good resources that gives actual code examples of how to accomplish this.
In ctr1 I have:
public event RoutedEventHandler MyEvent
{
add { AddHandler(MyEvent_randomName, value); }
remove { RemoveHandler(MyEvent_randomName, value); }
}
void RaiseMyEvent()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(ctr1.MyEvent_randomName);
RaiseEvent(newEventArgs);
}
protected override void RaiseEvent_click()
{
RaiseMyEvent();
}
and for my mainWindow I have:
public MainWindow()
{
InitializeComponent();
MainWindow.AddHandler(ctr1.MyEvent_randomName, new RoutedEventHandler(MyButtonHandler));
}
void MyButtonHandler(object sender, RoutedEventArgs e)
{
MessageBox.Show("My New Clicked Event");
}
Where I have been running into trouble is the "MainWindow.AddHandler(ctr1.MyEvent_random......);
I keep getting the error:
An object reference is required for the non-static field, method, or property 'System.Windows.UIElement.AddHandler(System.Windows.RoutedEvent, System.Delegate)'
Im sorry if this is a very beginner question but I only started WPF and C# a few days ago and I have yet to find a good online tutorial that explains everything plainly.
Check the error:
An object reference is required for the non-static field, method, or
property
'System.Windows.UIElement.AddHandler(System.Windows.RoutedEvent,
System.Delegate)'
You are trying to access the method statically:
MainWindow.AddHandler . . .
When you should be doing:
AddHandler . . .
As an aside you may want to look at ICommand and MVVM to do what you want to do, but as a beginner you have a lot to learn right now ;)
You can try this :
In ctr1
public event EventHandler Ctrl1ClickEvent;
when you press the button in ctrl1
Ctrl1ClickEvent(this, EventArgs.Empty);
In mainWindow
public MainWindow()
{
InitializeComponent();
this.ctrl1.Ctrl1ClickEvent += ctrl1ClickHandler;
}
private void ctrl1ClickHandler(object sender, EventArgs e)
{
MessageBox.Show("My New Clicked Event");
}
I know that VS will open an eventhandler stub by doubleclicking on an event.
I found the underlying event declaration in InitializeComponent of the form on which the button is located.
this.buttonWorkOn.Click += new System.EventHandler(this.buttonWorkOn_Click);
Can I use this event declaration (of Visual Studio) and register another eventhandling method with it?
Upon instantiation of that other form its eventhandling method would need to register itself with the click event of the button on the main form.
I have no clue how to do that even though I have read quite a bit about delegates and events and in principle I do understand how it works.
Thank you
If you right click on an event handler in the code editor and browse the definition you will find the way that it is declared, which you can then use in your own code.
For example, the declaration for a Button's Click event is:
public event EventHandler Click;
You can add these yourself and use them from other places to respond to events in any class you create.
Here's a sample form with a single button (added via the designer) that when clicked will raise its own event:
public partial class Form1 : Form
{
public event EventHandler ButtonClicked;
private void RaiseButtonClicked()
{
if (ButtonClicked != null)
ButtonClicked(this, EventArgs.Empty);
}
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
RaiseButtonClicked();
}
}
In another class you can then add a handler to that:
public class Responder
{
public Responder(Form1 form)
{
form.ButtonClicked += OnButtonClicked;
}
private void OnButtonClicked(object sender, EventArgs args)
{
MessageBox.Show("Button was clicked");
}
}
Now every instance of the Responder class will tell you when the button is clicked on the form.
By "Double clicking on an event", visual studio will generate an event handler for you. What you don't see is that visual studio also subscribes the generated event handler to the event, by adding a line of code in your designer file.
If goes something like this:
Double click 'clicked' event
Visual studio opens up your code file, and you have a new button1_clicked method, which is your event handler.
Your designer is updated with a line like button1.Clicked += button1_clicked
If you want to do manual event subscriptions, you can do so from your code file, by adding something like <formelement>.<event> += <eventhandler>. If you cant see available events in your intellisense, you can always check the online documentation. MSDN
(You should never change your designer file, as this is a generated file)
If you like to get multiple methods been executed when an event occurs you can simply add all of them in your code (or you can even add the same method multiple times):
private void DoSomething(object source, EventArgs eventArgs)
{
Console.WriteLine("Something happened.");
}
private void DoSomethingElse(object source, EventArgs eventArgs)
{
Console.WriteLine("Something else happened.");
}
private void AttachToEvent()
{
button1.Clicked += DoSomething;
button1.Clicked += DoSomethingElse;
button1.Clicked += DoSomething;
}
This would print out:
Something happened.
Something else happened.
Something happened.
OK – it was not my application, I just tried to improve on it.
Anyway, the question was who owns whom and who is visible where.
On the Mainform are controls for user input.
On MainForm a variable of type "class preview" is declared:
Preview pv
For the Preview class I added an event declaration named WorkOn:
public class Preview
{
#region "Variables"
#region "PublicEvent"
public event EventHandler WorkOn;
}
Then in the MainForm, the variable pv – declared as a class field - is instantiated within a method.
pv = new Preview()
after which the user input in the controls of the main form is checked and when ok saved in the variables of the preview class.
Then, the PreviewForm is instantiated within the preview class, with the instance of the owning class (preview --> as instance pv) passed as a variable to the instantiation of the PreviewForm.
I had to create this overloaded constructor because from the PreviewForm an eventhandler must be registered with the preview class to make this work – as I realized.
formPreview formPreview = new formPreview(this);
// this --> is the class preview, the instance pv
// Instantiation of FormPreview
public formPreview(Preview preview)
{
InitializeComponent();
this.preview = preview;
// now for the event in the preview class an eventhandling method
// of the preview form is registered:
preview.WorkOn += formPreview_Close;
}
This is the registered method of FormPreview:
private void formPreview_Close(object sender, EventArgs e)
{
this.Close();
}
I was reminded again that events can only be raised from the class that publishes the event. So I had to create a public event raising method within the class preview – here named OnWorkOn:
public void OnWorkOn()
{
if (WorkOn != null)
WorkOn(this, EventArgs.Empty);
}
And finally I could trigger the event from the MainForm within the button to whose underlying event I planned to register the eventhandling method of the PreviewForm in the first place.
Only now I had to use the class variable pv of the MainForm as it is the medium between the MainForm and the PreviewForm:
public void buttonWorkOn_Click(object sender, EventArgs e)
{
pv.OnWorkOn();
// raising the event, informing whoever is registered to it
//...
}
So the design of the application did not allow for registering any eventhandling method of the preview form directly on the MainForm. That was the problem and I didn't quite see through the whole design yet.
Well – this is the outcome of a german C# tutorial – the only german one I know of.
You'll find it here:
[https://www.youtube.com/watch?v=-zCiwcgxMHw&list=PLvvL1HRuCBItyw45XnCqEXzuegKQd3MfL][1]
The code is not available for download anymore, but I could provide it as I am through.
On my MDIform click event I am opening my Form2 by passing my control and one event like this:
Form2 Obj = new Form2(ListBox1, ListBox1_ItemChanged);
And my From2 has opening class declared like this:
private readonly ListBox m_AssigndTree;
private EventHandler navChange;
public Form2(ListBox1 AssigndTree, EventHandler ListBox1_ItemChanged)
{
InitializeComponent();
m_AssigndTree = AssigndTree;
navChange = NavBarGroup3_ItemChanged;
}
Now have a click event on Form2 and I want to fire the event ListBox1_ItemChanged How I can do that, as to invoke the event of same form I use to do directly myEvent.Invoke += (parameters)
I have the following event on Form2:
private void button1_DoubleClick(object sender, EventArgs e)
{
// navChange.Invoke +=
}
You can't raise an event, declared in another type, directly.
ListBox1_ItemChanged in your sample is just an instance of EventHandler delegate, this is not and event.
To call an event use it like a function:
m_AssigndTree.ItemChanged();
You'll need to make up the arguments