Below is my code (simplified version for readability) from a VSTO-based Word addin.
The problem is that if I have two documents open, such as documentation and a template, my addin helps develop the template and works fine until the template is closed and re-opened in the same Word instance (the documentation file kept Word alive). Once that happens the SelectionChange event is not received, even though the listener is attached (confirmed with debugger).
Is there anything wrong with this code? Any other ways to attach a selection changed event?
void Application_DocumentOpen(Word.Document Doc)
{
// this method gets called as intended
Document vstoDoc = Globals.Factory.GetVstoObject(doc);
vstoDoc.SelectionChange += new Microsoft.Office.Tools.Word.SelectionEventHandler(ThisDocument_SelectionChange);
}
private void Application_DocumentBeforeClose(Word.Document doc, ref bool Cancel)
{
// this one also gets called as intended
Document vstoDoc = Globals.Factory.GetVstoObject(doc);
vstoDoc.SelectionChange -= new Microsoft.Office.Tools.Word.SelectionEventHandler(ThisDocument_SelectionChange);
}
void ThisDocument_SelectionChange(object sender, SelectionEventArgs e)
{
// this doesn't get called if the document is closed and open again within the same Word instance
Log("Selection changed");
}
UPDATE: This seems like VSTO bug.
Attaching to other events works fine, I can use ContentControlOnEnter/Exit:
vstoDoc.SelectionChange += ThisDocument_SelectionChange; // doesn't work
vstoDoc.ContentControlOnEnter += vstoDoc_ContentControlOnEnter; // works
vstoDoc.ContentControlOnExit += vstoDoc_ContentControlOnExit; // works
Why dont you use
Globals.ThisAddIn.Application.WindowSelectionChange +=
new ApplicationEvents4_WindowSelectionChangeEventHandler(Application_WindowSelectionChange);
instead of converting your Microsoft.Office.Interop.Word.Document object to Microsoft.Office.Tools.Word.Document
Related
I'm writing Outlook VSTO add-in and I want to do size check before attachment add and if the file is too big I want to upload it to the cloud, so the code looks like:
public partial class ThisAddIn
{
private void ThisAddIn_Startup(object sender, EventArgs e)
{
Application.Inspectors.NewInspector += InspectorsOnNewInspector;
}
private void InspectorsOnNewInspector(Inspector inspector)
{
if (inspector.CurrentItem is MailItem mailItem)
{
mailItem.BeforeAttachmentAdd += MailItemOnBeforeAttachmentAdd;
}
}
private void MailItemOnBeforeAttachmentAdd(Attachment attachment, ref bool cancel)
{
// check and upload
cancel = true;
}
private void ThisAddIn_Shutdown(object sender, EventArgs e)
{
// Note: Outlook no longer raises this event. If you have code that
// must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
[SuppressMessage("ReSharper", "ArrangeThisQualifier")]
[SuppressMessage("ReSharper", "RedundantDelegateCreation")]
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
The problem is that all works fine until the file exceeds the size limit configured in MS Exchange. When it happens I get a notification message and after clicking "OK" mailItem.BeforeAttachmentAdd event doesn't fire. How can I deal with it?
None of your event handlers will work for more than a few seconds - you are setting the event handler either on a temporary variable (created by the compiler) in case of Application.Inspectors.NewInspector or on a local variable (when you set mailItem.BeforeAttachmentAdd event handler).
The object raising the events must be alive - store these objects on the global (class) level to make sure they are not collected by the Garbage Collector.
Also, there is no particular / guaranteed order of events, but I would imagine Outlook would always get the first pick. Worst case, you can patch IDropTarget implementation of the Outlook window and provide your own implementation. Not much you can do if an attachment is being inserted from the Ribbon...
I am developing a VSTO application for PowerPoint using C#. The goal is to export the selected slide of the opened PowerPoint presentation to PNG file on user's computer every 5 seconds.
PowerPoint API provides the following way to export the slide:
(Slide)Application.ActiveWindow.View.Slide.Export("D:/path", "png")
However, every time this method is called, PowerPoint window freezes (maybe deactivates?) for a split second, and because of this any expanded menus get closed (for example, the menu opened by right-clicking on a slide, menu for inserting shapes, etc.)
I am looking for a way to avoid this. Is there a way to fix this issue when using Slide.Export method? Or maybe there are some alternatives to using it?
I tried using custom libraries like Aspose.Slides, and they can fix this issue, but cause an even worse one: they can't access the Presentation object presented by PowerPoint assembly, so in order to use them on your assembly, you would have to save a copy to the computer and open it, which is a bad solution in my case.
Any ideas on how to fix my issue will be very helpful.
Edit: to reproduce the issue, create a VSTO add-in project for PowerPoint and replace ThisAddIn with the following code:
public partial class ThisAddIn
{
public Form form = new Form
{
Opacity = 0.01,
Visible = false,
};
delegate void InvokeEventHandler();
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
form.Show();
var del = new InvokeEventHandler(() => Timer_Tick());
form.Invoke(del);
var timer = new System.Timers.Timer();
timer.Interval = 5000;
timer.Elapsed += (s, ea) => form.Invoke(del);
timer.Start();
}
private void Timer_Tick()
{
try
{
var slide = (Slide)Application.ActiveWindow.View.Slide;
slide.Export(Path.Combine(Path.GetTempPath(), "test"), "png");
}
catch
{
return;
}
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
When PowerPoint opens, right-click on a slide and wait for a couple of seconds. When timer ticks, the menu will be closed.
The specified graphics format must have an export filter registered in the Windows registry. You can specify either the registered extension or the registered filter name. Microsoft PowerPoint will first search for a matching extension in the registry. If no extension that matches the specified string is found, PowerPoint will look for a filter name that matches.
Try using the JPG file format instead:
With Application.ActivePresentation.Slides(3)
.Export "c:\my documents\Graphic Format\" & _
"Slide 3 of Annual Sales", "JPG"
End With
I am writing a VSTO C# code that would copy the content of active projects in Visual Basic editor in any Office application and process it following some rules. The AddIn adds a button to the VBE toolbar and an event for a click.
When debugging, it works fine the first couple of times (between 8 and 12) I click the button but then it just stops responding to the clicks. Restarting the application does not help, but repeat debugging does (again, for the first 8 - 12 clicks).
I experimented with the code and found that it behaves this way whenever the code uses Regex, even something rather basic. Any ideas what may be going wrong?
This piece of code is for the illustration only. All it is supposed to do is to produce a message box "OK" after it applies Regex to each code module content. And so it does - for the first 8 to 12 times. After that, the button clicks produce no response whatsoever.
No error messages are shown, except when it is building the solution, among many lines it shows Exception thrown: 'System.Deployment.Application.DeploymentException' in System.Deployment.dll, which does not seem to affect the program during the first clicks.
using Office = Microsoft.Office.Core;
using VBA = Microsoft.Vbe.Interop;
using System.Text.RegularExpressions;
namespace CodeControl
{
public partial class ThisAddIn
{
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
AddButton();
}
public void AddButton()
{
Office.CommandBar cbr = Globals.ThisAddIn.Application.VBE.CommandBars["Edit"];
Office.CommandBarButton button = cbr.Controls.Add(Type: 1, Temporary: true).Control;
button.FaceId = 10;
button.Visible = true;
Globals.ThisAddIn.Application.VBE.Events.CommandBarEvents[button].Click +=
new VBA._dispCommandBarControlEvents_ClickEventHandler(DoWork);
}
void DoWork(object CommandBarControl, ref bool handled, ref bool CancelDefault)
{
foreach (VBA.VBComponent component in Globals.ThisAddIn.Application.VBE.ActiveVBProject.VBComponents)
{
VBA.CodeModule module = component.CodeModule;
if (module.CountOfLines < 4)
continue;
string text = module.Lines[1, module.CountOfLines];
foreach (string lineText in Regex.Split(text, #"(?:\r\n|\n|\r)"))
Console.WriteLine(lineText);
System.Windows.Forms.MessageBox.Show(module.Name);
}
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e){}
#region VSTO generated code
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
Hello, I am building windows C# WPF application which communicates with Microsoft Office word document (.docx). The app should update .docx template file with user input and this step is achived successfuly using OpenXML. The other part of the app is to show the edited word document to the user inside of the applicaion window or using MS Word and allow him to add some more information if he wants to do it. The problem I am facing is:
I should disable my application controls while word document is opened and I should enable them once the word is closed, also I want to know if the word app was saved (if a user made changes). The next code is button click event for openning word document:
using System.Windows;
using Microsoft.Office.Interop.Word;
using Application = Microsoft.Office.Interop.Word.Application;
public class MainWindowViewModel : BaseViewModel
{
...
... some view model initialization
...
public bool AreControlsEnabled { get; set; } = true;
private void OpenWord ()
{
AreControlsEnabled = false;
var app = new Application()
{
Visible = true
};
var doc = app.Documents.Open("pathtofile.docx");
var docClass = app.ActiveDocument as DocumentClass;
docClass.DocumentEvents2_Event_Close += DocClass_DocumentEvents2_Event_Close;
docClass.DocumentEvents_Event_Close += DocClass_DocumentEvents_Event_Close;
app.DocumentBeforeClose += new ApplicationEvents4_DocumentBeforeCloseEventHandler(DocBeforeClose);
app.DocumentBeforeSave += new ApplicationEvents4_DocumentBeforeSaveEventHandler(DocBeforeSave);
}
private void DocClass_DocumentEvents2_Event_Close ()
{
MessageBox.Show("DocClass_DocumentEvents2_Event_Close");
AreControlsEnabled = true;
}
private void DocClass_DocumentEvents_Event_Close ()
{
MessageBox.Show("DocClass_DocumentEvents_Event_Close");
AreControlsEnabled = true;
}
private void DocBeforeClose (Document doc, ref bool cancel)
{
MessageBox.Show("DocBeforeClose");
AreControlsEnabled = true;
}
private void DocBeforeSave (Document doc, ref bool SaveAsUI, ref bool cancel)
{
MessageBox.Show("DocBeforeSave");
AreControlsEnabled = true;
}
}
When I run the code - I see opened MS Word document as expected, but when I close it or save - no one of events fired and I can't understand why. Also, I can use System.Diagnostics.Process to launch the Word and add exit event to it, but in this way I can't know if the user applied some changes. So, if someone solved this problem, help me please. Thank you for reading and answers
You can:
Get the Current Changed Date of the File
Use System.Diagnostics.Process to start Word.
After The process ends you check the Changed Date again
If the user saved the file the Changed Date is updated
I don't know if the process is still running if the user just closes the document but not word. For this you could observe the Folder of the Dokument for thos ~... Temp Files Word creates while a document is open...
For some reason in my app my FolderSwitch works on the main Explorer that opens with the application but the NewExplorer event never fires, so obviously the FolderSwitch event won't fire on a new Explorer.
I can't work out why the event doesn't fire.
private List<_Outlook.Explorer> ListOfExplorerWindows = new List<_Outlook.Explorer> { };
private _Outlook.Application Application;
public void OnConnection(object Application, Extensibility.ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
{
this.Application = (_Outlook.Application)Application;
}
public void OnStartupComplete(ref Array custom)
{
_Outlook.Explorer Explorer = this.Application.ActiveExplorer();
Explorer.FolderSwitch += new _Outlook.ExplorerEvents_10_FolderSwitchEventHandler(Explorer_FolderSwitch);
ListOfExplorerWindows.Add(Explorer);
this.Application.Explorers.NewExplorer += new _Outlook.ExplorersEvents_NewExplorerEventHandler(Explorers_NewExplorer);
}
private void Explorers_NewExplorer(_Outlook.Explorer Explorer)
{
Explorer.FolderSwitch += new _Outlook.ExplorerEvents_10_FolderSwitchEventHandler(Explorer_FolderSwitch);
ListOfExplorerWindows.Add(Explorer);
}
For any events you want to keep around when using VSTO, you are required to keep around a class-level member (Explorer, Application, Inspector, CommandBar, etc.) to keep the GC Thread from removing them. This is a resource optimization, but can also be a painful lesson to learn.
See related MSDN Forum post regarding event lifetime or similar SO post.