如何将Outlook邮件拖放到richTextBox中

4
我有一个WinForms应用程序的问题;我想要将Outlook邮件拖放到RichTextBox中。我找到了许多关于拖放功能的文章,但它们都将Mailtext插入到rTB中(参见:链接)。实际上,我可以将桌面上的文档(如.txt、.jpg、Outlook邮件)插入到我的程序中。我的richTextBox会自动生成文件的图像,并将此图像插入到位置上。例如:

rTB

用户拖放文件后,图像将在放置位置创建,如果用户双击图像,则文件将被打开。

问题:

程序工作正常,但是如果我尝试从Outlook中拖动邮件,则程序会将邮件正文插入到richTextBox中,而不是作为图像。

我在桌面上保存了一封邮件并尝试将该邮件插入到我的程序中。我的richTextBox中输出以下内容(完美):

来自桌面的Mailicon通过拖放:

MailIconfromdesk

否则,我试图从Outlook中拖放邮件,我的程序会输出以下内容(只看文本而不是图片):

通过Outlook拖放的邮件(问题!): InsertFromOutlook

程序将cc/mail地址和邮件正文插入到rTB中。

这是代码后面的部分:(我的richTextBox是一个名为"MyRichTextBox"的自己创建的richTextBox,请在此处下载项目:link_RICHTEXTBOX。)

    private void Form1DragDrop(object sender, DragEventArgs e)
            {
                Startup();
               //Microsoft.Office.Interop.Outlook.ApplicationClass oApp =
               //      new Microsoft.Office.Interop.Outlook.ApplicationClass();
               Microsoft.Office.Interop.Outlook.Explorer oExplorer = _Outlook.ActiveExplorer();
               Microsoft.Office.Interop.Outlook.Selection oSelection = oExplorer.Selection;

               foreach (object item in oSelection)
               {
                   Microsoft.Office.Interop.Outlook.MailItem mi = (Microsoft.Office.Interop.Outlook.MailItem)item;

                   rTB_test.Text = mi.Body.ToString();

                    string mailName = "Mail\n" + (mailList.Count + 1);
                    // load an image with enough room at the bottom to add some text:
                    Image img = Image.FromFile(Imagepath);
                    // now we add the text:
                    int width = img.Width;
                    using (Graphics G = Graphics.FromImage(img))
                    using (Font font = new Font("Arial", 7f))
                    {
                        SizeF s = G.MeasureString(mailName, font, width);
                        G.DrawString(mailName, font, Brushes.Black, 
                            (width - s.Width) / 2, img.Height - s.Height - 1);

                    }
                    // adding the image is easy only if we use the clipboard..
                    Clipboard.SetImage(img);
                    // now insert image
                    rTB_test.Paste();
                    // now we can get a hashcode as a unique key..
                    // ..we select the image we have just inserted:
                    rTB_test.SelectionStart = rTB_test.TextLength - 1;
                    rTB_test.SelectionLength = 1;
                    // finally we need to store the mail itself with its key:
                    mailList.Add(rTB_test.SelectedRtf.GetHashCode(), mi);   
                    // cleanup: unselect and set cursor to the end:
                    rTB_test.SelectionStart = rTB_test.TextLength;
                    rTB_test.SelectionLength = 0;
            }
        Microsoft.Office.Interop.Outlook.Application _Outlook = null;

        Dictionary<int, Microsoft.Office.Interop.Outlook.MailItem> mailList =
  new Dictionary<int, Microsoft.Office.Interop.Outlook.MailItem>();

        private void rTB_test_DoubleClick(object sender, EventArgs e)
        {
            var ss = rTB_test.SelectionStart;
            var sl = rTB_test.SelectionLength;
            int hash = rTB_test.SelectedRtf.GetHashCode();
            // a few checks:
            if (sl == 1 && mailList.Keys.Contains(hash))
            {
                Microsoft.Office.Interop.Outlook.MailItem mi = mailList[hash];
                // do stuff with the msgItem..
                // ..
            }
        }

        void lbl_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Microsoft.Office.Interop.Outlook.MailItem mi =
              (Microsoft.Office.Interop.Outlook.MailItem)((Label)sender).Tag;
            // code to process the doubleclicked mail item..
        }

        void Startup()
        {
            _Outlook = new Microsoft.Office.Interop.Outlook.Application();
        }

        private void Form1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }

用户双击图片后,应该在Outlook浏览器中打开邮件。
更新:如果我使用TaW答案中的代码,则会输出以下内容:
在我双击图标后,邮件不会被打开...所以答案中的代码只是"图标创建"。
感谢您的支持!

RTB中的图像很麻烦。为什么不使用FlowLayoutPanel,您可以在其中插入一个动态创建的Label,并将邮件放在其标记中..?它可以轻松地显示文本和图像! - TaW
问题是:我使用自己创建的rTB。所以我无法切换到流式布局面板...我知道这个问题是可以解决的。我的问题是:程序插入了邮件正文而不是图片! - Xeidos
看到已更正的更新! - TaW
我的代码按照要求创建了图标,并允许您在双击时访问邮件项。由于我没有在任何机器上安装Outlook,因此未提供打开它的代码。也许mi.Display();可以完成工作... - 看起来您没有删除显示正文文本的旧代码?带有“测试”文本的两个或三个(?)图标是什么?它们看起来与您之前展示的图标完全不同?而且它们看起来像是悬停在文本上方? - TaW
哦,完全正确!我忘记在你的图片中注释“标签函数”了! - Xeidos
显示剩余2条评论
1个回答

1

以下是我在评论中所指的内容:

private void Form1DragDrop(object sender, DragEventArgs e)
{
   Startup();
   Microsoft.Office.Interop.Outlook.ApplicationClass oApp = 
         new Microsoft.Office.Interop.Outlook.ApplicationClass();
   Microsoft.Office.Interop.Outlook.Explorer oExplorer = _Outlook.ActiveExplorer();
   Microsoft.Office.Interop.Outlook.Selection oSelection = Explorer.Selection;

   foreach (object item in oSelection)          
   {
       Microsoft.Office.Interop.Outlook.MailItem mi = 
        (Microsoft.Office.Interop.Outlook.MailItem)item;
      //    rTB_test.Text = mi.Body.ToString();
      Label lbl = new Label();
      lbl.AutoSize = false;
      lbl.Size = new Size( 80, 50);         // <-- your choice!
      lbl.Text = someText;                 // <-- your choice!
      lbl.TextAlign = ContentAlignment.BottomCenter;
      lbl.Image = someImage;             // <-- your choice!
      lbl.ImageAlign = ContentAlignment.TopCenter;
      int count = rTB_test.Controls.Count;
      int itemsPerRow = rTB_test.Width / 80;
      lbl.Location = new Point( (count % itemsPerRow) * 80, 
                                 count / itemsPerRow * 50); 
      lbl.Tag = mi;               // store the data object
      lbl.MouseDoubleClick += lbl_MouseDoubleClick;
      lbl.Parent = rTB_test;     // add to the RTF's Controls
   }
}

void lbl_MouseDoubleClick(object sender, MouseEventArgs e)
{
   Microsoft.Office.Interop.Outlook.MailItem mi = 
     (Microsoft.Office.Interop.Outlook.MailItem) ( (Label)sender).Tag;
   // code to process the doubleclicked mail item..
}

这些标签将会覆盖 RTB 中任何文本而不会干扰它。如果您想的话,可以修改位置代码以将其移开或以许多其他方式样式化标签。 更新 在最后的评论后,问题变得更加清晰:应用程序的其他部分已经在向 RTB 中添加邮件图标,我们需要添加更多“同样的”内容。
最好通过剪贴板添加图像;以下是可以实现此操作的代码:
// create some test text, maybe extract it from the mailheader?..
string mailName = "Mail\n" + (mailList.Count + 1);
// load an image with enough room at the bottom to add some text:
Image img = Image.FromFile(yourMailImageFile);
// make the images unique by embedding a counter in a bright pixel:
img = (Image)fingerPrintID((Bitmap)img, 250 - mailList.Count);      //*1*
// now we add the text:
int width = img.Width;
using (Graphics G = Graphics.FromImage(img))
using (Font font = new Font("Arial", 7f))
{
    SizeF s = G.MeasureString(mailName, font, width);
    G.DrawString(mailName, font, Brushes.Black, 
        (width - s.Width) / 2, img.Height - s.Height - 1);

}
// adding the image is easy only if we use the clipboard..
Clipboard.SetImage(img);
// insert only at the end!        
rTB_test.SelectionStart = rTB_test.TextLength;
rTB_test.SelectionLength = 0;
// now insert image
rTB_test.Paste();
// now we can get a hashcode as a unique key..
// ..we select the image we have just inserted:
rTB_test.SelectionStart = rTB_test.TextLength - 1;
rTB_test.SelectionLength = 1;
// retrieve the counter id:
string id = GetID(rTB_test.SelectedRtf);    //*2*
// finally we need to store the mail itself with its key:
mailList.Add(id, mi);   
// cleanup: unselect and set cursor to the end:
rTB_test.SelectionStart = rTB_test.TextLength;
rTB_test.SelectionLength = 0

