---
description: SpreadsheetControl의 Mail Merge 출력물 관련 기능
---

# ExcelMailMergeHelper

## 정의

* 네임스페이스: GST.PlusWin6.Core.Library
* 어셈블리: GST.PlusWin6.Core.dll

## 설명

* 엑셀 메일머지 출력물 정보 조회 및 메일머지 바인딩된 출력물 개체(IWorkbook 타입)에 대한 미리보기, 인쇄 기능을 지원하는 클래스
* 엑셀 메일머지 기준 정보와 기본 출력물 설정은 "PlusWin-Dev6" 프로그램의 \[엑셀 메일머지 설정], \[엑셀 메일머지 출력물] 메뉴에서 등록
* 지정된 업체의 고유한 출력물은 "PlusWin6" 프로그램을 해당 업체 서비스로 로그인하여 \[엑셀 출력물 관리] 메뉴에서 등록

{% hint style="info" %}
`IWorkbook`은 DevExpress.Spreadsheet 네임스페이스에 정의된 인터페이스\
(어셈블리: DevExpress.Spreadsheet.v22.1.Core.dll )
{% endhint %}



## Changes (PW5 → PW6)

* 엑셀 메일머지 기준 정보의 기본키가 'emm\_id'로 변경 ( 기존 'type\_id'와 같음 )



## Static Method

### Preview

* 엑셀 메일 머지 출력물의 미리보기 실행
* Parameters
  * `IWorkbook document` : 미리보기에 표현할 Spreadsheet 문서 개체
  * `string emmId` : 엑셀 메일머지 ID
  * `Dictionary<string, object> queryParams` : 데이터 조회시 필요한 파라미터 정보
  * `DataSet mailMergeDataSource` : 메일 머지 바인딩할 데이터
  * `string mailMergeDataMember` : 메일 머지 바인딩할 데이터의 Data Member
  * `string documentId` : 엑셀 메일머지 출력물 ID (고정된 출력물을 로드하고자 할 경우에 사용)
* Returns
  * `bool` : 처리에 실패시 false 반환

```csharp
public static bool Preview(IWorkbook document);

public static bool Preview(string emmId, Dictionary<string, object> queryParams, string documentId = null);

public static bool Preview(string emmId, DataSet mailMergeDataSource, string mailMergeDataMember, string documentId = null);
```



### EditInPreview

* 메일 머지 데이터가 바인딩 된 엑셀 출력물을 사용자가 수정할 수 있는 팝업으로 실행
* Parameters
  * `IWorkbook document` : 미리보기에 표현할 Spreadsheet 문서 개체
  * `string emmId` : 엑셀 메일머지 ID
  * `Dictionary<string, object> queryParams` : 데이터 조회시 필요한 파라미터 정보
  * `DataSet mailMergeDataSource` : 메일 머지 바인딩할 데이터
  * `string mailMergeDataMember` : 메일 머지 바인딩할 데이터의 Data Member
  * `string documentId` : 엑셀 메일머지 출력물 ID (고정된 출력물을 로드하고자 할 경우에 사용)
* Returns
  * bool : 처리에 실패시 false 반환

```csharp
public static bool EditInPreview(IWorkbook document);

public static bool EditInPreview(string emmId, Dictionary<string, object> queryParams, string documentId = null);

public static bool EditInPreview(string emmId, DataSet mailMergeDataSource, string mailMergeDataMember, string documentId = null);
```



### Print

* 엑셀 메일 머지 출력물을 미리보기 없이 바로 인쇄
* Parameters
  * `IWorkbook document` : 인쇄할 Spreadsheet 문서 개체
  * `string emmId` : 엑셀 메일머지 ID
  * `Dictionary<string, object> queryParams` : 데이터 조회시 필요한 파라미터 정보
  * `DataSet mailMergeDataSource` : 메일 머지 바인딩할 데이터
  * `string mailMergeDataMember` : 메일 머지 바인딩할 데이터의 Data Member
  * `string documentId` : 엑셀 메일머지 출력물 ID (고정된 출력물을 로드하고자 할 경우에 사용)
* Returns
  * `bool` : 처리에 실패시 false 반환

