DocumentSaved event is never raised - c#

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.

Related

Delegate.Combine: How to Check if multicast (combinable) delegates already has a delegate inside of it?

I am using Unity 3D, however, that information should be irrelevant for solving this problem as the core problem is System.Delegate (I wanted to let you know as I'll be linking to some Unity docs for clarification).
I have a custom window that has a custom update function DirectorUpdate. I need this function to run every editor update regardless of what the user/window is doing.
In order for this to be called every editor update, I Combine my method with the Delegate EditorApplication.update:
protected void OnEnable()
{
// If I do the below, base EditorApplication.update won't be called anymore.
// EditorApplication.update = this.DirectorUpdate;
// So I need to do this:
EditorApplication.update = (EditorApplication.CallbackFunction)System.Delegate.Combine(new EditorApplication.CallbackFunction(this.DirectorUpdate), EditorApplication.update);
... // Other stuff
}
Note that this is done inside a window's OnEnable.
The problem is that OnEnable can be called more than once during a single run (for example, when closing the window and then reopening the window during a single editor session) causing
EditorApplication.update = (EditorApplication.CallbackFunction)System.Delegate.Combine(new EditorApplication.CallbackFunction(this.DirectorUpdate), EditorApplication.update);
to be called multiple times, meaning my update method (this.DirectorUpdate) will eventually get called multiple times per update, which is causing some serious bugs.
So, the question is how do I check if EditorApplication.update already has my method "inside" of it. (By inside of it, I of course mean it has already been System.Delegate.Combine(d) to the delegate.)
I am aware that there could be other solutions, for example restoring EditorApplication.update to what it was prior when the window closes, however that won't account for all situations (for example, OnEnable also gets called during window refresh and such) and the bug will persist. (Also, what if another window Concatenates with EditorApplication.update while this window is open?) As such, the best solution would be to check if EditorApplication.update is already callin this method BEFORE Delegate.Combine-ing it.
I think you took the complicated road ;)
Subscribing and unsubscribing events and delegates is as simple as using the operators += and -= like
protected void OnEnable()
{
// You can substract your callback even though it wasn't added so far
// This makes sure it is definitely only added once (for this instance)
EditorApplication.update -= DirectorUpdate;
// This basically internally does such a Combine for you
EditorApplication.update += DirectorUpdate;
... // Other stuff
}
private void OnDisable()
{
// Remove the callback once not needed anymore
EditorApplication.update -= DirectorUpdate;
}
This way you can also have multiple instances of this window open and they all will receive the callback individually.
Btw if this is actually about an EditorWindow then afaik you should not use OnEnabled but you would rather use Awake
Called as the new window is opened.
and OnDestroy.
I am not familiar with what System.Delegate.Combine(d) does, but you can consider instead of enabling/disabling your window, destroying and instantiating it every time, and move your code to the Start or the Awake for it to be called only once per window "activation".
Last but not least, use a mighty boolean in the OnDisable so that you can handle the combine execution if your component was ever disabled. Like so:
bool omgIWasDisabled;
protected void OnEnable()
{
if (!omgIWasDisabled) {
EditorApplication.update = (EditorApplication.CallbackFunction)System.Delegate.Combine(new EditorApplication.CallbackFunction(this.DirectorUpdate), EditorApplication.update);
}
... // Other stuff
}
void OnDisable() {
omgIWasDisabled = true;
}
Hope any of those works out.

ExcelDNA C# Chart.MouseDown event firing only once

i'm tryng to have an handle the event every time I click on a chart, on each worksheet of an opened workbook.
I'm using the SheetActivate event like this:
private static void Xlapp_SheetActivate(Object obj_Ws)
{
myCharts.SetAllCharts((XL.Worksheet)obj_Ws);
}
to call a method every time a worksheet is activated, and then the "SetAllCharts" method in the "MyCharts" class that looks like:
internal void SetAllCharts(object obj_Ws)
{
XL.Worksheet Ws = (XL.Worksheet)obj_Ws;
XL.ChartObjects ChObj = Ws.ChartObjects();
if (ChObj.Count > 0)
{
xlapp.StatusBar = ("Setting " + ChObj.Count + " charts");
foreach (XL.ChartObject obj_Chart in ChObj)
{
XL.Chart myChart = obj_Chart.Chart;
myChart.MouseDown += myChart_MouseDown;
}
}
}
for now, the method handler (simply a xlapp.StatusBar message that reports X and Y of the click) works... only once, the first time I activate a worksheet, on the first click on a chart. After that i'm not getting the message box anymore...
What am I doing wrong??
You have to be careful with the lifetime of the COM objects (or at least the magic .NET wrappers around them) that you set event handlers on. They might be created on the fly as you enumerate a collection and garbage collected soon after, losing your event handler in the process. That's why it works once or a few times.
The test for this, before you start thinking about how to write the code, is to keep the objects in some higher object level or global list.
In your code this would be the obj_Chart object you are enumerating. Just make sure these objects are all kept alive.
(I find this stuff a bit confusing because the opposite happen with WPF - I think the event handlers prevent things from garbage collecting?)

