반응형

안녕하세요~

 

코딩연습생입니다

 

C# WINFORM에서 그리드뷰의 내용은 엑셀로 내보개기에 대한 포스팅을 할려고 합니다

 

예전 OLEDB를 이용한 엑셀 연동을 포스팅한적이 있는데요

 

 

https://codingman.tistory.com/103?category=715728

 

[C#] OLEDB를 통한 엑셀파일 불러오기(데이터그리드뷰)

안녕하세요 코딩 연습생 입니다 이전 포스팅에서 직접 엑셀의 API를 활용하여 엑셀파일의 내용을 불러와 데이터그리드뷰와 연동하는 포스팅을 업로드했었는데요 https://codingman.tistory.com/100 [C#] ��

codingman.tistory.com

 

해당 예제를 사용하여 구현하셔도 상관은 없습니다~ 하지만 이번엔 Interop.Excel를 사용하여 구현을 해볼껀데요

 

프로젝트를 하나 생성하시고 윈폼을 하나 만듭니다

 

 

저는 위와 같은 화면을 디자인해서 생성하였습니다

 

아래쪽에 보이는 그리드뷰 영역에 "엑셀"이라는 버튼을 누루면 내보내기가 가능한 기능을 구현을 해볼려고 해요

 

일단 첫번째로 엑셀을 사용하기 위한 선언을 합니다

using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
using System.IO;

 

두번째는 버튼을 추가하여 클릭 이벤트를 생성한뒤에 다음과 같이 코딩을 합니다

 

        private void hoverGradientButton3_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Title = "Save as Excel File";
            sfd.Filter = "Excel Documents (*.xls)|*.xls";
            sfd.FileName = "납품처마스터.xls";

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                copyAlltoClipboard();

                object misValue = System.Reflection.Missing.Value;
                Excel.Application xlexcel = new Excel.Application();

                xlexcel.DisplayAlerts = false;
                Excel.Workbook xlWorkBook = xlexcel.Workbooks.Add(misValue);
                Excel.Worksheet xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

                try
                {
                    Excel.Range rng = xlWorkSheet.get_Range("D:D").Cells;
                    rng.NumberFormat = "@";
                    Excel.Range CR = (Excel.Range)xlWorkSheet.Cells[1, 1];
                    CR.Select();
                    xlWorkSheet.PasteSpecial(CR, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, true);

                    xlWorkBook.SaveAs(sfd.FileName, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
                    xlexcel.DisplayAlerts = true;
                    xlWorkBook.Close(true, misValue, misValue);

                    //파일 닫기... 
                    uint processId = 0;
                    GetWindowThreadProcessId(new IntPtr(xlexcel.Hwnd), out processId);
                    xlexcel.Quit();
                    if (processId != 0)
                    {
                        System.Diagnostics.Process excelProcess = System.Diagnostics.Process.GetProcessById((int)processId);
                        excelProcess.CloseMainWindow();
                        excelProcess.Refresh();
                        excelProcess.Kill();
                    }

                    MessageBox.Show("엑셀 파일 생성이 완료 되었습니다.");

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                    xlWorkBook.Close();
                    uint processId = 0;
                    GetWindowThreadProcessId(new IntPtr(xlexcel.Hwnd), out processId);
                    xlexcel.Quit();
                    if (processId != 0)
                    {
                        System.Diagnostics.Process excelProcess = System.Diagnostics.Process.GetProcessById((int)processId);
                        excelProcess.CloseMainWindow();
                        excelProcess.Refresh();
                        excelProcess.Kill();
                    }
                }
            }
        }

 

몇가지 오류가 뜨실껀데 아래의 내용을 적용하면 모두 해결 되실겁니다

 

두번째는 그리드뷰의 내용을 클립보드(Clipboard)안에 담는 함수 부분입니다

 

        private void copyAlltoClipboard()
        {
            dataGridView1.SelectAll();
            DataObject dataObj = dataGridView1.GetClipboardContent();
            if (dataObj != null)
                Clipboard.SetDataObject(dataObj);
        }

 

그리고 C#에서 엑셀을 연동하여 사용하시면 항상 프로세스에 엑셀 찌꺼기(?)가 남아 있습니다

 

그걸 해결하기 위해 몇번 삽질을 했는데요

 

이를 해결하기 위해 프로젝트 소스 상단에 DLL 하나를 Import 시켜줍니다

 

        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

 

이렇게 하시면 엑셀 프로세스를 불러와 사용한뒤에 해당 PID값을 기억헀다가 종료시에 강제 삭제해주게 됩니다

 

 

실행 순서는 이렇게 됩니다

 

 

버튼을 누루게 되면

 

 

이렇게 저장 위치를 선택하실수 있게 나오고

 

 

저장이 완료되면 위의 사진과 같이 그리드가 전체 선택이 되면서 저장되어집니다

 

