11

用例:用户需要能够将电子邮件项目从 Outlook 拖放到我的 WinForms (.Net 4) 应用程序中的表单上。应用程序以 .msg 格式保存这些项目并将它们存储在预定位置。

问题:我的代码对来自其他来源的拖放并不可靠(例如,将 jpeg 从 IE 拖到表单上会触发相同的事件)。这是因为我无法确定拖动的项目是否是 Outlook 对象,或者拖动的项目来自哪个源。

是否有一种解决方法,使我只能接受特定类型的拖放项目?这是我在 DragDrop 事件处理程序中的代码:

Outlook.Application outlook = new Outlook.Application();
Outlook.Selection sel = outlook.ActiveExplorer().Selection;

try
{    
    foreach (object item in sel)
    {
        if (item is Outlook.MailItem)
        {
            var mail = item as Outlook.MailItem;

            CopyMailItemToLocalTempDir(mail);

            txtComment.Text = "Email from " + mail.SenderName + " Regarding " + mail.Subject;
        }
    }
}
finally
{
    // This is hokey but it prevents Outlook from remembering previously selected items
    // - refer http://stackoverflow.com/questions/14090420/interop-outlook-doesnt-clear-selected-mails-at-drag-and-drop
    var folder = outlook.ActiveExplorer().CurrentFolder;
    outlook.ActiveExplorer().CurrentFolder = outlook.GetNamespace("MAPI").GetDefaultFolder(Outlook.OlDefaultFolders.olFolderContacts);
    Thread.Sleep(50);
    outlook.ActiveExplorer().CurrentFolder = folder;

    Marshal.ReleaseComObject(sel);
    Marshal.ReleaseComObject(outlook);
    sel = null;
    outlook = null;
}

从 Outlook 拖动时有关 DragEventArgs 对象 (e) 的一些详细信息:

e.Data.GetFormats() returns: 
{string[15]}
    [0]: "RenPrivateSourceFolder"
    [1]: "RenPrivateLatestMessages"
    [2]: "RenPrivateMessages"
    [3]: "RenPrivateItem"
    [4]: "FileGroupDescriptor"
    [5]: "FileGroupDescriptorW"
    [6]: "FileDrop"
    [7]: "FileNameW"
    [8]: "FileName"
    [9]: "FileContents"
    [10]: "Object Descriptor"
    [11]: "System.String"
    [12]: "UnicodeText"
    [13]: "Text"
    [14]: "CSV"

e.Data.GetData("Text") returns: 
"From\tSubject\tReceived\tSize\tCategories\t\r\nJoe Sender\tThis is the email subject\t10:51 AM\t3 KB\t\t"
4

2 回答 2

1

我这里有解决方案的源代码,它只允许删除 Outlook 项目。以下是事件处理程序:

private void Form1_DragEnter(object sender, DragEventArgs e)
    {
        //display formats available
        this.label1.Text = "Formats:\n";
        foreach (string format in e.Data.GetFormats())
        {
            this.label1.Text += "    " + format + "\n";
        }

        //ensure FileGroupDescriptor is present before allowing drop
        if (e.Data.GetDataPresent("FileGroupDescriptor"))
        {
            e.Effect = DragDropEffects.All;
        }
    }

    private void Form1_DragDrop(object sender, DragEventArgs e)
    {
        //wrap standard IDataObject in OutlookDataObject
        OutlookDataObject dataObject = new OutlookDataObject(e.Data);

        //get the names and data streams of the files dropped
        string[] filenames = (string[])dataObject.GetData("FileGroupDescriptorW");
        MemoryStream[] filestreams = (MemoryStream[])dataObject.GetData("FileContents");

        this.label1.Text += "Files:\n";
        for (int fileIndex = 0; fileIndex < filenames.Length; fileIndex++)
        {
            //use the fileindex to get the name and data stream
            string filename = filenames[fileIndex];
            MemoryStream filestream = filestreams[fileIndex];
            this.label1.Text += "    " + filename + "\n";

            //save the file stream using its name to the application path
            FileStream outputStream = File.Create(filename);
            filestream.WriteTo(outputStream);
            outputStream.Close();
        }
    }
于 2013-07-04T10:05:35.693 回答
1

是否有一种解决方法,使我只能接受特定类型的拖放项目?

是的,有2种方式

(使用单个文件时):

if (e.Data.GetData(typeof(...)) is ...)
    //process it

if (e.Data.GetDataPresent(typeof(...)))
    //process it

关于稳健性

由于您没有指定类型Outlook.MailItem(或可能Image)但来源:我假设您的程序在代码的其他部分失败(由于设计不良)。例如ActiveExplorer().Selection在第 2 行或finally {}零件中。这很容易通过预过滤/尝试捕获到位(在涉及 Outlook 之前)或在DragEnter事件中(当类型严格是某种类型的 Outlook 时更好)来管理。

要掌握拖放内容,请查看此

用于多文件处理

或者对于像outlook消息这样的特殊类型,你已经有了一个很好的解决方案,在你提到的文章中有很多解释。

我还找到了一个针对您的非一般(仅限 Outlook)用例(写于 2012 年)的答案,该用例展示了 OutlookDataObject类,并且可能基于您提到的文章(写于 2008 年)。

于 2020-02-16T01:36:28.247 回答