I’ve been using Twitter and one of the things that I followed recently was the Silverlight forums and that caused a question to bob up on my screen just yesterday;
I haven’t replied back to the original poster as I don’t imagine that I’ve got the solution to his particular problem but it occurred to me that with Silverlight 4, reaching into an application like Outlook to use a little bit of functionality is exactly the kind of scenario that you can tackle with COM interop so that sparked my interest in experimenting with it.
It feels like there’s a few possibilities around how you might do this with Silverlight 4;
- Staying within the sandbox you could try and do drag-and-drop from Outlook to Silverlight.
- I don’t think you can do a straight drag-drop because I don’t think Silverlight sees that as a file drop.
- I suspect you’d have to drag to desktop and then drag the resultant file to the Silverlight app.
- To do (2) and stay in the sandbox, you’d have to unpick the binary Outlook message format yourself which wouldn’t be much fun unless there’s some way to get Outlook to save a message as XML ( I haven’t found that yet ).
- Leaving the sandbox, with an out of browser “trusted” application you could;
- Attempt to do 1.1 and 1.2 above but ask Outlook to decipher the Outlook .msg file for you
- Read the email details from Outlook in the first place – that is, pop up a dialog in Silverlight which shows the user their Outlook email so that they don’t have to drag and drop.
I decided to experiment with 2.2.
I wrote a little app, it’s should be running below if I can figure out where to drop it onto my website. If you’re on the Silverlight 4 beta you can click it to install it locally ( if you’re not on the beta you’ll perhaps get a white rectangle or, hopefully, a Silverlight logo );
- FirstName
- LastName
- ContractStartDate
- ContractDuration
- Correspondence which is a list of Email which is
- From
- To
- Subject
- Body
void GetEmails() { // TODO - this is ugly, especially the reach into the application for its // dispatcher but the Outlook code is slow for me so I feel the need to // move the whole thing to another thread. // TODO - this code needs moving into some email service outside of this VM. Dispatcher dispatcher = Application.Current.MainWindow.Dispatcher; this.Loading = true; ThreadPool.QueueUserWorkItem(o => { dynamic outlook = ComAutomationFactory.CreateObject("Outlook.Application"); dynamic inbox = outlook.GetNamespace("Mapi").GetDefaultFolder(olFolderInbox); int itemCount = inbox.Items.Count; for (int i = 1; i <= itemCount; i++) { Email newEmail = new Email() { Subject = inbox.Items[i].Subject, Body = inbox.Items[i].Body, From = inbox.Items[i].SenderName, To = inbox.Items[i].To }; newEmail.Body = newEmail.Body.Substring(0, Math.Min(30, newEmail.Body.Length)); dispatcher.BeginInvoke(() => { this.Emails.Add(newEmail); }); } dispatcher.BeginInvoke(() => this.Loading = false); }); }
- How to try and deal with ChildWindow from an MVVM perspective. I jump through a hoop or two in that;
- I want to put up the ChildWindow and then ask it for a list of attached emails when it is dismissed.
- Dismissing the ChildWindow is done via the “Close” button click which is handled on the ViewModel.
- In order for the ViewModel to close the ChildWindow it needs to call ChildWindow.Close() but then the ViewModel doesn’t know what a ChildWindow is so it’s a bit tricky for it to do that.
- In the end;
- I defined some interface ICloseableWindow that has a Close member on it and I implemented that on my ChildWindow
- I passed the ChildWindow as a command parameter to the bound command on the ViewModel.
- In the handler on the ViewModel, I test for ICloseableWindow and ask it to Close itself.
- This way I felt that the ViewModel is still reasonably independent because all it knows about is ICloseableWindow.
- How to deal with the Outlook email enumeration code taking quite a long time.
- I dealt with this by moving it to another thread but that introduced a dependency for my ViewModel to get back to the UI thread.
- I haven’t got any IoC container in here but I could have addressed the previous point (2.1) by asking for some “IInvokeUIService” on an IoC container and then using that to get back to the UI thread rather than reaching directly into Application.Current.MainWindow as I do above.
If you want to take a look, here’s the source code for download – note that I spent a couple of hours with it so it’s not very polished but if it helps you with something you’re doing then that’s great.