我们需要创建一个字典来存储我们的邮件:
Dictionary<string, Microsoft.Office.Interop.Outlook.MailItem> mailList = 
  new Dictionary<string, Microsoft.Office.Interop.Outlook.MailItem>();  // *3*

以下是如何在DoubleClick事件中访问邮件的方法:
private void rTB_test_DoubleClick(object sender, EventArgs e)
{
    var ss = rTB_test.SelectionStart;
    var sl = rTB_test.SelectionLength;
    string id = GetID(sr);  //*4*
    // a few checks:
    if (sl == 1 &&  mailList.Keys.Contains(id) && sr.Contains(@"{\pict\") )
    {
       Microsoft.Office.Interop.Outlook.MailItem mi = mailList[id]; 
       // do stuff with the msgItem, e.g..
       mi.Display();

    }
}

这是与我使用的图片一起的结果:

enter image description here mail

请注意,除了添加图片之外,我们还在字典中存储了邮件数据和RTB中图像的位置。

更新2: 我们用RtfText的HashCode替换了图像位置作为键;这对RTF内容的任何更改都很鲁棒。但是,它依赖于图像是唯一的,因此建议像代码中那样为其文本添加索引(或基于GUID设置一些随机像素)。

更新3和4: (*1* - *6*)

我们发现需要使键具有弹性,以适应多个变化,例如围绕图标的字体,这会影响Rtf代码,或用户放大图像等。

以下是一个FingerPrint函数,通过在图像顶部设置几个像素来使我们添加的图片不显眼且独特。设置三个标记和一个ID:

Bitmap fingerPrintID(Bitmap bmp, int key)  //*5*
{
    for (int i = 0; i < 3; i++)
    {
        bmp.SetPixel(i, 0, Color.FromArgb(255, 238,238,238)); // EE EE EE
    }
    bmp.SetPixel(3, 0, Color.FromArgb(255, key, key, key));
    return bmp;
}

要检索此功能,将从RTF代码中提取3个十六进制数字作为字符串:

string GetID(string Rtf)   //*6*
{
    int x = Rtf.IndexOf("eeeeeeeeeeeeeeeeee");  // 238 238 238
    if (x < 0) return "";
    string hex = Rtf.Substring(x +18, 6);
    return hex;
}

我选择像素要相当明亮; 如果你知道你使用的图像,你可以更进一步优化颜色选择。有了新的字符串ID,我们不需要调用GetHashCode。


  1. RTB中还应该包含什么?文本?格式化文本?
  2. 图像中的那些第一封邮件是如何进入RTB的?其他代码?
- TaW
不,如果用户从Outlook拖动邮件到rTB中,则程序应该创建一个像我在问题中说的那样的图标/图像。如果用户双击图标,则应打开邮件。我的程序运行良好,但是如果我将邮件拖到它上面,则整个邮件正文将被插入程序中,而不是像桌面文件一样插入图像。 - Xeidos
是的,还有一些其他的代码,它们将这些图标添加到rTB中。但我不能将整个项目添加到此线程中... - Xeidos
当然。顺便说一下:我已经找到了一种使链接更加健壮的方法。它涉及使用从RtfText生成的HashCode作为字典中的键。在双击时很容易获得,但在添加邮件时也同样容易(通过选择最后一个文本位置)。如果你需要帮助,我们可以明天再谈。 - TaW
让我们在聊天中继续这个讨论 - TaW
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接