Here is some simple sample C# code in Visual Studio 2008:
public partial class Form1 : Form
{
private static System.Timers.Timer TestTimer;
public Form1()
{
InitializeComponent();
TestTimer = new System.Timers.Timer();
TestTimer.Elapsed += DoSomething;
}
private void DoSomething(Object source, EventArgs e)
{
}
}
If I right click on the DoSomething assigned as a handler, and select Go to definition, VS finds the body of DoSomething. So far so good.
If I Right Click on it and Find all references it finds nothing. (!?)
If I do either of these actions for the body of DoSomething itself, it finds only itself, not the assignment as an event handler.
Am I missing something obvious? A setting perhaps? In all other cases when you ask for all references that includes the definition and every other reference. I realize the assignment is thinking in terms of delegates, but this seems inconsistent. It would be very convenient to easily find when something was assigned as a handler.
Your event handler declaration is not quite up to snuff. The ElapsedEventHandler delegate has a different signature. Fix:
void DoSomething(object sender, System.Timers.ElapsedEventArgs e) {
// etc..
}
IntelliSense now will be able to find all references. Do favor using IntelliSense to get the event assignment correct. After you type +=, press the Tab key twice to let it automatically generate the code.
Related
First, the apology: I'm new to posting questions on this site, so I apologize for formatting or information errors.I have seen many answers to taking data from a serial port dropped on a form and using it to populate text boxes, graphs, etc. on the main form, using "Invoke" because the serial port is running in a different thread.
I am trying to "generalize" some comm stuff we use all the time in to a class (yes, the old VB6 programmer is trying to grow up :-) and I'm having issues. I can do some things if I force a form name in the main program.cs and use the same namespace for the class, but this sorta defeats the purpose. I've also tried adding an event on the "received" even of the serial port in the class to raise an event on the main form. The event tries to get raised but a cross thread exception occurs.
The code at this point is quite large, so I'll try to "outline" it. In simplistic form, assuming I have a for called "Form1" which contains a text box called textbox1 and a class called "SerialThing":
Form1:
SerialThing mySerialThing ;
Form1_Load:
mySerialThing = new SerialThing();
DisplayData()
Textbox1.Text = "You Got Data!";
SerialThing:
Static SerialPort myDevice;
Init()
myDevice = new SerialPort;
myDevice.DataReceived += new SerialDataReceivedEventHandler(devicePort_DataReceived);
devicePort_DataReceived()
this.Invoke(new EventHandler(DisplayData));
The above will work if the serial port is placed on the main form, but not if created inside the class.
Again, sorry if too complex, or too simplistic. I am looking for an "easy" way to do this, but keep the class "generalized" (ideally not have to have the workspace names match, etc).
-Vin
There are many, many ways to do this. I'll present the classic approach using a custom event, delegates, and Invoke(), as I think it's important to understand that process. Once you've got this down, you can jump to some of the newer approaches.
First, in your SerialThing() class, you declare a Custom event to pass out data when it is received:
class SerialThing
{
public delegate void DataReceivedDelegate(string data);
public event DataReceivedDelegate DataReceived;
static SerialPort myDevice;
public SerialThing()
{
myDevice = new SerialPort();
myDevice.DataReceived += new SerialDataReceivedEventHandler(myDevice_DataReceived);
}
void myDevice_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// ... grab the data and place into a string called "data" ...
string data = "";
// raise our custom event:
if (DataReceived != null)
{
DataReceived(data);
}
}
}
Now, over in Form1, you subscribe to that custom event when you create the instance of SerialThing. Additionally, when that event is received, you marshal the call from the secondary thread to the main thread using InvokeRequired, Invoke, and a delegate:
public partial class Form1 : Form
{
SerialThing mySerialThing;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
mySerialThing = new SerialThing();
mySerialThing.DataReceived += new SerialThing.DataReceivedDelegate(mySerialThing_DataReceived);
}
private delegate void DataReceivedDelegate(string data);
void mySerialThing_DataReceived(string data)
{
if (this.InvokeRequired)
{
this.Invoke(new DataReceivedDelegate(mySerialThing_DataReceived), new Object[] { data });
}
else
{
textBox1.Text = data;
}
}
}
EDIT: In response to your comments below...
Think of a delegate as simply a "pointer to a method". When you execute the delegate, the associated method gets run.
The InvokeRequired() portion determines if the code is running in a different thread than the one that created the control. In this case, the control is the Form itself (this). If true is returned, then the event was received in a different thread. We then proceed to this.Invoke() line inside the true portion of the If block. Again this refers to the Form. Thus the Form is requesting to Invoke ("run") the passed delegate on the thread that created it (the main UI thread). We create a instance of the delegate that actually points to the same method we are already in resulting in a recursive call. The second parameter is simply an array of Object used to pass the parameters along with the delegate.
When Invoke() is run we end up re-entering the method because of the recursive call. At this point, however, the InvokeRequired() check will return false as we are now running in the main UI thread. Therefore we drop down into the false portion of the If statement where we update the TextBox. In this pattern it is safe to update an GUI controls in the else block of the If statement.
Note that a recursive call isn't necessary here. This is simply a style choice. We could have instead used a second "helper" function that the delegate pointed to, and Invoked that instead. The recursive approach reduces the number of methods required.
This is perhaps the most verbose approach to solving this type of problem. I like it, though, as it shows the flow of events and data, and movement between the threads.
We could shorten all the Form code to just this, using anonymous delegates:
private void Form1_Load(object sender, EventArgs e)
{
mySerialThing = new SerialThing();
mySerialThing.DataReceived += delegate (string data)
{
this.Invoke((MethodInvoker)(delegate() { textBox1.Text = data; }));
};
}
I don't know about you, but as a former VB6 programmer myself, that just looks weird when you first see that type of thing.
I've also used components that I know have things running in different
threads, yet the "form code" has never had to use the delegate stuff,
so maybe there's something that can be buried into the class?
Yes, it's possible to bake some "magic" into a class so that it raises events already on the main UI thread, thus not requiring any Invoke() calls. One way to do this is thru using a SynchronizationContext.
Another possibility for approaching this type of problem would be to use a BackgroundWorker() control which has events such as ProgressChanged() and RunWorkerCompleted() that are raised in the main UI thread for you (they do the necessary invoking type stuff under the hood for you).
I'm trying to write a simple Visual Studio extension that performs an action when a file is saved:
protected override void Initialize()
{
base.Initialize();
var dte = (DTE)GetService(typeof(DTE));
dte.Events.DocumentEvents.DocumentSaved += DocumentEvents_DocumentSaved;
}
void DocumentEvents_DocumentSaved(Document doc)
{
// Do something
}
But apparently the DocumentsSaved event is never raised, so the DocumentEvents_DocumentSaved is not called...
Am I missing something? Isn't this event supposed to be raised every time a file is saved? If not, is there another way I can detect changes to the files in the solution? (I'd rather avoid resorting to a FileSystemWatcher if possible...)
(note: I know that the extension is properly loaded, since a breakpoint in the Initialize method is hit, so the problem is not there)
According to this: http://social.msdn.microsoft.com/Forums/en-US/vsx/thread/0857a868-e650-42ed-b9cc-2975dc46e994
You need to keep a strong reference to both the Events and DocumentEvents objects for it to work.
I have created an Excel Addin project in C#. Now the solution contains a file ThisAddin.cs, which has a class ThisAddin. Later I have added an item called Form to the same solution. In Form, when I click on a button, for that button click event i want to call a method inside ThisAddin.cs file.
namespace ExcelAddIn
{
public partial class ThisAddIn
{
public void RefreshExcelData()
{
}
}
}
Now in MyForm.cs, while trying to create an object for ThisAddin class there is a compilation error that Thisaddin class doesn't have a constructor that takes 0 arguments.
private void btnUploadTestCases_Click(object sender, EventArgs e)
{
ThisAddIn objrefresh = new ThisAddin();
}
What am I missing here?
You are approaching the problem from the wrong direction. When you click the button, you don't want to create a new add-in, what you really want is to access the add-in instance which is created for you by VSTO when Excel starts up, which is accessible via Globals.ThisAddIn.
Change your code in the Form to the following:
private void btnUploadTestCases_Click(object sender, EventArgs e)
{
var addIn = Globals.ThisAddIn;
addIn.RefreshExcelData();
}
... and it should work a charm.
That being said, is there a good reason for this a method to be on ThisAddIn? In general, ThisAddIn should be used to wire up and tear down the add-in when Excel starts up / shuts down, and I would recommend to put as little logic in there as possible.
Use this code:
Globals.ThisAddIn.Application.StatusBar = "Referesh clicked!!!."; Globals.ThisAddIn.RefreshExcelData();
Just make sure your function remains public.
When I'm to subscribe to event, i'm coding like that: (in visual studio 2010)
1. I Write down like following code:
this.Loaded +=
2. I Press tab key.
3. A IDE fill a below code automatic:
this.Loaded+=new RoutedEventHandler(someClass_Loaded);
4. But the method someClass was not exist yet. so I write a method like following code:
private void someClass_Loaded()
{
}
5. But signiture of someClass was not defined properly yet. so I set cursor on the delegate, "RoutedEventHandler".
6. I press F12. and then IDE showing me a define of the RoutedEventHandler.
namespace System.Windows
{
[...]public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);
}
7. copy a arguments of the RoutedEventHandler.
8. I paste it to the method someClass_Loaded
private void someClass_Loaded(object sender, RoutedEventArgs e)
{
}
Is it best coding practice?
ps. When I subscribe a event by anonymous method, I do like this.
press tab key.
Try doing this twice. Not only will Visual Studio expand the new event handler assignment, it will also create a stub method in the class that has the correct name and proper signature.
There is a private void btnContBalloon_Click(object sender, EventArgs e). Can I make this static because I want to invoke this from static method but I can not.
Making events static is a great way to shoot the foot. A static event has an unlimited life-time. Which makes any event handlers you register for the event live forever too. Which makes any form that contains such an event handler live forever too. A leak.
Registering an event handler for a static event requires code in, say, the FormClosing event handler that explicitly unregisters the handler. You can see this explicitly documented in the MSDN Library article for the SystemEvents class, one of the few examples of a class in the .NET framework that has static events.
The better approach is to keep track of the form instance whose button's Click event should be activated. Something like this:
public partial class Form1 : Form {
public static Form1 MainForm { get; private set; }
public Form1() {
InitializeComponent();
MainForm = this;
}
public void RunClickMethod() {
button1.PerformClick();
}
protected override void OnFormClosing(FormClosingEventArgs e) {
MainForm = null;
base.OnFormClosing(e);
}
}
Which allows client code to do this:
Form1.MainForm.RunClickMethod();
Yes, if that method doesn't need the instance members of the enclosing class you can make it static. Nothing prevents an event handler from being static, if that is the real question.
Bottom line: If that method only uses the sender object (probably the button) and the event args or other static members, then this is perfectly valid and possible.
In general: Yes, eventhandlers can be made static. But the normal rules for static methods apply.
But often the autogenerated code gets into trouble when you change a autogenerated eventhandler to static. I'd do that with manual added eventhandlers, only.