4

I got a problem with my WinForms-Application; I want to Drag&Drop a Outlook Mail into a RichTextBox. I found many articles about the Drag&Drop function but they all insert the Mailtext into the rTB (see: Link).Actually I can insert document like .txt, .jpg, Outlook-mails from desktop... to my program. My richTextBox automatic generate an image for the file and insert this image on a position. Like:

rTB.

After the user Drag and Drop the file a image will be created on the Drop position and if the user double click the image the file will be opened.

PROBLEM:

The program work fine, but if I try to drag a mail out of Outlook, the program insert the mailbody to the richTextBox and no as an image.

I have saved one Mail on the desktop and try to insert this mail to my program. The following output is given in my richTextBox (would be perfect):

Mailicon from desktop per Drag&Drop:

MailIconfromdesk

Otherwise I tried to Drag&Drop a mai from Outlook to my program and the following output is given (Just look at the text and not the images:

Mail from Outlook per Drag&Drop (THE PROBLEM!!!): InsertFromOutlook

The Programm insert the cc/mailadress and Mailbody to the rTB.

Here is the code behind: (My richTextBox is a own created richTextBox called "MyRichTextBox" Download the project under: link_RICHTEXTBOX. )

CODE

    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;
        }

After the user double click on the picture the mail should be opened in Outlookexplorer.

UPDATE

If I use the code from TaW´s answer the following output is given:

DragDropfromOutlook

After I double click the icon the mail won´t be open... So the code from the answer is just a "iconcreation". Thank you in advanced!

Community
  • 1
  • 1
Xeidos
  • 342
  • 2
  • 14
  • Images in a RTB are a pain.. Why not use a FlowLayoutPanel where you can insert a dynamically created, say Label with the Mail in its Tag..? It can easily display text and an Image along with it! – TaW Jan 19 '15 at 17:00
  • The problem is: I use a own created rTB. So I can´t switch to flow Layout Panel... I know the problem is solveable. My problem is: The program insert the mailbody and not the image! – Xeidos Jan 19 '15 at 20:44
  • Well, ok. But my suggestion still applies: Don't try to work with the RTB.Text! An RTB is a Control and has a `Controls` collection. Add a nice, dynamically created `Label`, code its `Doubleclick`event (by a Lambda) and you're done.. Of course you can find how to insert an Image (usually via the Clipboard, aarrgh..!) but I see no good reason to do so.. – TaW Jan 19 '15 at 22:36
  • See the corrected update! – TaW Jan 20 '15 at 20:07
  • My code creates the icon as requested and lets you access them mailItem in a double click. Code for open it is not provided as I don't have outlook installed on any machine. Maybe `mi.Display();` will do the job.. - Looks like you have not deleted the old code which displays the body text? What are the two or three (?) Icons with 'Test' as their text? They don't look anything like the icons you shown before? Also they look as if they are hovering above the text? – TaW Jan 21 '15 at 13:37
  • Ohhh, totally true! I forgot to comment the "label-funktions" from you in the picture! – Xeidos Jan 21 '15 at 13:39
  • Done... So now the program just generate icons like in the answer showen. – Xeidos Jan 21 '15 at 13:41

1 Answers1

1

Here is what I meant in my comments:

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..
}

These Labels will sit on top of any Text in the RTB without interfering with it. If you want to, you can modify the code for the Location to move them out of the way or style the Labels in many other ways..

Update

After the last remarks the problem get a lot clearer: other parts of the application are already adding mail icons to the RTB and we shall add more 'of the same'..

Adding an Image is best done via the clipboard; here is code that will do that:

// 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

We need to create a Dictionary to store our mails:

Dictionary<string, Microsoft.Office.Interop.Outlook.MailItem> mailList = 
  new Dictionary<string, Microsoft.Office.Interop.Outlook.MailItem>();  // *3*

Here is how we can access the mails in the DoubleClick event:

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();

    }
}

Here is the result along with the image I use:

enter image description here mail

Note that in addition to adding the image we also store the both the mail data and the position of the image in the RTB in a Dictionary.

Update 2: I have replaced the position of the image as key with a HashCode of its RtfText; this is robust to any changes in the rest of the RTF's content. However, it relies on the images being unique, so adding an index to their text as in the code is recommended. (Or setting a few random pixels, maybe based on a GUID..)

Update 3 & 4: (*1* - *6*)

We found that we need to make the key resilient to several changes, like fonts surrounding the icon, which will influence the Rtf code, or the user enlarging the image.

Here is a FingerPrint function, which will make the images we add in unobtrusivly unique by setting a few pixels at the top of the image. Three to set a marker and one to set an 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;
}

And to retrieve this function will pull the 3 hex digits as string from the RTF code:

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;
}

I chose the pixels to be rather bright; if you know which image you use, you can optimze the color choice even more.. With the new string id, we don't need the GetHashcode calls..

TaW
  • 53,122
  • 8
  • 69
  • 111
  • The code dosn´t solve my problem! I can insert Images from a File, but got one problem with the Outlook mails. If I try to Drag Drop the Outlook mail the programm insert the mail body and not a image as usual. – Xeidos Jan 20 '15 at 11:40
  • I don't understand you. What program would insert an Image (an Image of what??) when you drag an e-mail onto it?? Do you mean an icon as a stand-in for the mail? If so, that's what the code does. Or are you talking about images inside the mail? If so, it will be up to you to extract them.. If you want help you need to be clear and precise! – TaW Jan 20 '15 at 12:17
  • 1) What else shall be in the RTB? Text? Formatted text? - 2) How do those first mails in the images get into the RTB? Some other code? – TaW Jan 20 '15 at 15:47
  • No, if the user Drag a mail from Outlook into the rTB the programm should create a icon/image like i said in the question. If the user double click on the icon the mail should be opened. My program works fine but if I Drag a mail to it the full mailbody will be insert into the program and not a image like from desktop files. – Xeidos Jan 20 '15 at 15:49
  • Yeah there is some other code... its a own project called: MyRichTextBox... But the project is really big so i cant upload it to stackoverflow. If you want I can load it up to an extern server so you can download it. – Xeidos Jan 20 '15 at 15:50
  • Here is the downloadlink for the ExtendRichTextBox: http://www.megafileupload.com/en/file/600805/MyExtRichTextBox-zip.html – Xeidos Jan 20 '15 at 15:52
  • Sorry, I can't look at that code. I just would like to know if other code than the one you want to write is at the moment already adding those mail icons to the RTB? – TaW Jan 20 '15 at 16:09
  • Yeah there is some other code, whitch add those icons to the rTB. But I cant add the full project to this thread... – Xeidos Jan 20 '15 at 16:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/69232/discussion-between-xeidos-and-taw). – Xeidos Jan 20 '15 at 16:17
  • Sure. BTW: I have found a way to make the link robust. It involves using a HashCode made from the RtfText as the key into the dictionary. Easily gotten in the doubleclick, but just as easy when adding the mail (by selecting the last one text position.. We can takl tomorrow if you need help.. – TaW Jan 20 '15 at 23:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/69302/discussion-between-taw-and-xeidos). – TaW Jan 21 '15 at 13:45