```csharp
public static bool Print(IWorkbook document);

public static bool Print(string emmId, Dictionary<string, object> queryParams, string documentId = null);

public static bool Print(string emmId, DataSet mailMergeDataSource, string mailMergeDataMember, string documentId = null);
```



### GenerateMailMergeDocument

* 데이터가 바인딩된 엑셀 메일 머지 출력물의 문서(IWorkbook)를 반환
* Parameters
  * `string emmId` : 엑셀 메일머지 ID
  * `Dictionary<string, object> queryParams` : 데이터 조회시 필요한 파라미터 정보
  * `DataSet mailMergeDataSource` : 메일 머지 바인딩할 데이터
  * `string mailMergeDataMember` : 메일 머지 바인딩할 데이터의 Data Member
  * `string documentId` : 엑셀 메일머지 출력물 ID (고정된 출력물을 로드하고자 할 경우에 사용)
* Returns
  * `IWorkbook` : 등록된 엑셀 문서 정보를 참조하여 데이터 조회 후 메일 머지 바인딩 처리된 문서

```csharp
public static IWorkbook GenerateMailMergeDocument(string emmId, DataSet mailMergeDataSource, string mailMergeDataMember, string documentId = null);

public static IWorkbook GenerateMailMergeDocument(string emmId, Dictionary<string, object> queryParams, string documentId = null);
```



### ExecuteQuery

* 등록된 엑셀 문서 정보를 참조하여 데이터 조회
* output 타입 파라미터(`DataSet result`, `string resultDataMember`)로 결과를 참조
* Parameters
  * `string emmId` : 엑셀 메일머지 ID
  * `Dictionary<string, object> queryParams` : 데이터 조회시 필요한 파라미터 정보
  * `out DataSet result` : 쿼리 실행 결과 DataSource
  * `out string resultDataMember` : 쿼리 실행 결과 DataMember
* Returns
  * `bool` : 조회에 실패시 false

```csharp
public static bool ExecuteQuery(string emmId, Dictionary<string, object> queryParams, out DataSet result, out string resultDataMember);
```



### RetrieveDocuments

* 이전 버전의 "RetrieveDocumentInfo"
* 엑셀 메일머지 출력물 리스트를 반환
* Parameters
  * `string documentId` : 엑셀 메일머지 출력물 ID (데이터 검색 조건)
  * `string documentName` : 엑셀 메일머지 출력물 이름 (데이터 검색 조건)
  * `string emmId` : 엑셀 메일머지 ID (데이터 검색 조건)
* Returns
  * `DataTable` : 쿼리 실행 결과

<table><thead><tr><th width="198">필드</th><th width="115.33333333333331">타입</th><th></th></tr></thead><tbody><tr><td>document_id</td><td>string</td><td>엑셀 메일머지 출력물 ID</td></tr><tr><td>document_name</td><td>string</td><td>엑셀 메일머지 출력물 이름</td></tr><tr><td>remarks</td><td>string</td><td>비고</td></tr><tr><td>screenshot</td><td>byte[]</td><td>엑셀 메일머지 출력물의 스크린샷 이미지</td></tr><tr><td>emm_id</td><td>string</td><td>엑셀 메일머지 ID</td></tr><tr><td>form_id</td><td>string</td><td>폼 ID</td></tr><tr><td>menu_name</td><td>string</td><td>메뉴명</td></tr><tr><td>document_type</td><td>string</td><td>출력물 등록 유형 ("Default" or "General")</td></tr></tbody></table>

```csharp
public static DataTable RetrieveDocuments();

public static DataTable RetrieveDocuments(string documentId, string documentName, string emmId);
```



### ShowPrintDialog

* 엑셀 메일머지 ID(emmId)로 등록된 전체 출력물 리스트를 조회하는 팝업을 열고, 선택하여 미리보기 또는 인쇄 실행
* Parameters
  * `string emmId` : 엑셀 메일머지 ID
  * `Dictionary<string, object> queryParams` : 데이터 조회시 필요한 파라미터 정보
* Returns
  * `DialogResult` : 정상적으로 출력 신호를 보내면 DialogResult.OK 반환

```csharp
public static DialogResult ShowPrintDialog(string emmId, Dictionary<string, object> queryParams);
```



## Example

### case 1