Conflicts between 2 unit tests c# using a static class

I have conflicts between some of my unit tests.
I have a class with a static event, when I run each test one at a time I have no problem, but when I run all tests in a batch, the tests which are firing the event will crash because of the registred listeners (which have registred to the event in the previous tests).
Obviously I don't want the event handlers to be executed when the tested class fires the event, so what is the best solution ?
I know I wouldn't have the problem if the event was not static, but I would prefer not have to redesign this if there is another solution.
Detaching all the event listeners before running the test could be a solution, but I think it is impossible to do it from outside of the class (which seems normal cause we don't want a client being able to detach all other listeners), and doing it from the inside would means that I have to add a method in the class for the only purpose of the unit tests, which is as bad practice.
Is there a way to run the test in an isolation mode that would prevent other previous tests to impact it ? Like if it was run in a completely separated process so that I don't get the same reference to the static event ? (But I still need to be able to executes all tests in batch with a simple click)
Thanks for your help and ideas !
For information I am using Visual Studio 2012 unit test framework.
Somewhere within each individual test you are going to attach yourself to the static event. So simply before the assert simply detach yourself or better guard the detaching within a finally block:
[TestCase]
public void MyTestDetachingBeforeAssert()
{
bool finishedCalled = false;
var eventListener = new EventHandler((sender, e) => finishedCalled = true);
MyClass.Finished += eventListener;
// Can lead to detach problems if this throws an exception!
MyClass.DoSomething();
MyClass.Finished -= eventListener;
Assert.That(finishedCalled);
}
[TestCase]
public void MyTestDetachingInFinally()
{
bool finishedCalled = false;
var eventListener = new EventHandler((sender, e) => finishedCalled = true);
try
{
MyClass.Finished += eventListener;
MyClass.DoSomething();
Assert.That(finishedCalled);
}
finally
{
MyClass.Finished -= eventListener;
}
}

How to prevent path from being attached if condition not required? SSIS custom component

In my custom data flow component, I have overriden the OnOutputPathAttached method. I want outputs to be attached under certain conditions. ie:
public override void OnOutputPathAttached(int outputID)
{
if (/*condition*/)
{
//do some processing
base.OnOutputPathAttached(outputID);
}
else
{
System.Windows.Forms.MessageBox.Show("Error message");
//CODE TO STOP OUTPUT FROM BEING ATTACHED???
}
}
What should I put so that the output isn't attached? For now it shows the error message but still attaches the output.
I suspect that it's too late to stop the user from attaching a path by the time your OnOutputPathAttached method is called. (At least, that's how I'm reading the MSDN page on the AttachPathAndPropagateNotifications method.)
Your best bet seems to be to return VS_ISBROKEN from your Validate method, along with raising useful OnError events.

EnableRaisingEvents (enabling and disabling it)

I am maintaining some code which has two FileSystemWatcher events that makes it difficult to debug (and it has an error). So my idea is to simplify the code by making the execution sequential. Pretty much like this:
Main method
1) normal code here
2) enable event 1, let it check for files, disable it when it is done running once
3) enable event 2, let it check for files, disable it when it is done running once
Then the database logs would make more sense. I would be able to see which part of the program that is doing something wrong.
private void InitializeFileSystemWatcher()
{
this.MessageMonitor = new FileSystemWatcher(this.MessagePath, this.MessageFilter);
this.MessageMonitor.IncludeSubdirectories = true; // Recursive.
this.MessageMonitor.Created += new FileSystemEventHandler(OnMessageReceived);
this.MessageMonitor.EnableRaisingEvents = true;
}
From the main, I can set the EnableRaisingEvents=true to EnableRaisingEvents=false. Both events indexes the files in some folder and enacts a callback method.
My question is this: If the event is currently executing and I set EnableRaisingEvents=false, will it pause or continue to execute until it finishes?
If it does continue, I figure just to have a bool doRUN variable set at beginning and the end of the event as a check for the main method.
You should just detach the event handler after you check to make sure that it is working properly and then instantiate the second FileSystemWatcher.
Inside of the OnMessageReceived you could od something like
public void OnMessageRecieved(Object sender, Events e) //Not the real signature
{
MessageMonitor.Created -= OnMessageReceived();
//Do Your things
OtherMessageMonitor.Created += OnMessageReceived();
}

Categories

Resources