Ticket S19805
Visible to All Users

FileAttachments Module - How to drag & drop file attachments from Outlook messages into ListView or DetailView with FileData objects

created 17 years ago (modified 7 years ago)

From Q102850:
"Hi,
I am using the FileAttachmentBase to add files to a class in my project. Drag/Drop works great if I want to add a file from Windows Explorer. I want to be able to drag an attachment from Outlook and drop it into my application in the same way.
Thanks,
Stephan"

Show previous comments (3)

    I would appreciate this Feature too. Several customers asked for it already.

      This is not a XAF specific issue. Please search the web for solutions.

        I have just received specific user request for this feature as well.  Reading other related tickets, it seems the only option is to modify and recompile DevExpress sources - not something I want to do.

        Before I head down a long and treacherous path is there any update on whether this will be supported by the fileattachment module?  Either dragging the email OR dragging the attachments from the email?  Currently users are getting around this by saving the MSG or attachments first, but since they know about drag/drop from File Explorer they can't understand why they can do this from Outlook as well.

        I am familiar with handling this as a fully custom option (did it years ago in Visual Foxpro drag/drop on a grid from either file or Outlook item) and it worked beautiful.  However, since we are already using the fileattachment and the filesystemdata modifications (to store on disk vs. database) I would like to be able to extend or override the drag/drop behavior without modifying sources.

        Answers approved by DevExpress Support

        created 7 years ago (modified 7 years ago)

        Hello, Michael!

        We investigated your code and introduced a few changes to XAF codebase to make your implementation simpler.

        Starting with version 17.2.5 (try this hot fix build, if you cannot wait for the next maintenance build), you can handle the FileAttachmentListViewController.CustomDragOver  event to manually set the e.DragEventErgs.Effect property to DragDropEffects.Copy for the "FileGroupDescriptor"  data format and handle the FileAttachmentListViewController.CustomizeDragDropFileNames  event to manually save messages to temporary files and specify names for created files:

        C#
        using DragAndDropEmailFileAttachment.Module.BusinessObjects; using System.IO; using Microsoft.Office.Interop.Outlook; using System.Windows.Forms; using System.Linq; using DevExpress.ExpressApp; using DevExpress.ExpressApp.FileAttachments.Win; namespace DragAndDropEmailFileAttachment.Module.Win.Controllers { public class DragDropAttachmentsFromEmailController : ViewController { private FileAttachmentListViewController fileAttachmentListViewController; public DragDropAttachmentsFromEmailController() : base() { TargetViewType = ViewType.ListView; TargetObjectType = typeof(ObjectWithAttachment); } protected override void OnActivated() { base.OnActivated(); fileAttachmentListViewController = Frame.GetController<FileAttachmentListViewController>(); if (fileAttachmentListViewController != null) { fileAttachmentListViewController.CustomDragOver += FileAttachmentListViewController_CustomDragOver; fileAttachmentListViewController.CustomizeDragDropFileNames += FileAttachmentListViewController_CustomizeDragDropFileNames; } } private void FileAttachmentListViewController_CustomDragOver(object sender, CustomDragOverEventArgs e) { if(fileAttachmentListViewController != null && fileAttachmentListViewController.AddFromFileAction.Active) { if(e.DragEventArgs.Data.GetDataPresent(DataFormats.FileDrop)) { e.DragEventArgs.Effect = DragDropEffects.Copy; } else if(e.DragEventArgs.Data.GetDataPresent("FileGroupDescriptor")) { e.DragEventArgs.Effect = DragDropEffects.Copy; } else { e.DragEventArgs.Effect = DragDropEffects.None; } } else { e.DragEventArgs.Effect = DragDropEffects.None; } e.Handled = true; } private string CorrectFileName(string fileName) { foreach(char invalidChar in Path.GetInvalidFileNameChars()) { if(fileName.Contains(invalidChar)) { fileName = fileName.Replace(invalidChar, '_'); } } return fileName; } private void FileAttachmentListViewController_CustomizeDragDropFileNames(object sender, CustomizeDragDropFileNamesEventArgs e) { if(e.DragEventArgs.Data.GetDataPresent("FileGroupDescriptor")) { Microsoft.Office.Interop.Outlook.Application outlookApplication = new Microsoft.Office.Interop.Outlook.Application(); foreach(MailItem mailItem in outlookApplication.ActiveExplorer().Selection.OfType<MailItem>()) { string fileName = mailItem.Subject + ".msg"; fileName = CorrectFileName(fileName); string fullFileName = Path.Combine(Path.GetTempPath(), this.Application.ApplicationName, "tempmsgs", fileName); mailItem.SaveAs(fullFileName, OlSaveAsType.olMSG); e.FileNames.Add(fullFileName); } } } protected override void OnDeactivated() { base.OnDeactivated(); if (fileAttachmentListViewController != null) { fileAttachmentListViewController.CustomizeDragDropFileNames -= FileAttachmentListViewController_CustomizeDragDropFileNames; fileAttachmentListViewController.CustomDragOver -= FileAttachmentListViewController_CustomDragOver; fileAttachmentListViewController = null; } } } }

        See the attached project for more details.

        Additional references:
        How to: Install the Visual Studio Tools for Office Runtime Redistributable
        Referencing the Office Primary Interop Assembly
        Cannot find Microsoft.Office.Interop Visual Studio

        Thanks,
        Nat.

          Comments (2)
          MK MK
          Michael Köster 1 7 years ago

            Perfect

            DevExpress Support Team 7 years ago

              Hello, Michael!

              These events will be available starting with version 17.2.5.

              Thanks,
              Nat

              Other Answers

              created 7 years ago (modified 7 years ago)

              Here is a quick solution with inheritance.
              I save the msg file to the temp folder and load it into the fileattachment class.

              namespace Salud.Module.Win.Controllers
              {

              public partial class OutlookMsgDragnDropController : DevExpress.ExpressApp.FileAttachments.Win.FileAttachmentListViewController
                  {
                      public OutlookMsgDragnDropController()
                      {
                          InitializeComponent();

              }

              protected void GetOutlookMessage(DragEventArgs e)
                      {
                          Microsoft.Office.Interop.Outlook.Application oApp = new Microsoft.Office.Interop.Outlook.Application();
                          for (int i = 1; i <= oApp.ActiveExplorer().Selection.Count; i++)
                          {
                              object temp = oApp.ActiveExplorer().Selection[i];
                              if (temp is Microsoft.Office.Interop.Outlook.MailItem)
                              {
                                  Microsoft.Office.Interop.Outlook.MailItem mailItem = (temp as Microsoft.Office.Interop.Outlook.MailItem);
                                  string file = string.Format(@"{0}{1}.msg", Path.Combine(Path.GetTempPath(), "YourTempFolder"), mailItem.Subject.Replace(":","-"));
                                  mailItem.SaveAs(file, Microsoft.Office.Interop.Outlook.OlSaveAsType.olMSG);
                                  //Load msg file into your byte array
                                  Dateianhang datei = FileHelper.LoadFromFile(ObjectSpace, file, "Email");
                                  //Add to collection
                                  ((DevExpress.ExpressApp.ListView)View).CollectionSource.Add(datei);
                                  ObjectSpace.CommitChanges();
                              }
                          }
                      }

              protected override void OnDragDrop(DragEventArgs e)
                      {
                          if (e.Data.GetDataPresent("FileGroupDescriptor"))
                              GetOutlookMessage(e);
                          else
                              base.OnDragDrop(e);
                      }

              protected override void OnDragOver(DragEventArgs e)
                      {
                          if (AddFromFileAction.Active && e.Data.GetDataPresent(DataFormats.FileDrop))
                          {
                              e.Effect = DragDropEffects.Copy;
                          }
                          else if (e.Data.GetDataPresent("FileGroupDescriptor"))
                          {
                              e.Effect = DragDropEffects.Copy;
                          }
                          else
                          {
                              e.Effect = DragDropEffects.None;
                          }

              }
                  }
              }

                Comments (1)
                Dennis Garavsky (DevExpress) 7 years ago

                  Thanks for sharing, Michael!

                  created 7 years ago (modified 4 years ago)

                  Recommendations for XAF v17.2.4 and older versions
                  Hello Randy,

                  I would like to repost my solution from the T182151 ticket for you and others to follow. In fact, it does not require our source code modification and can be implemented on your project side after disabling the default class:

                  1. Copy the content of the …\DevExpress.ExpressApp.Modules\DevExpress.ExpressApp.FileAttachment.Win\FileAttachmentListViewController.cs file into your project. This class does not contain a lot of code and uses only public and documented APIs. It should not be difficult to maintain this class.
                  2. Change the default namespace and class name to yours and add the following method into the copied class:

                  Code
                  protected override void OnFrameAssigned() { base.OnFrameAssigned(); Frame.GetController<DevExpress.ExpressApp.FileAttachments.Win.FileAttachmentListViewController>().Active["any text"] = false; }

                  3. Modify its source code as you require to support drag-and-drop operations from Outlook messages. The latter part is unrelated to DevExpress, and you may want to look for standard solutions on sites like StackOverFlow, CodeProject, MSDN, etc. For instance, the https://www.codeproject.com/Articles/28209/Outlook-Drag-and-Drop-in-C article  or VB.NET example code in the T252167 ticket looks like a good starting point.

                  NOTE: this WinForms solution is for ListView, but a similar solution can be implemented for the FilePropertyEditor and its underlying FileDataEdit in DetailView. You may need to create a custom property editor based on the FileDataEdit descendant with the overridden OnDragDrop and OnDragOver methods (refer to the corresponding XAF source code for more details).

                  ASP.NET WebForms solutions will be different due to the underlying platform specifics. We also suggest you first implement this task in a non-XAF form first. The following tickets will be a good starting point for this:

                    Show previous comments (2)
                    AF AF
                    Andreas Fasching 4 years ago

                      Would the creator of ticket https://supportcenter.devexpress.com/ticket/details/q466771 which is linked above mind to open it as public ticket?

                      Dennis Garavsky (DevExpress) 4 years ago

                        @Andreas: While we cannot make q466771 public, I have updated my original answer with the links to relevant ASP.NET WebForms examples.

                        AF AF
                        Andreas Fasching 4 years ago

                          Thanks Dennis!

                          Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

                          Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.