* 일반적인 방법 (데이터가 바인딩된 메일머지 출력물에 별도의 처리를 하지 않음)

```csharp
try
{
    var paramDatas = new Dictionary<string, object>();
    paramDatas.Add("@p_itemcd", "0304203B0070000500C");

    ExcelMailMergeHelper.Preview("TEST_01", paramDatas);
}
catch (Exception ex)
{
    ShowErrorMessageBox(ex);
}
```



### case 2

* 메일머지 데이터가 바인딩된 출력물 개체(IWorkbook)를 반환받아 가공하여 인쇄
* ex) Spreadsheet 그리기 옵션 및 셀 병합 등

```csharp
try
{
    var paramDatas = new Dictionary<string, object>();
    paramDatas.Add("@p_itemcd", "0304203B0070000500C");
    
    var document = ExcelMailMergeHelper.GenerateMailMergeDocument("DWG_01", paramDatas);

    //
    //// 여기에 엑셀 문서 수정
    //Worksheet mainSheet = document.Worksheets[0];
    //
    
    ExcelMailMergeHelper.Preview(document);
}
catch (Exception ex)
{
    ShowErrorMessageBox(ex);
}
```



### case 3

* 엑셀 메일머지 설정 정보를 참조하여 데이터 조회 결과만을 반환 받아 DataColumn, DataRow를 추가하는 등의 작업을 거친 후 메일머지 바인딩 후 인쇄
* ex) QR코드 이미지 추가 등
* 아래 예제 코드에서는 "QRCoder.dll" 어셈블리를 참조

```csharp
try
{
    var paramDatas = new Dictionary<string, object>();
    paramDatas.Add("@p_itemcd", "0304203B0070000500C");

    if (!ExcelMailMergeHelper.ExecuteQuery("TEST_01", paramDatas, out DataSet result, out string dataMember))
        return;

    if ((result?.Tables?.Count ?? 0) > 0)
    {
        var qrGenerator = new QRCodeGenerator();
        result.Tables[0].Columns.Add("qrcode", typeof(Image));
        
        foreach (DataRow row in result.Tables[0].Rows)
        {
            QRCode qrCode = new QRCode(qrGenerator.CreateQrCode(row["itemcd"].ToString(), QRCodeGenerator.ECCLevel.Q));
            row["qrcode"] = qrCode.GetGraphic(20);
        }
    }

    // 방법 1) 가공된 DataSource를 바로 출력물 미리보기 형태로 실행
    ExcelMailMergeHelper.Preview("TEST_01", result, dataMember);


    // 방법 2) DataSource를 메일머지 바인딩한 문서 개체를 받아와 다시 가공 후 미리보기로 실행
    var document = ExcelMailMergeHelper.GenerateMailMergeDocument("TEST_01", result, dataMember);
    //
    //// 여기에 엑셀 문서 수정
    //Worksheet mainSheet = document?.Worksheets?.FirstOrDefault();
    //
    ExcelMailMergeHelper.Preview(document);
}
catch (Exception ex)
{
    ShowErrorMessageBox(ex);
}
```



### case 4

* 첨부파일로 등록된 이미지나 PDF 파일을 확인하여, 조회된 엑셀 출력물에 다음 페이지로 등록
* PdfDocumentProcessor (어셈블리 DevExpress.Docs.v22.1)

