سؤال

لقد سمح تطبيق WinForms منذ فترة طويلة بخيار "طباعة" يستخدم بشكل أساسي RDLC.

طلب العميل أن نضيف ميزة تسمح للمستخدمين بإرسال الإخراج "المطبوع" عبر البريد الإلكتروني.

الآن ، نعلم أنه يتم إنشاء ملف EMF (في المجلد المؤقت) كنوع من المنتجات الثانوية المخفية لعملية الطباعة الحالية لدينا.

يبدو لنا أنه يمكننا ببساطة الاستيلاء على ملف EMF وإرفاقه بالبريد الإلكتروني الجديد ويتم الانتهاء من المهمة.

  1. هل هذا هو الخيار الأفضل؟
  2. هل يمكن أن نعتمد على ملف EMF يتم فتحه بواسطة أي جهاز Windows؟
  3. كيف نحدد ملف EMF؟ ... يبدو فقط اسمه %TEMP%\DiaryGrid_1.emf حالياً. حسنًا ، لذا فإن DiaryGrid هو اسم ملف RDLC الخاص بنا ولكن يتم إضافة _1 في مكان ما على طول الطريق.
هل كانت مفيدة؟

المحلول

لقد فعلت ذلك من قبل. لقد قمت بتصدير التقرير إلى PDF بشكل برمجي إلى موقع معين ، ثم نرسل بريدًا إلكترونيًا إلى ملف PDF وحذفه. سأحاول العثور على الرمز لك (ليس في المنزل الآن)

تحرير:

آسف لآخر. أنا الآن في المنزل وسأعطيك بعض كتل التعليمات البرمجية التي أعتقد أنها ستمنحك بعض المساعدة لإلغاء مهمتك. سأقوم بتضمين بعض التعليقات على الكود حتى تتمكن من فهم بعض الأشياء المحددة في مشروعي. يتم اختبار هذا الرمز ويعمل بشكل جيد في عملائي ، لكنني متأكد من أنه يمكن تحسينه. من فضلك ، اسمحوا لي أن أعرف إذا كان يمكنك تحسين هذا الرمز ؛)

بادئ ذي بدء ، سنقوم بتصدير التقرير إلى PDF.

private string ExportReportToPDF(string reportName)
{
   Warning[] warnings;
   string[] streamids;
   string mimeType;
   string encoding;
   string filenameExtension;
   byte[] bytes = ReportViewer1.LocalReport.Render(
      "PDF", null, out mimeType, out encoding, out filenameExtension,
       out streamids, out warnings);

   string filename = Path.Combine(Path.GetTempPath(), reportName);
   using (var fs = new FileStream(filename, FileMode.Create))
   {
      fs.Write(bytes, 0, bytes.Length);
      fs.Close();
   }

   return filename;
}

الآن ، نحتاج إلى فئة تتحكم في نظام البريد. كل نظام بريد لديه خصائصه الخاصة ، لذلك ربما ستحتاج إلى تعديل هذه الفئة. سلوك الفصل بسيط. تحتاج فقط إلى ملء الخصائص ، واستدعاء طريقة إرسال. في حالتي ، لا تسمح لي Windows بحذف ملف PDF بمجرد إرساله (يقول Windows إن الملف قيد الاستخدام) ، لذلك أقوم ببرمجة الملف الذي سيتم حذفه في إعادة التشغيل التالية. ألقِ نظرة على طريقة الحذف. من فضلك ، لاحظ أن طريقة الإرسال تستخدم فئة Cutom المسماة MailConfig. هذه فئة صغيرة تحتوي على بعض سلاسل التكوين مثل المضيف واسم المستخدم وكلمة المرور. سيتم إرسال البريد باستخدام هذه المعلمة.

public class Mail
{
   public string Title { get; set; }
   public string Text { get; set; }
   public string From { get; set; }
   public bool RequireAutentication { get; set; }
   public bool DeleteFilesAfterSend { get; set; }

   public List<string> To { get; set; }
   public List<string> Cc { get; set; }
   public List<string> Bcc { get; set; }
   public List<string> AttachmentFiles { get; set; }

   #region appi declarations

   internal enum MoveFileFlags
   {
      MOVEFILE_REPLACE_EXISTING = 1,
      MOVEFILE_COPY_ALLOWED = 2,
      MOVEFILE_DELAY_UNTIL_REBOOT = 4,
      MOVEFILE_WRITE_THROUGH = 8
   }

   [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
   static extern bool MoveFileEx(string lpExistingFileName,
                                 string lpNewFileName,
                                 MoveFileFlags dwFlags);

   #endregion

   public Mail()
   {
      To = new List<string>();
      Cc = new List<string>();
      Bcc = new List<string>();
      AttachmentFiles = new List<string>();
      From = MailConfig.Username;
   }

   public void Send()
   {
      var client = new SmtpClient
      {
         Host = MailConfig.Host,
         EnableSsl = false,
      };

      if (RequireAutentication)
      {
         var credentials = new NetworkCredential(MailConfig.Username, 
                                                 MailConfig.Password);
         client.Credentials = credentials;
      }

      var message = new MailMessage
      {
         Sender = new MailAddress(From, From),
         From = new MailAddress(From, From)
      };

      AddDestinataryToList(To, message.To);
      AddDestinataryToList(Cc, message.CC);
      AddDestinataryToList(Bcc, message.Bcc);

      message.Subject = Title;
      message.Body = Text;
      message.IsBodyHtml = false;
      message.Priority = MailPriority.High;

      var attachments = AttachmentFiles.Select(file => new Attachment(file));
      foreach (var attachment in attachments)
         message.Attachments.Add(attachment);

      client.Send(message);

      if (DeleteFilesAfterSend)
         AttachmentFiles.ForEach(DeleteFile);
   }

   private void AddDestinataryToList(IEnumerable<string> from,
      ICollection<MailAddress> mailAddressCollection)
   {
      foreach (var destinatary in from)
         mailAddressCollection.Add(new MailAddress(destinatary, destinatary));
   }

   private void DeleteFile(string filepath)
   {
      // this should delete the file in the next reboot, not now.
      MoveFileEx(filepath, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT);
   }
}

الآن ، يمكنك إنشاء نموذج لطلب المصير ، وإضافة بعض التحقق من الصحة ، وما إلى ذلك ، وإرجاع مثيل لفئة البريد ... أو يمكنك ببساطة "رمز صلب" القيم وملء الفئة.

فيما يلي الرمز الذي أستخدمه في زر لاستدعاء هذا النموذج ، في المثال الخاص بي يسمى SendMailView.

private void BtnSendByMail_Click(object sender, EventArgs e)
{
   SendMailView sendMailView = new SendMailView();

   if (sendMailView.ShowDialog()== DialogResult.OK)
   {
      Mail mail = sendMailView.CurrentItem;
      mail.AttachmentFiles.Add(ExportReportToPDF("Invoice.pdf"));
      mail.DeleteFilesAfterSend = true;
      mail.RequireAutentication = true;
      mail.Send();
   }
   sendMailView.Dispose();
}

في هذا المثال ، Senmailview.CurrentItem هو مثيل فئة البريد. نحن ببساطة بحاجة إلى الاتصال إلى ميثس إرسال ويتم العمل.

هذه هي أكبر إجابة كتبتها على الإطلاق ... آمل أن تساعدك: D إذا كان لديك أي مشكلة في استخدامها ، اتصل بي. بالمناسبة ، أنا لست فخوراً جدًا بلغتي الإنجليزية ، لذا سامحني إذا كان النص له أي خطأ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top