엑셀 파일을 열어보시면 이렇게 헤더까지 그대로 내보내기 되어 진 모습을 볼 수 있네요

 

 

감사합니다~

반응형
반응형

안녕하세요

 

코딩연습생입니다

 

이번 포스팅은 C# WINFORM에서 데이터드리트뷰(DataGridView)를 사용하실때

 

뷰안에서 값 변경이 일어났을때 이벤트를 캣치해서 행위를 할려고 할때 해당 뷰의 내용의 셀(Cell)이 콤보 박스 일 경우

 

에는 이벤트가 먹질 않습니다

 

그래서 이런 경우 이벤트를 발생시킬수 있는 방법을 알려드리고자 합니다

 

이미 많은 분들이 알고 계실듯 한데 언제나 처럼 기록과 혹시나 모를 분들을 위해 포스팅 합니다

 

보통 데이터그리드뷰에서 값 변경 이벤트로 사용되는 이벤트 함수는 

 

CellValueChanged() 함수를 사용하는데요 다른 타입의 셀은 모두 반응하는데 이상하게 콤보박스만 반응하지 않습니다

 

 

이럴때는 다음과 같이 이벤트를 걸어주면 사용할 수 있습니다

 

첫번째 이벤트 함수는 EditingControlShowing() 함수 입니다

 

 

위와 같이 이벤트를 생성하시고 다음과 같이 콤보 박스에 아이템을 설정해 줍니다

 

private void sGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            if (sGridView1.CurrentCell.ColumnIndex == 3)
            {
                int rowIndex = this.sGridView1.CurrentCell.RowIndex;
                string y1Name = this.sGridView1.Rows[rowIndex].Cells[3].Value as string;

                ComboBox comboBox = e.Control as ComboBox;

                if (comboBox != null)
                {
                    object value = comboBox.SelectedItem;
                    comboBox.SelectedIndexChanged -= comboBox_SelectedIndexChanged;
                    comboBox.Items.Clear();

                    if (y1Name.Length > 0)
                    {
                        comboBox.Items.AddRange(new object[] { "Y", "N" });
                    }

                    comboBox.SelectedItem = value;

                    comboBox.SelectedIndexChanged += comboBox_SelectedIndexChanged;
                }
            }
        }

 

그리고 EditingControlShowing() 함수가  동작했을때 정의한 콤보박스에 SelectdIndexChanged 함수가 동작하게 합니다

 

 private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                if (sGridView1.CurrentCell.RowIndex >= 0)
                {
                    if (sGridView1.CurrentCell.ColumnIndex == 3)
                    {
                        if (sGridView1.Rows[sGridView1.CurrentCell.RowIndex].Cells[5].Value != null)
                        {
                            this.sGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
                            this.sGridView1.UpdateCellValue(sGridView1.CurrentCell.ColumnIndex, sGridView1.CurrentCell.RowIndex);
							
                            //이벤트 발생시 동작할 내용 부분
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.ToString());
            }
        }

 

위의 comboBox_SelectedIndexChanged() 함수는 직접 타이핑해서 생성하였습니다

 

마지막으로 CellClick() 함수 입니다

 

 

생성된 CellClick() 함수에 아래와 같이 코딩을 합니다

        private void sGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if ((e.RowIndex < 0) || (e.ColumnIndex < 0))
            {
                return;
            }

            if (e.ColumnIndex != 0)
            {
                return;
            }

            DataGridViewRow dataGridViewRow = this.sGridView1.Rows[e.RowIndex];
            DataGridViewCell dataGridViewCell = dataGridViewRow.Cells[e.ColumnIndex];
            
            if (dataGridViewCell is DataGridViewComboBoxCell)
            {
                sGridView1.CurrentCell = dataGridViewCell;
                sGridView1.BeginEdit(true);

                DataGridViewComboBoxEditingControl comboboxEdit = (DataGridViewComboBoxEditingControl)this.sGridView1.EditingControl;

                if (comboboxEdit != null)
                {
                    comboboxEdit.DroppedDown = true;
                }
            }
        }

 

동작 순서는 이렇습니다 데이터 그리드뷰의 컨트롤에서 셀 클릭이벤트가 발생하게 되면 EditingControlShowing()를

 

호출하게 되어 콤보박스가 동작 할 수 있도록 이벤트를 활성화 해주구요

 

콤보박스가 동작한뒤에 값이 변경되는것이 감지 되어지면 comboBox_SelectedIndexChanged()가 호출되어 지는 겁니다

 

이렇게 하시면 데이터드리드뷰에서도 콤보박스의 값 변경 이벤트를 사용할수 있게 됩니다

 

디버깅 모드 상태에서 아래 그림처럼 그리드 뷰의 콤보 박스의 값을 변경하게 되면

이렇게 중단점이 걸리는 걸 보실수 있습니다

 

 

반응형

+ Recent posts