```csharp
public override void ClickPreviewButton()
{
    ExcelMailMergeHelper.Preview(CreatePrintout());
}

public override void ClickPrintButton()
{
    ExcelMailMergeHelper.Print(CreatePrintout());
}

private IWorkbook CreatePrintout()
{
    if (gvwList.FocusedRowHandle < 0)
    {
        ShowMessageBox(Messages.NoDataSelected);
        return null;
    }

    Dictionary<string, object> paramDatas = new Dictionary<string, object>();
    paramDatas.Add("@p_orgdiv", Config["orgdiv"]);
    paramDatas.Add("@p_datnum", txtDatnum1.Text);
    paramDatas.Add("@p_login_user", Config.UserId);

    try
    {
        IWorkbook mainWorkbook = ExcelMailMergeHelper.GenerateMailMergeDocument("QC_A4000", paramDatas);
        mainWorkbook.Unit = DevExpress.Office.DocumentUnit.Millimeter;

        // 첨부파일 정보 조회
        string query = $@"
            SELECT saved_name, original_name
            FROM sysAttachments
            WHERE attdatnum = '{txtAttdatanum.Text}'";

        DataTable attachDatas = ExecuteSql(query, false)?[0];

        // 이미지 파일 처리
        var images = new List<Image>();

        if ((attachDatas?.Rows?.Count ?? 0) > 0)
        {
            foreach (DataRow row in attachDatas.Rows)
            {
                string savedName = row.GetValue("saved_name")?.ToString() ?? string.Empty;
                string originalName = row.GetValue("original_name")?.ToString() ?? string.Empty;

                bool isImageFile = Util.IsRecognisedImageFile(originalName);
                byte[] fileBytes = null;
                Image image = null;

                // 이미지 or PDF 파일만 등록
                if (isImageFile || Path.GetExtension(originalName).Equals(".pdf", StringComparison.OrdinalIgnoreCase))
                {
                    if (isImageFile)
                    {
                        fileBytes = AttachmentHelper.DownloadFile(savedName);
                        using (MemoryStream ms = new MemoryStream(fileBytes))
                        {
                            image = Image.FromStream(ms);
                        }
                    }
                    else
                    {
                        var fileBytesOfPdf = AttachmentHelper.DownloadFile(savedName); ;
                        using (MemoryStream stream = new MemoryStream(fileBytesOfPdf))
                        {
                            PdfDocumentProcessor processor = new PdfDocumentProcessor();
                            processor.LoadDocument(stream);
                            image = processor.CreateBitmap(1, 1000);

                            fileBytes = image.ConvertImageToByteArray();

                            processor.CloseDocument();
                        }
                    }

                    images.Add(image);
                }
            }
        }

        foreach (Image image in images)
        {
            if (image == null)
                continue;

            Worksheet newWorksheet = mainWorkbook.Worksheets.Add();
            newWorksheet.ActiveView.Margins.Top = 12F;
            newWorksheet.ActiveView.Margins.Bottom = 12F;
            newWorksheet.ActiveView.Margins.Left = 6F;
            newWorksheet.ActiveView.Margins.Right = 6F;

            CellRange range;

            // 용지 가로 설정
            if (image.Width > image.Height)
            {
                range = newWorksheet["A1:O36"];
                newWorksheet.ActiveView.Orientation = PageOrientation.Landscape;
            }
            // 용지 세로 설정
            else
            {
                range = newWorksheet["A1:L48"];
                newWorksheet.ActiveView.Orientation = PageOrientation.Portrait;
            }

            newWorksheet.SetPrintRange(range);

            // 이미지 추가
            Picture picture = newWorksheet.Pictures.AddPicture(image, range, true);

            // 이미지 가운데로 이동
            float offsetX = (float)((range.ColumnWidth * range.ColumnCount) - picture.Width) / 2F;
            float offsetY = (float)((range.RowHeight * range.RowCount) - picture.Height) / 2F;
            picture.Move(offsetY, offsetX);
        }

        return mainWorkbook;
    }
    catch (Exception ex)
    {
        ShowErrorMessageBox(ex);
        WaitFormEx.Close();
        return null;
    }
}
```



### case 5

* 미리보기 없이 엑셀 출력물 파일(.xlsx)을 사용자가 지정한 경로에 저장

<pre class="language-csharp"><code class="lang-csharp">private void SaveExcelDocument()
{
    Dictionary&#x3C;string, object> paramValues = new Dictionary&#x3C;string, object>();

<strong>    paramValues.Add("@p_orgdiv", Config["orgdiv"]);
</strong>    // ...
    // ...

    IWorkbook spreadsheet = ExcelMailMergeHelper.GenerateMailMergeDocument("type", paramValues);

    SaveFileDialog sfd = new SaveFileDialog();
    sfd.Filter = "Excel Files (*.xlsx)|*.xlsx";
    sfd.FileName = $"{this.Text}.xlsx";

    if (sfd.ShowDialog() == DialogResult.OK)
    {
        spreadsheet.SaveDocument(sfd.FileName, DocumentFormat.Xlsx);
    }
}
</code></pre>



