views:

621

answers:

3

Hello,

I'm developing an application that needs to perform some processing on the user's Outlook contacts. I'm currently accessing the list of Outlook contacts by iterating over the result of MAPIFolder.Items.Restrict(somefilter), which can be found in Microsoft.Office.Interop.Outlook.

In my application, my user needs to choose several contacts to apply a certain operation on. I would like to add a feature that will allow the user to drag a contact from Outlook and drop it on a certain ListBox in the UI (I work in WPF but this is probably is more generic issue).

I'm very new to C# and WPF - how can I:

  1. Receive a dropped item on a ListBox
  2. Verify it's a ContactItem (or something that wraps ContactItem)
  3. Cast the dropped item to a ContactItem so I can process it

Thanks

A: 

What you could probably do is accept the drag and drop event in your .wpf app and then get the selected item(s) from outlook and pull them into your application.

Update

Add the Outlook PIA references to you app.

Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.Explorer activeExplorer = app.ActiveExplorer();
Microsoft.Office.Interop.Outlook.Selection currentSelection = activeExplorer.Selection;

Then you can iterate over the currentSelection collection to see what the user has dragged over.

76mel
I don't understand this solution. In the drop event I receive a DataObject. What does it mean "selected item(s) from Outlook"? There may be multiple open windows with multiple selections, all may be relevant contacts... No?
Roee Adler
When I tried this I was not able to get the item from the DataObject directly. So in the event I would look at outlook Explorer.Selection which contains the selected item(s) in the current view. I would then get the property information from each of the items
76mel
@76mel: could you please paste some example code?
Roee Adler
+3  A: 

Hello,

I tried this with a TextBox (no difference with a ListBox in practice).

Summary :

Searching in all outlook contacts for the one recieved dragged as text. The search here is based on the person's FullName.

condition(s):

When you drag a contact, it must show the FullName when selected in outlook. The only catch is when two persons have the same full names!! If it's the case you can try to find a unique identifier for a person by combining ContactItem properties and searching them in the dragged text.

private void textBox1_DragDrop(object sender, DragEventArgs e)
{
    if (e.Data.GetData("Text") != null)
    {                
        ApplicationClass app;
        MAPIFolder mapif;
        string contactStr;

        contactStr = e.Data.GetData("Text").ToString();

        app = new ApplicationClass();                

        mapif = app.GetNamespace("MAPI").GetDefaultFolder(OlDefaultFolders.olFolderContacts);                

        foreach (ContactItem tci in mapif.Items)
        {
            if (contactStr.Contains(tci.FullName))
            {
                draggedContact = tci; //draggedContact is a global variable for example or a property...
                break;
            }                    
        }

        mapif = null;

        app.Quit;
        app = null;
        GC.Collect();
    }
}

of course this code is to be organized-optimized, it's only to explain the method used.

You can try using the Explorer.Selection property combined with GetData("Text") [to ensure it's coming from Outlook, or you can use GetData("Object Descriptor") in the DragOver Event, decode the memory stream, search for "outlook", if not found cancel the drag operation] And why not drag multiple contacts!

private void textBox1_DragDrop(object sender, DragEventArgs e)
{
    if (e.Data.GetData("Text") != null)
    {
        ApplicationClass app;
        Explorer exp;
        List<ContactItem> draggedContacts;                
        string contactStr;

        contactStr = e.Data.GetData("Text").ToString();

        draggedContacts = new List<ContactItem>();

        app = new ApplicationClass();
        exp = app.ActiveExplorer();
        if (exp.CurrentFolder.DefaultItemType == OlItemType.olContactItem)
        {
            if (exp.Selection != null)
            {
                foreach (ContactItem ci in exp.Selection)
                {
                    if (contactStr.Contains(ci.FullName))
                    {
                        draggedContacts.Add(ci);
                    }
                }
            }
        }

        app = null;
        GC.Collect();
    }
}
najmeddine
Interesting solution, thanks. Several comments: 1) the machines that are supposed to run my software have 2000+ contacts, which probably means each drop event will take several seconds; 2) it's problematic to isolate a unique field. FullName is not necessarily unique as you mentioned, in which case fall-backs will be required (e.g. what if both contacts having the same name don't have e-mails defined? etc). So it sounds like a regression over all the fields (if-else chain) to try find the "tie-braker". Again, thanks.
Roee Adler
added an alternate solution using ActiveExplorer.Selection.
najmeddine
Regarding the selection, I would like to ask the same question I asked Damien: what happens if I have multiple Outlook-related windows open? E.g. the main contacts folder is open, and an additional e-mail screen. If I have a contact selected in the main contacts screen, but I drag a contact from the e-mail screen (e.g. from the "From" clause) - which will be received as the selected by my software?
Roee Adler
It's not well documented. I've done tests and I found out that when you drag a contact from an open e-mail screen, you have to check ActiveInspector.CurrentItem,cast to MailItem if possible,search in it's sender-recipents for the fullName recieved (contactStr). At the same time, if you have a contact selected in the Contacts screen, ActiveExplorer.Selection = this contact. I propose:-Dragged contact FullName->ContactStr-Search for it in the sender-recipients of ActiveInspector and ActiveExplorer.Selection, it narrows very well the search list comparing to the first method. I hope this help.
najmeddine
@najmeddine: many thanks, you really deserve the bounty
Roee Adler
@Rax Olgud: you're welcome.
najmeddine
+1  A: 

An Outlook contact, when dropped, supports the following formats:

(0): "RenPrivateSourceFolder"
(1): "RenPrivateMessages"
(2): "FileGroupDescriptor"
(3): "FileGroupDescriptorW"
(4): "FileContents"
(5): "Object Descriptor"
(6): "System.String"
(7): "UnicodeText"
(8): "Text"

The most interesting looking one on that list (for me) is Object Descriptor, which then led me to someone with a similar sounding problem:

http://bytes.com/topic/visual-basic-net/answers/527320-drag-drop-outlook-vb-net-richtextbox

Where it looks like in that case, they detect that it's an Outlook drop, and then use the Outlook object model to detect what's currently selected, with the implication that that must be the current drop source.

Damien_The_Unbeliever
@Damien: what happens if I have multiple Outlook-related windows open? E.g. the main contacts folder is open, and an additional e-mail screen. If I have a contact selected in the main contacts screen, but I drag a contact from the e-mail screen (e.g. from the "From" clause) - which will be received as the selected by my software?
Roee Adler
Damien_The_Unbeliever