반응형

안녕하세요

 

코딩연습생입니다

 

C# Winform에서 엑셀 연동시 데이터를 읽어오거나 쓰기를 할때 Cells를 많이 사용하게 됩니다

 

저번 포스팅에서도 한번 언급했던 적이 있는데 300건 이후로 속도가 현저히 느려집니다

 

그래서 속성 설정으로 속도를 개선하는것을 예전에 포스팅 했던 적이 있는데요

 

https://codingman.tistory.com/101

 

[C#] 엑셀 Cells 사용시 속도 문제 해결하기

안녕하세요. 코딩연습생입니다. 정말 오랜만에 글을 쓰는거 같습니다.. 회사 프로젝트 진행 때문에 시간을 너무 빼앗겨 버리네요ㅎㅎ 근데 저도 이제 블로거가 다 된거 같습니다 하루에도 몇번�

codingman.tistory.com

근데 위의 방법도 근본적인 속도 문제가 해결 되질 않습니다

 

정말 미비한 차이만 발생하더라구요

 

그래서 이번 포스팅에서는 근본적인 속도 문제를 해결 해보려고 합니다

 

일단 기본적인 엑셀 값 쓰기 방식인데요 이전 포스팅을 참조해 주세요

 

https://codingman.tistory.com/100

 

[C#] 엑셀 템플릿파일 불러오기 및 값 넣기

안녕하세요 코딩 연습생입니다 아직도 코로나19로 인해서 기업들 소상인 분들 모두 참 어렵게 지내고 계시는거 같습니다 저 또한 회사원으로 회사가 많이 힘들어 지고 있다고 체감할 정도니깐��

codingman.tistory.com

위의 방식으로 구현을 할 경우 조건이 엑셀의 Row수가 대략 100개 이하일 경우에 사용하세요

 

그 이상 넘어가게 되면 속도가 많이 걸립니다 대략 300~500개의 Row의 값을 쓸 경우 대략 10~15분 가량이 소요

 

됩니다

 

이 문제를 해결하기 위해 고민도 많이 하고 검색도 많이 했는데 뚜렸한 답변이 없더라구요

 

OLEDB를 사용한 방법도 있긴 한데 해당 방법은 쿼리 형식으로 데이터를 읽고/쓰기를 해야 해서

 

특정 Cell 지정이나 이미 생성되어 있는 양식화에 적용하기에는 어렵고 복잡하더라구요

 

그래서 검색 내용한 내용과 기존 방식을 응용해서 구현해 봤습니다

 

일단 소스 코드 부터 보여 드리겠습니다

 

private void hoverGradientButton21_Click(object sender, EventArgs e)
        {
            DataGridView_Change(false);

            string ExcelPath = Environment.CurrentDirectory + @"\Excel\Shipping_sample.xlsx";
            string ExcelEndPath;
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Title = "저장경로 지정하세요";
            saveFileDialog.OverwritePrompt = true;
            saveFileDialog.Filter = "Excel File(*.xlsx)|*.xlsx";

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                ExcelEndPath = saveFileDialog.FileName;

                //파일생성유무 확인(기준 하루 한번 생성이 가능 재생성시 그존 파일 삭제.
                if (File.Exists(ExcelEndPath))
                {
                    File.Delete(ExcelEndPath);
                }

                Excel.Application app = new Excel.Application();
                app.DisplayAlerts = false;
                app.Visible = false;
                app.ScreenUpdating = false;
                app.DisplayStatusBar = false;
                app.EnableEvents = false;

                Excel.Workbooks workbooks = app.Workbooks;
                Excel.Workbook workbook = workbooks.Open(ExcelPath, 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
                Excel.Sheets sheets = workbook.Worksheets;
                Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);
                Excel.Range rng = worksheet.get_Range("A1", "CG3000");


                //Excel.Range totalRange = worksheet.get_Range(worksheet.get_Range("A1"), lastCell);
                object[,] only_data = (object[,])rng.get_Value();
                

                try
                {
                    //엑셀 시트 인덱스 번호는 0,0 부터 시작 하는 것이 아니라 1,1 A1 부터 시작 함. 0,0 으로 시작하면 오류... 
                    //시트에 값 쓰기... 
                    string query = "EXEC SP_SHIP_CUST_PLAN_EXCEL";
                    query += "           'SELECT',";
                    query += "           '" + WORK_FROM_KEY.Text + "',";
                    query += "           ''";
                    SAC_MesDB db = new SAC_MesDB();
                    DataTable dt = db.ExcuteQuery(query);

                    if (dt.Rows.Count > 0)
                    {
                        int row = dt.Rows.Count + 30;
                        int column = rng.Columns.Count;
                        object[,] data = new object[row, column];

                        data = only_data;

                        //해더 복사
                        for (int h = 1; h <= column - 1; h++)
                        {
                            data[1, h] = only_data[1, h];
                            data[2, h] = only_data[2, h];
                            data[3, h] = only_data[3, h];
                            data[4, h] = only_data[4, h];
                            data[5, h] = only_data[5, h];
                            data[6, h] = only_data[6, h];
                        }

                        //고객사 계획 일자 헤더 생성.
                        DateTime Today = Convert.ToDateTime(WORK_FROM_KEY.Text);
                        data[5, 25] = string.Format("{0:M/d}", Today);

                        //총일
                        data[2, 8] = dt.Rows[0]["TOTAL_CNT"].ToString();
                        //지정일수
                        data[2, 9] = dt.Rows[0]["BACK_CNT"].ToString();

                        for (int i = 0; i <= dt.Rows.Count - 1; i++)
                        {
                            data[7 + i, 1] = dt.Rows[i]["Cust_Code"].ToString();
                            data[7 + i, 2] = dt.Rows[i]["VEND_NAME"].ToString();
                            data[7 + i, 3] = dt.Rows[i]["Delivery_Code"].ToString();
                            data[7 + i, 4] = dt.Rows[i]["Delivery_Name"].ToString();
                            data[7 + i, 5] = dt.Rows[i]["Part_No"].ToString();
                            data[7 + i, 6] = dt.Rows[i]["Cust_GridNo"].ToString();
                            data[7 + i, 7] = dt.Rows[i]["Part_Name"].ToString();
                            data[7 + i, 8] = dt.Rows[i]["LAST_FINQTY"].ToString();
                            data[7 + i, 9] = dt.Rows[i]["SELL_FINQTY"].ToString();
                            data[7 + i, 10] = dt.Rows[i]["SELL_RESULT"].ToString();
                            data[7 + i, 14] = dt.Rows[i]["AVG_CNT"].ToString();
                            data[7 + i, 15] = dt.Rows[i]["Min_Storage"].ToString();
                            data[7 + i, 16] = dt.Rows[i]["Max_Storage"].ToString();
                            data[7 + i, 17] = dt.Rows[i]["STORAGE_FINQTY"].ToString();
                            data[7 + i, 18] = dt.Rows[i]["WIP_FINQTY"].ToString();
                            data[7 + i, 20] = dt.Rows[i]["Cust_Plan_Qty"].ToString();
                            data[7 + i, 21] = dt.Rows[i]["Add_Cust_Plan_Qty"].ToString();
                            data[7 + i, 22] = dt.Rows[i]["Ship_LotQty"].ToString();
                            data[7 + i, 23] = dt.Rows[i]["Cust_SafeQty"].ToString();
                            data[7 + i, 25] = dt.Rows[i]["Cust_Qty"].ToString();
                            data[7 + i, 72] = dt.Rows[i]["D0"].ToString();
                            data[7 + i, 73] = dt.Rows[i]["D1"].ToString();
                            data[7 + i, 74] = dt.Rows[i]["D2"].ToString();
                            data[7 + i, 75] = dt.Rows[i]["D3"].ToString();
                            data[7 + i, 76] = dt.Rows[i]["D4"].ToString();
                            data[7 + i, 77] = dt.Rows[i]["D5"].ToString();
                            data[7 + i, 78] = dt.Rows[i]["D6"].ToString();
                            data[7 + i, 79] = dt.Rows[i]["D7"].ToString();
                            data[7 + i, 80] = dt.Rows[i]["D8"].ToString();
                            data[7 + i, 81] = dt.Rows[i]["D9"].ToString();
                            data[7 + i, 82] = dt.Rows[i]["D10"].ToString();
                            data[7 + i, 83] = dt.Rows[i]["D11"].ToString();
                            data[7 + i, 84] = dt.Rows[i]["D12"].ToString();
                            data[7 + i, 85] = dt.Rows[i]["D13"].ToString();
                        }

                        rng.Value = data;
                    }

                    SubForms.SplashWnd.SplashClose(this);

                    if (File.Exists(ExcelEndPath)) File.Delete(ExcelEndPath);
                    workbook.SaveAs(ExcelEndPath);

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

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                    workbook.Close(true, null, null);
                    app.Quit();

                    ReleaseExcelObject(app);
                    ReleaseExcelObject(workbook);
                    ReleaseExcelObject(workbooks);
                    ReleaseExcelObject(worksheet);
                    ReleaseExcelObject(sheets);
                }
                finally
                {
                    workbook.Close(true, null, null);
                    app.Quit();

                    ReleaseExcelObject(app);
                    ReleaseExcelObject(workbook);
                    ReleaseExcelObject(workbooks);
                    ReleaseExcelObject(worksheet);
                    ReleaseExcelObject(sheets);
                }
            }
        }
        
private void ReleaseExcelObject(object obj)
        {
            try
            {
                if (obj != null)
                {
                    Marshal.ReleaseComObject(obj);
                    obj = null;
                }
            }
            catch (Exception ex)
            {
                obj = null;
                throw ex;
            }
            finally
            {
                GC.GetTotalMemory(false);
                GC.Collect();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                GC.GetTotalMemory(true);
            }
        }

 

전체 소스입니다

 

해당 문제 해결 방법은 object[,] 였습니다

 

템플릿화 된 문서를 불러와서 object[,] 배열에 담아주고 object[,] 배열의 값을

 

수정하여 완성된 데이터를 배열에서 만들어 준뒤에 range 함수의 Value를 통해 BulkInsert를 실행해 주는것입니다

 

구문별로 설명을 다시 한면

 

 

위의 소스 코드 영역은 엑셀 파일(템플릿)을 불러와 첫번째 시트 중 A1부터 CG3000까지를 영역 설정을 지정하는

 

구문 입니다

 

선택된 영역의 내용을 only_data라는 object[,] 배열에 담아 줍니다

 

 

only_data의 object[,]배열을 동일한 object 배열인 data의 배열로 복사 합니다

 

이유는 onlu_data를 직접수정하게되면  기존 속도하고 큰 차이가 없어지게 됩니다

 

예를들면 100 = 100으로 복사한 뒤에 10, 50, 60의 수치를 변경한다고 헀을 경우 

 

결국 100을 모두 조회 해야 하기 때문입니다

 

하지만 위의 처럼 오브젝트를 두개를 선언해서 1개의 오브젝는 100

 

나머지 한개의 오브젝트에는 필요한 수지만 10, 50, 60만 지정합니다

 

그럼 데이터를 쓰기 할 경우 10, 50, 60만 조회 하면 되기 때문에 속도가 빨라지겠죠

 

 

data 오브젝트 배열에 필요한 값 만큼만 지정하여 입력해 줍니다

 

직접 Cells를 사용하여 엑셀 문서에 데이터를 조합하는것이 아닌 object[,]의 내용을 조합하는 것 입니다

 

 

다음 조합된 오브젝트 배열을 엑셀 함수인 Range.Value를 사용하여 오브젝트를 바로 넣어주게 되면

 

끝이됩니다

 

속도 차이는 

* 500개 Row 기준

   1) Cells 함수 사용시 10~15분 소요

   2) 1개의 오브젝트 사용시 5~10분 소요

   3) 2개의 오브젝트 사용시 1분 미만

 

이런 결과가 테스트 되었습니다

 

혹시 저 처럼 속도 문제로 머리 썪고 계시다면 한번 적용 해보시기 바랍니다

 

반응형
반응형

안녕하세요

 

코딩연습생입니다

 

C# WINFORM 환경에서 DB 위치에서 데이터를 받아 DataGridView에 데이터를 바인딩 한뒤

 

Row추가 진행시 다음과 같은 오류가 발생합니다

 

이럴경우 DataTable를 이용해서 해결 할 수 있는데요

 

일단 프로시져의 내용을 DataGridView에 바인딩 시켜 줍니다.

private void Load()
        {
            string query = "EXEC SP_SHIP_DELIVERY_LIST";
            query += "           'SELECT',";                         //구분
            query += "           '" + textBox1.Text + "',";          //Cust_Code
            query += "           '" + textBox3.Text + "',";          //Delivery_Code
            query += "           '" + textBox2.Text + "',";          //Part_Code
            query += "           '" + textBox4.Text + "',";          //Cust_GridNo
            query += "           '',";                               //Part_Name
            query += "           '',";                               //Active
            query += "           ''";                                //Remark
            SAC_MesDB db = new SAC_MesDB();
            
            dataGridView1.DataSource = db.ExcuteQuery(query);

            dataGridView1.Columns[0].ReadOnly = true;
            dataGridView1.Columns[1].ReadOnly = true;
            dataGridView1.Columns[2].ReadOnly = true;
        }

간단합니다.

 

MSSQL에 있는 SP_SHIP_DELIVERY_LIST 프로시져를 호출해서 DataGridView에 바인딩 시키는 부분입니다

 

그런데 문제는 이게 아니죠

 

DataGridView에 데이터바인딩 이후에 Row 추가를 하게 되면 다음과 같은 오류가 발생합니다

 

"컨트롤이 데이터 바인딩된 경우에는 datagridview의 행 컬렉션에 프로그래밍 방식으로 행을 추가할 수 없습니다"

 

그래서 폭풍 검색을 했더니 DataTable에 담아 그리드가 아닌 dt에 Row를 추가하면 동작한다고 해서 변경해 봤습니다

 

private void Load()
        {
        	DataTable dt = new DataTable();
            
            string query = "EXEC SP_SHIP_DELIVERY_LIST";
            query += "           'SELECT',";                         //구분
            query += "           '" + textBox1.Text + "',";          //Cust_Code
            query += "           '" + textBox3.Text + "',";          //Delivery_Code
            query += "           '" + textBox2.Text + "',";          //Part_Code
            query += "           '" + textBox4.Text + "',";          //Cust_GridNo
            query += "           '',";                               //Part_Name
            query += "           '',";                               //Active
            query += "           ''";                                //Remark
            SAC_MesDB db = new SAC_MesDB();
            
            dt = new DataTable();
            
            dt = db.ExcuteQuery(query);
            
            dataGridView1.DataSource = dt;

            dataGridView1.Columns[0].ReadOnly = true;
            dataGridView1.Columns[1].ReadOnly = true;
            dataGridView1.Columns[2].ReadOnly = true;
        }

이렇게 구문을 바꾸어서 Row를 추가해 봤습니다

 

Row를 추가하는 버튼 이벤트 입니다

private void hoverGradientButton3_Click(object sender, EventArgs e)
        {
            int MaxRow = dataGridView1.Rows.Count;

            if (MaxRow >= 0)
            {
                if (dataGridView1.Rows[MaxRow - 1].Cells[0].Value.ToString() != "")
                {
                    string[] row0 = { "", "", "", "", "", "", "" };
                    dt.Rows.Add(row0);
                    
                    dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[0].Style.BackColor = Color.Yellow;
                    dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[1].Style.BackColor = Color.Yellow;
                    dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[2].Style.BackColor = Color.Yellow;
                }
                else
                {
                    MessageBox.Show("추가 등록은 한번에 하나씩만 가능합니다.");
                }
            }
        }

 

오옷!! 동작을 합니다

처음 바인딩 후 동작

단, 이상한 현상이 발생했습니다

 

처음 데이터 바인딩 이후에는 잘 추가가 되는데 한번 바인딩이 된 이후에 데이터가 재 바인딩 되면 MaxRow를 

 

찾기 못하고 추가가 되지 않는 현상이 발생합니다

 

재바인딩 후 동작

음...뭐가 문제인지 모르겠지만 구문을 다시 한번 바꾸어 봤습니다

 

폼의 상단에 DataTable를 선언합니다

 

private DataTable dt;

조회되는 부분에서는 프로시져만 호출하고 바인딩 시킵니다

private void Load()
        {
            string query = "EXEC SP_SHIP_DELIVERY_LIST";
            query += "           'SELECT',";                         //구분
            query += "           '" + textBox1.Text + "',";          //Cust_Code
            query += "           '" + textBox3.Text + "',";          //Delivery_Code
            query += "           '" + textBox2.Text + "',";          //Part_Code
            query += "           '" + textBox4.Text + "',";          //Cust_GridNo
            query += "           '',";                               //Part_Name
            query += "           '',";                               //Active
            query += "           ''";                                //Remark
            SAC_MesDB db = new SAC_MesDB();

            dataGridView1.DataSource = db.ExcuteQuery(query);

            dataGridView1.Columns[0].ReadOnly = true;
            dataGridView1.Columns[1].ReadOnly = true;
            dataGridView1.Columns[2].ReadOnly = true;

        }

 

Row 추가 이벤트 구문에서 DataTable를 선언하고 Row 추가 이후에 DataTable에 신규 Row를 추가 합니다

 

        private void hoverGradientButton3_Click(object sender, EventArgs e)
        {
            int MaxRow = dataGridView1.Rows.Count;

            if (MaxRow >= 0)
            {
                if (dataGridView1.Rows[MaxRow - 1].Cells[0].Value.ToString() != "")
                {
                    dt = new DataTable();
                    dt = dataGridView1.DataSource as DataTable;
                    string[] row0 = { "", "", "", "", "", "", "" };
                    dt.Rows.Add(row0);
                    dataGridView1.DataSource = dt;
                    
                    dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[0].Style.BackColor = Color.Yellow;
                    dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[1].Style.BackColor = Color.Yellow;
                    dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[2].Style.BackColor = Color.Yellow;
                }
                else
                {
                    MessageBox.Show("추가 등록은 한번에 하나씩만 가능합니다.");
                }
            }
        }

 

이렇게 변경하고 실행을 해 보았습니다

 

역시 처음 바인딩시에는 정상적으로 잘 되는것을 확인했습니다

 

다음은 재바인딩 후에 실행해 보겠습니다

 

 정상적으로 추가되는 모습을 확인할 수 있습니다

 

이렇게 동일한 방식으로도 어는 위치에서 동작하는지에 따라 문제가 될 수 있다는걸 알 수 있는 계기였습니다ㅎ

(이걸 찾아내는냐고 2시간을 버렸네요..ㅠ)

 

문제없이 디버깅 통과 모습

저와 같은 문제로 고민 하는 분이라면 이렇게 DataTable 위치를 변경해서 구동 해 보시기 바랍니다

 

 

반응형
반응형

안녕하세요

 

코딩연습생입니다

 

C# Winform에서 oledb를 사용하여 엑셀 연동을 구현하실때 다음과 같은 오류가 간혹 나타납니다

 

이럴 경우 조치 할 수 있는 방법에 대해 포스팅 해보도록 하겠습니다

 

해결 방법은 Access 패키지 설치 입니다

 

1. AccessRuntime 설치

   - https://www.microsoft.com/en-us/download/details.aspx?id=39358

 

Microsoft Access 2013 Runtime

The Microsoft Access 2013 Runtime enables you to distribute Access 2013 applications to users who do not have the full version of Access 2013 installed on their computers.

www.microsoft.com

해당 링크에서 다운로 받아 설치 합니다

 

2. Microsoft Access Database Engine 2016 Redistributable 설치

   - https://www.microsoft.com/en-us/download/details.aspx?id=54920

 

Microsoft Access Database Engine 2016 Redistributable

This download will install a set of components that can be used to facilitate transfer of data between Microsoft Office System files and non-Microsoft Office applications.

www.microsoft.com

 

설치에는 별다른게 없이 다음 버튼만 누루면 설치가 완료 됩니다

 

설치 이후 컴퓨터 재부팅 후에 재실행 하시면 해당 오류가 해결 된 걸 보실 수 있습니다

 

반응형
반응형

안녕하세요

 

코딩연습생입니다

 

이번 포스팅은 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()가 호출되어 지는 겁니다

 

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

 

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

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

 

 

반응형
반응형

안녕하세요

 

코딩연습생입니다~

 

블로그를 운영한지 몇달이 지났는데 아직도 수익은 일일 천원을 못넘기고 있네요ㅎㅎ

 

하루 100원 정도 수익금이 나오고 있습니다~

 

대단하죠?ㅎㅎ

 

애드센스 싸이트에서 이상한 경고나 나타나서 확인을 해보니

 

"주소를 확인하지 않아 지급이 보류 중입니다"

 

이거 뭔말인가해서 검색을 해봤지요ㅎ

 

구글 애드센스 계정을 생성하고 활동하여 발생한 수익금이 10달러 이상이 되면 인증?을 위해

 

계정에 등록한 주소지가 실거주지가 맞는지 확인을 하기 위한 인증 절차를 거쳐야 한다는 말입니다

 

그래서 애드센스 싸이트에서 아래와 같은 창을 보실 수 있는데요

 

 

앞에 일자가 나오는데 왠지 창피해서 비공개로 캡쳐 하였습니다ㅎㅎ

 

그리고 대략 25일뒤에 집으로 우편이 날라 왔습니다

 

급한 마음에 빨리 뜯어보았는데요ㅎ 이렇게 생겼습니다

 

 

뭔가 구글에서 받아본게 처음이라 그런지 설레더라구요ㅋㅋㅋ

 

안에 내용은 뭐 큰거 없이 PIN번호화 PIN번호 등록 방법이 기술되어 있습니다

 

 

우측 중앙에 있는 파란색 글씨의 PIN 번호를 구글 애드센스 싸이트의 제출 화면에 등록하면 끝이 납니다

 

 

혹시 애드센스 계정의 주소와 실거주 주소가 다를 경우 다음 방법으로 재인증 절차를 실행 하면 됩니다

 

● 애드센스 홈페이지 -> 메뉴탬 -> 계정 -> 계정 정보 -> 주소 확인

 

주소를 수정한 후에 재발급 받을 수 있는 시간이 조금 소요 된다니 기다려 보시면 됩니다

 

반응형
반응형

안녕하세요

 

코딩연습생입니다

 

이번 포스팅 주제는 투명 팝업창을 이용한 ProgressBar 만들기 입니다

 

프로그래스바란?

.NET에서 진행율을 표기하기 위한 그래픽 컨트롤 입니다

 

비쥬얼스튜디오의 도구 모음에 기본 도구로 있는데요

 

대충 이렇게 생긴 모습입니다

 

흔히 프로그램을 사용하다보면 업데이트나 데이터 처리를 할때 사용자에게 얼마큼 진행되었는지를 알려주기위해

 

사용합니다

 

이런 컨트롤을 팝업창을 통해 메인 Form위에 투명으로 띄워 진행 여부를 표시해주는 팝업을 생성해볼려고 합니다

 

일단 팝어창을 만들기 위해 From을 하나 생성합니다

 

그리고 생성된 폼 속정에서 TransparencyKey를 배경색과 동일하게 설정 합니다

 

이렇게 설정하시면 해당 폼이 팝업으로 띄워졌을때 주변 배경이 투명으로 처리되어 보여지게 됩니다

 

그리고 무언가 처리중인걸 표시하기 위해 픽쳐박스 컨트롤에 GIF 파일을 넣어 줄겁니다

 

PictureBox 컨트롤을 팝업 폼에 생성하고 그림박스의 배경 이미지를 GIF 파일로 넣어줍니다

 

참고로 진행 상태 GIF는 아래 링크 페이지를 활용하시면 됩니다

 

https://www.sitepoint.com/demos/loading-images/

 

AJAX Loading Images Collections | SitePoint

 

www.sitepoint.com

 

여기까지 설정을 하셨다면 아래와 같은 화면이 구성 될겁니다

 

 

그럼 cs코드 안으로 들어가서 아래와 같이 Using을 선언 합니다

 

using System.Threading;
using System.Runtime.InteropServices;
using System.Resources;

 

쓰레드는 GIF를 움직이기 위해 필요하고

 

인터럽트서비스는 팝업창을 핸들링하기 위해 필요합니다

 

그리고 마지막 리소스는 GIF를 등록하게 되면 이미지가 리소스로 들어가기 때문에 선언 햇습니다

 

public partial class SplashWnd : Form
    {
        Bitmap bit;

        #region Static Function
        /// 
        /// 스플래쉬 닫을 때 true로 세팅하는 값
        /// 
        private static bool isCloseCall = false;

        /// 
        /// 스플래쉬 띄우기
        /// 
        public static void SplashShow()
        {
            System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess();
            Control mainWindow = Control.FromHandle(process.MainWindowHandle);

            isCloseCall = false;
            Thread thread = new Thread(new ParameterizedThreadStart(ThreadShowWait));
            thread.Start(new object[] { mainWindow });
        }

        /// 
        /// 스플래쉬 닫기
        /// 
        /// 스플래쉬를 닫은 후 맨 앞으로 가져올 폼
        public static void SplashClose(Form formFront)
        {
            //Thread의 loop 를 멈춘다.
            isCloseCall = true;

            //주어진 폼을 맨 앞으로
            SetForegroundWindow(formFront.Handle);
            formFront.BringToFront();
        }

        /// 

        /// 윈도우를 맨 앞으로 가져오기 위한 Win32 API 메서드
        /// 
        /// 윈도우 핸들
        /// 
        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        /// 

        /// 스플래쉬를 띄우기 위한 Parameterized Thread Method
        /// 
        /// 메인 윈도(위치를 잡기 위해)
        private static void ThreadShowWait(object obj)
        {
            object[] objParam = obj as object[];
            SplashWnd splashWnd = new SplashWnd();
            Control mainWindow = objParam[0] as Control;

            if (mainWindow != null)
            {
                //메인 윈도를 알 때에는 메인 윈도의 중앙
                splashWnd.StartPosition = FormStartPosition.Manual;
                splashWnd.Location = new Point(
                    mainWindow.Location.X + (mainWindow.Width - splashWnd.Width) / 2,
                    mainWindow.Location.Y + (mainWindow.Height - splashWnd.Height) / 2);
            }
            else
            {
                //메인 윈도를 모를 땐 스크린 중앙
                splashWnd.StartPosition = FormStartPosition.CenterScreen;
            }

            splashWnd.Show();
            splashWnd.BringToFront();

            //닫기 명령이 올 때 가지 0.01 초 단위로 루프
            while (!isCloseCall)
            {
                Application.DoEvents();
                Thread.Sleep(10);
            }

            //닫는다.
            if (splashWnd != null)
            {
                splashWnd.CloseForce();
                splashWnd = null;
            }
        }

        #endregion Static Function


        #region SplashWnd Member, Function, Event

        /// 

        /// 값이 true 이면 창이 닫히지 않음.
        /// 
        private bool cannotClose = true;

        /// 

        /// 생성자
        /// 
        public SplashWnd()
        {
            InitializeComponent();

            //투명도는 줘도 되고 안 줘도 되고
            this.Opacity = 0.7f;

        }

        /// 

        /// 사용자가 ALT+F4 등의 키로 닫는 걸 방지
        /// 
        /// 
        protected override void OnClosing(CancelEventArgs e)
        {
            if (cannotClose)
            {
                e.Cancel = true;
                return;
            }

            base.OnClosing(e);
        }

        /// 

        /// 이 메서드를 호출해야만 창이 닫힌다.
        /// 
        public void CloseForce()
        {
            //OnClose 에서 닫힐 수 있도록 세팅
            cannotClose = false;
            this.Close();
        }
        #endregion SplashWnd Member, Function, Event

        protected override void OnLoad(EventArgs e)
        {
            ResourceManager rm = Properties.Resources.ResourceManager;
            Bitmap normal = (Bitmap)rm.GetObject("loading14");
            bit = new Bitmap(normal);
            ImageAnimator.Animate(bit, new EventHandler(this.OnFrameChanged));
            base.OnLoad(e);

        }

        protected override void OnPaint(PaintEventArgs e)
        {
            ImageAnimator.UpdateFrames();
            Graphics g = pictureBox1.CreateGraphics();
            g.DrawImage(this.bit, new Point(0, 0));
            base.OnPaint(e);
        }

        private void OnFrameChanged(object sender, EventArgs e)
        {
            this.Invalidate();
        }
    }

 

그 다음 ProgressBar를 사용하시고자 하는 위치에서

 

SplashWnd.SplashShow();

 

구분을 사용해서 팝업을 생성해주고

 

진행이 끝난뒤 아래 구분을 통해 팝업창을 해제 합니다

 

SplashWnd.SplashClose(this);

 

사용자가 내가 만든 프로그램 안에서 어떤 행위가 진행 될때 알려주기 위한 표시기 역할로 만들것이기 때문에

 

프로그램에서 행위가 일어나기전과 끝난뒤에 위의 구문을 넣어주면 무언가 진행되어지는것을 알려줄수 있습니다

 

반응형
반응형

안녕하세요

 

코딩 연습생 입니다

 

이전 포스팅에서 직접 엑셀의 API를 활용하여 엑셀파일의 내용을 불러와 데이터그리드뷰와 연동하는 포스팅을

 

업로드했었는데요

 

https://codingman.tistory.com/100

 

[C#] 엑셀 템플릿파일 불러오기 및 값 넣기

안녕하세요 코딩 연습생입니다 아직도 코로나19로 인해서 기업들 소상인 분들 모두 참 어렵게 지내고 계시는거 같습니다 저 또한 회사원으로 회사가 많이 힘들어 지고 있다고 체감할 정도니깐요 그래도 국가에서..

codingman.tistory.com

 

이전 포스팅 방식으로 직접 구현을 해보신 분이나 관련 내용을 아시는분들이라면 아실것 같은데요

 

위의 방법으로 구현했을시(직접 엑셀을 임포트하는 방식) 제일 큰 단점은 대량을 엑셀 파일을 읽을때

 

엄청 느리다는것 입니다

 

그것을 조금이나마 해결하고자 엑셀의 문서 속성을 변경하여 이용하는데

 

https://codingman.tistory.com/101

 

[C#] 엑셀 Cells 사용시 속도 문제 해결하기

안녕하세요. 코딩연습생입니다. 정말 오랜만에 글을 쓰는거 같습니다.. 회사 프로젝트 진행 때문에 시간을 너무 빼앗겨 버리네요ㅎㅎ 근데 저도 이제 블로거가 다 된거 같습니다 하루에도 몇번씩 포스팅 걱정을 하..

codingman.tistory.com

 

이것도 전에 포스팅했었네요ㅎㅎ 근데 이 방법도 미미한 차이일뿐 사용자는 크게 느끼지 못합니다

 

그래서 이번에 포스팅할 내용은 직접 엑셀을 임포는하는 방식이 아닌 OleDbConnection을 이용한 엑셀 연동 방식으로

 

구현을 해볼려고 합니다

 

아마 이미 정보가 많이 있어서 한번쯤 구현을 해보시지 않았을까 싶은데요

 

하나씩 쉽게 이해할수 있도록 순서대로 포스팅해보도록 할께요

 

첫번재는 해당 From에서 OleDb를 사용하기 위한 선언부 입니다

 

아마 닷넷 4버전 이상을 사용하시는분이라면 기본적으로 포함되어 있을건데

 

혹시 프로젝트의 참조부분에 System.Data가 있는지 확인한 후에 없으시면 참조추가를 사용해서 추가해 줍니다

 

 

그리고 From의 제일 상단위에 다음과 같이 선언을 합니다

 

using System.Data.OleDb;

 

사실 윈도우에서 기본 사용이 가능해야 하는데 오류가 발생을 많이 합니다

 

그래서 사전 배포를 용이하게 하기 위해서 몇가지 설치 파일을 설치 해야합니다

 

해당 패키지를 설치 하지 않고 배포 하시면

 

"Microsoft.ACE.OLEDB.12.0 공급자는 로컬 컴퓨터에 등록할 수 없습니다.(System.Data)"

위와 같은 오류를 경험하게 되십니다ㅎㅎ

 

저와 같은 경험을 하지 않게 해드리기 위해서 미리 패키지 설치까지 합니다

 

http://www.microsoft.com/ko-kr/download/details.aspx?id=13255

 

Microsoft Access Database Engine 2010 재배포 가능 패키지

이 다운로드를 실행하면 2010 Microsoft Office System 파일과 Microsoft Office가 아닌 다른 응용 프로그램 사이에서 데이터를 쉽게 전송할 수 있는 구성 요소 집합이 설치됩니다.

www.microsoft.com

위의 주소로 접속해서 32비트 & 64비트 설치 파일을 모두 설치 해주세요

 

그다음 비쥬얼스튜디오로 돌아와서 From에 버튼을 하나 생성해 줍니다

 

저는 기존 소스를 이용하겠습니다

 

 

이렇게 버튼을 하나 준비해 주시구요

 

버튼의 Click 이벤트를 만들어 주세요

 

만드신 이벤트안에 아래의 소스코드를 만들어 줍니다

 

private void hoverGradientButton10_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Title = "엑셀 파일 선택하세요";
            openFileDialog.Filter = "Excel Files|*.xls;*.xlsx;*.xlsm";
            DialogResult result = openFileDialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                SubForms.SplashWnd.SplashShow();

                this.Cursor = Cursors.WaitCursor;
                //엑셀 앱
                Excel.Application app = new Excel.Application();
                app.DisplayAlerts = false;
                app.Visible = false;
                app.ScreenUpdating = false;
                app.DisplayStatusBar = false;
                app.EnableEvents = false;

                Excel.Workbooks workbooks = app.Workbooks;

                //엑셀 워크북(파일경로읽어서)
                //Excel.Workbook workbook = workbooks.Open(openFileDialog.FileName);
                Excel.Workbook workbook = workbooks.Open(openFileDialog.FileName, 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
                // 엑셀 워크싯 객체
                Excel.Sheets sheets = workbook.Worksheets;
                Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1);

                // 엑셀파일 이름이 나온다
                string excelFileName = workbook.Name;
                //excelFileName = excelFileName.Substring(book.Name.Length-3);
                string[] str = excelFileName.Split('.');
                // 워크시트 첫번째 이름
                string workSheetName = worksheet.Name;

                try
                {
                    if (str[1].Equals("xls"))
                    {
                        // 연결 string
                        string constr = "provider=Microsoft.Jet.OLEDB.4.0;Data Source='"
                      + openFileDialog.FileName + "';Extended Properties=Excel 8.0;";

                        //경로까지 다 포함해서 .xls라고 뜨네;
                        //MessageBox.Show(openFileDialog.FileName);

                        // excel conn
                        OleDbConnection conn = new OleDbConnection(constr);

                        // excel cmd
                        OleDbCommand cmd = new OleDbCommand("SELECT * FROM [" + workSheetName + "$]", conn);
                        conn.Open();

                        OleDbDataAdapter sda = new OleDbDataAdapter(cmd);
                        DataTable dt = new DataTable();
                        sda.Fill(dt);
                        this.Cursor = Cursors.WaitCursor;
                        dataGridView1.DataSource = dt;
                        this.Cursor = Cursors.Default;
                        conn.Close();


                    }
                    else if (str[1].Equals("xlsx"))
                    {
                        // 연결 string
                        String constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" +
                        openFileDialog.FileName +
                        ";Extended Properties='Excel 12.0 XML;HDR=No;IMEX=1';";

                        //경로까지 다 포함해서 .xls라고 뜨네;
                        //MessageBox.Show(openFileDialog.FileName);

                        // excel conn
                        OleDbConnection conn = new OleDbConnection(constr);

                        // excel cmd
                        OleDbCommand cmd = new OleDbCommand("SELECT * FROM [" + workSheetName + "$]", conn);
                        conn.Open();

                        OleDbDataAdapter sda = new OleDbDataAdapter(cmd);
                        DataTable dt = new DataTable();
                        sda.Fill(dt);

                        int j = 0;
                        //dataGridView1.DataSource = dt;
                        for(int i=6; i<=dt.Rows.Count-1; i++)
                        {
                            
                            dataGridView2.Rows.Add(1);
                            dataGridView2.Rows[j].Cells[0].Value = dt.Rows[i][0].ToString();
                            dataGridView2.Rows[j].Cells[1].Value = dt.Rows[i][2].ToString();
                            dataGridView2.Rows[j].Cells[2].Value = dt.Rows[i][4].ToString();
                            dataGridView2.Rows[j].Cells[3].Value = dt.Rows[i][5].ToString();
                            dataGridView2.Rows[j].Cells[4].Value = dt.Rows[i][6].ToString();
                            dataGridView2.Rows[j].Cells[5].Value = dt.Rows[i][7].ToString();
                            dataGridView2.Rows[j].Cells[6].Value = dt.Rows[i][8].ToString();
                            dataGridView2.Rows[j].Cells[7].Value = dt.Rows[i][9].ToString();
                            dataGridView2.Rows[j].Cells[8].Value = dt.Rows[i][10].ToString();
                            dataGridView2.Rows[j].Cells[9].Value = dt.Rows[i][11].ToString();
                            dataGridView2.Rows[j].Cells[10].Value = dt.Rows[i][12].ToString();
                            dataGridView2.Rows[j].Cells[11].Value = dt.Rows[i][13].ToString();
                            dataGridView2.Rows[j].Cells[12].Value = dt.Rows[i][14].ToString();
                            dataGridView2.Rows[j].Cells[13].Value = dt.Rows[i][15].ToString();
                            dataGridView2.Rows[j].Cells[14].Value = dt.Rows[i][16].ToString();
                            dataGridView2.Rows[j].Cells[15].Value = dt.Rows[i][17].ToString();
                            dataGridView2.Rows[j].Cells[16].Value = dt.Rows[i][18].ToString();
                            dataGridView2.Rows[j].Cells[17].Value = dt.Rows[i][19].ToString();
                            dataGridView2.Rows[j].Cells[18].Value = dt.Rows[i][20].ToString();
                            dataGridView2.Rows[j].Cells[19].Value = dt.Rows[i][21].ToString();
                            dataGridView2.Rows[j].Cells[20].Value = dt.Rows[i][22].ToString();
                            dataGridView2.Rows[j].Cells[21].Value = dt.Rows[i][23].ToString();
                            dataGridView2.Rows[j].Cells[22].Value = dt.Rows[i][24].ToString();
                            dataGridView2.Rows[j].Cells[23].Value = dt.Rows[i][25].ToString();
                            dataGridView2.Rows[j].Cells[24].Value = dt.Rows[i][26].ToString();
                            dataGridView2.Rows[j].Cells[25].Value = dt.Rows[i][27].ToString();
                            dataGridView2.Rows[j].Cells[26].Value = dt.Rows[i][28].ToString();
                            dataGridView2.Rows[j].Cells[27].Value = dt.Rows[i][29].ToString();
                            dataGridView2.Rows[j].Cells[28].Value = dt.Rows[i][30].ToString();
                            dataGridView2.Rows[j].Cells[29].Value = dt.Rows[i][31].ToString();
                            dataGridView2.Rows[j].Cells[30].Value = dt.Rows[i][32].ToString();
                            dataGridView2.Rows[j].Cells[31].Value = dt.Rows[i][33].ToString();
                            dataGridView2.Rows[j].Cells[32].Value = dt.Rows[i][34].ToString();
                            dataGridView2.Rows[j].Cells[33].Value = dt.Rows[i][35].ToString();
                            dataGridView2.Rows[j].Cells[34].Value = dt.Rows[i][36].ToString();
                            dataGridView2.Rows[j].Cells[35].Value = dt.Rows[i][37].ToString();
                            dataGridView2.Rows[j].Cells[36].Value = dt.Rows[i][38].ToString();
                            dataGridView2.Rows[j].Cells[37].Value = dt.Rows[i][39].ToString();
                            dataGridView2.Rows[j].Cells[38].Value = dt.Rows[i][40].ToString();
                            dataGridView2.Rows[j].Cells[39].Value = dt.Rows[i][41].ToString();
                            dataGridView2.Rows[j].Cells[40].Value = dt.Rows[i][42].ToString();
                            dataGridView2.Rows[j].Cells[41].Value = dt.Rows[i][43].ToString();
                            dataGridView2.Rows[j].Cells[42].Value = dt.Rows[i][44].ToString();
                            dataGridView2.Rows[j].Cells[43].Value = dt.Rows[i][45].ToString();
                            dataGridView2.Rows[j].Cells[44].Value = dt.Rows[i][46].ToString();
                            dataGridView2.Rows[j].Cells[45].Value = dt.Rows[i][47].ToString();
                            dataGridView2.Rows[j].Cells[46].Value = dt.Rows[i][48].ToString();
                            dataGridView2.Rows[j].Cells[47].Value = dt.Rows[i][49].ToString();
                            dataGridView2.Rows[j].Cells[48].Value = dt.Rows[i][50].ToString();
                            dataGridView2.Rows[j].Cells[49].Value = dt.Rows[i][51].ToString();
                            dataGridView2.Rows[j].Cells[50].Value = dt.Rows[i][52].ToString();
                            dataGridView2.Rows[j].Cells[51].Value = dt.Rows[i][53].ToString();
                            dataGridView2.Rows[j].Cells[52].Value = dt.Rows[i][54].ToString();
                            dataGridView2.Rows[j].Cells[53].Value = dt.Rows[i][55].ToString();
                            dataGridView2.Rows[j].Cells[54].Value = dt.Rows[i][56].ToString();
                            dataGridView2.Rows[j].Cells[55].Value = dt.Rows[i][57].ToString();
                            dataGridView2.Rows[j].Cells[56].Value = dt.Rows[i][58].ToString();
                            dataGridView2.Rows[j].Cells[57].Value = dt.Rows[i][59].ToString();
                            dataGridView2.Rows[j].Cells[58].Value = dt.Rows[i][60].ToString();
                            dataGridView2.Rows[j].Cells[59].Value = dt.Rows[i][61].ToString();
                            dataGridView2.Rows[j].Cells[60].Value = dt.Rows[i][62].ToString();
                            dataGridView2.Rows[j].Cells[61].Value = dt.Rows[i][63].ToString();
                            dataGridView2.Rows[j].Cells[62].Value = dt.Rows[i][64].ToString();
                            dataGridView2.Rows[j].Cells[63].Value = dt.Rows[i][65].ToString();
                            dataGridView2.Rows[j].Cells[64].Value = dt.Rows[i][66].ToString();
                            dataGridView2.Rows[j].Cells[65].Value = dt.Rows[i][67].ToString();
                            dataGridView2.Rows[j].Cells[66].Value = dt.Rows[i][68].ToString();
                            dataGridView2.Rows[j].Cells[67].Value = dt.Rows[i][69].ToString();
                            dataGridView2.Rows[j].Cells[68].Value = dt.Rows[i][70].ToString();
                            dataGridView2.Rows[j].Cells[69].Value = dt.Rows[i][71].ToString();
                            dataGridView2.Rows[j].Cells[70].Value = dt.Rows[i][72].ToString();
                            dataGridView2.Rows[j].Cells[71].Value = dt.Rows[i][73].ToString();
                            dataGridView2.Rows[j].Cells[72].Value = dt.Rows[i][74].ToString();
                            dataGridView2.Rows[j].Cells[73].Value = dt.Rows[i][75].ToString();
                            dataGridView2.Rows[j].Cells[74].Value = dt.Rows[i][76].ToString();
                            dataGridView2.Rows[j].Cells[75].Value = dt.Rows[i][77].ToString();
                            dataGridView2.Rows[j].Cells[76].Value = dt.Rows[i][78].ToString();
                            dataGridView2.Rows[j].Cells[77].Value = dt.Rows[i][79].ToString();
                            dataGridView2.Rows[j].Cells[78].Value = dt.Rows[i][80].ToString();
                            dataGridView2.Rows[j].Cells[79].Value = dt.Rows[i][81].ToString();
                            dataGridView2.Rows[j].Cells[80].Value = dt.Rows[i][82].ToString();
                            dataGridView2.Rows[j].Cells[81].Value = dt.Rows[i][83].ToString();
                            
                            j++;
                        }

                        this.Cursor = Cursors.Default;
                        conn.Close();

                        Finish_Data_Insert();
                        SubForms.SplashWnd.SplashClose(this);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                    workbook.Close(true, null, null);
                    app.Quit();

                    ReleaseExcelObject(worksheet);
                    ReleaseExcelObject(sheets);
                    ReleaseExcelObject(workbook);
                    ReleaseExcelObject(workbooks);
                    ReleaseExcelObject(app);
                }
                finally
                {
                    workbook.Close(true, null, null);
                    app.Quit();

                    ReleaseExcelObject(worksheet);
                    ReleaseExcelObject(sheets);
                    ReleaseExcelObject(workbook);
                    ReleaseExcelObject(workbooks);
                    ReleaseExcelObject(app);
                }
            }
        }

 

오브젝트 초기화를 위해 아래 함수로 하나 작성해 줍니다

 

private void ReleaseExcelObject(object obj)
        {
            try
            {
                if (obj != null)
                {
                    Marshal.ReleaseComObject(obj);
                    obj = null;
                }
            }
            catch (Exception ex)
            {
                obj = null;
                throw ex;
            }
            finally
            {
                GC.Collect();
            }
        }

 

이렇게 해주시고 생성하신 버튼을 누구게 되면 OpenFileDialog가 열리고 거기서 엑셀 파일을 선택해 주시면

 

해당 엑셀의 문서 내용이 데이터그리드뷰에 옴겨지게 됩니다

 

위의 소스 내용중 "SubForms.SplashWnd.SplashShow();" 구문은 주석 또는 삭제 하셔도 무관합니다

 

해당 코드는 사용자에게 진행중을 표시하기 위한 ProgressBar를 구현한것인데 없어도 구동하는데 전혀 문제가 없습니다

 

해당 내용은 다른 포스팅에서 정리해서 올리도록 할께요

 

이전 방식과 현재의 방식을 모두 구현을 하셨다면 속도 비교를 해보시면 깜짝 놀라실수 있을겁니다

 

동일 엑셀 문서기준 (대략 Row가 1000개)의 파일을 불러오기 하였을때

 

기존방식 : 10~15분 소요

현재방식 : 30초 미만

 

엄청난 차이를 보여주더라구요

 

엑셀과 연동을 구현하기 위해 고민중이시라면 위의 방법을 통해 구현해 보시길 바랍니다

반응형
반응형

안녕하세요

 

코딩연습생입니다

 

이번 시간에 포스팅하고자 하는건 제목에도 나와 있지만

 

MSSQL을 통해서 C#으로 DataGridView 컨트롤의 컬럼을 동적으로 생성하게 하여

 

한 페이지에서 여러 Data를 조회 할 수 있는 유동적인 DataGirdView를 사용하는 방법을 포스팅 해볼려고 합니다

 

말은 거창한데 결국은 데이터그리드뷰의 속성을 하나씩 설정해서 유동적으로 사용하게 하는 방법입니다

 

첫번째는 조회 타입에 따라 변화 할 그리드뷰의 속성을 MSSQL에서 프로시져로 지정 합니다

 

IF @GUBUN = 'COL_CNT_MANDO'
		BEGIN
			SELECT 37 AS CNT    --전체 컬럼 출력수
		END
		
		IF @GUBUN = 'COL_CNT_ETC'
		BEGIN
			SELECT 22 AS CNT    --전체 컬럼 출력수
		END


		IF @GUBUN = 'COL_NAD_MANDO'
		BEGIN
			SELECT '고객코드' AS COL_NM
			UNION ALL
			SELECT '고객명' AS COL_NM
			UNION ALL
			SELECT 'ERP 품번' AS COL_NM
			UNION ALL
			SELECT '거래선 도번' AS COL_NM
			UNION ALL
			SELECT '납품처코드' AS COL_NM
			UNION ALL
			SELECT '납품처명' AS COL_NM
			UNION ALL
			SELECT '차종명' AS COL_NM
			UNION ALL
			SELECT '*D+0(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+0(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+1(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+1(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+2(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+2(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+3(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+3(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+4(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+4(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+5(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+5(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+6(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+6(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+7(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+7(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+8(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+8(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+9(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+9(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+10(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+10(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+11(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+11(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+12(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+12(야간)' AS COL_NM
			UNION ALL
			SELECT '*D+13(주간)' AS COL_NM
			UNION ALL
			SELECT '*D+13(야간)' AS COL_NM
		END

		IF @GUBUN = 'COL_NAD_ETC'
		BEGIN
			SELECT '고객코드' AS COL_NM
			UNION ALL
			SELECT '고객명' AS COL_NM
			UNION ALL
			SELECT 'ERP 품번' AS COL_NM
			UNION ALL
			SELECT '거래선 도번' AS COL_NM
			UNION ALL
			SELECT '납품처코드' AS COL_NM
			UNION ALL
			SELECT '납품처명' AS COL_NM
			UNION ALL
			SELECT '차종명' AS COL_NM
			UNION ALL
			SELECT '*D+0' AS COL_NM
			UNION ALL
			SELECT '*D+1' AS COL_NM
			UNION ALL
			SELECT '*D+2' AS COL_NM
			UNION ALL
			SELECT '*D+3' AS COL_NM
			UNION ALL
			SELECT '*D+4' AS COL_NM
			UNION ALL
			SELECT '*D+5' AS COL_NM
			UNION ALL
			SELECT '*D+6' AS COL_NM
			UNION ALL
			SELECT '*D+7' AS COL_NM
			UNION ALL
			SELECT '*D+8' AS COL_NM
			UNION ALL
			SELECT '*D+9' AS COL_NM
			UNION ALL
			SELECT '*D+10' AS COL_NM
			UNION ALL
			SELECT '*D+11' AS COL_NM
			UNION ALL
			SELECT '*D+12' AS COL_NM
			UNION ALL
			SELECT '*D+13' AS COL_NM
		END

위의 쿼리내용을 보게 되면 미리 타입에 따라 컬럼 갯수와 컬럼명칭을 설정해서 가져오기 위한 쿼리 입니다

 

유동적인 그리드뷰를 적용시킬 윈폼 페이지 안에 아래와 같이 코딩을 합니다

 

private void Grid_Column()
        {
            this.Cursor = Cursors.WaitCursor;   //마우스 커서를 Waitting

            dataGridView1.Rows.Clear();  //그리드뷰 초기화
            dataGridView1.Columns.Clear(); //

            string query = "";
            if (radioButton1.Checked == true)
            {
                query += "EXEC SP_SHIP_CUST_PLAN ";
                query += "     'COL_CNT_MANDO'";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";

            }
            else
            {
                query += "EXEC SP_SHIP_CUST_PLAN ";
                query += "     'COL_CNT_ETC'";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
            }
            
            
            //MSSQL 프로바이더
            DB db = new DB();
            DataTable dt = db.ExcuteQuery(query);

            //datatable의 내용을 그리드에 display
            foreach (DataRow row in dt.Rows)
            {
                dataGridView1.ColumnCount = Convert.ToInt32(row[0].ToString());
            }

            dt.Clear();


            query = "";
            if (radioButton1.Checked == true)
            {
                query += "EXEC SP_SHIP_CUST_PLAN ";
                query += "     'COL_NAD_MANDO'";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
            }
            else
            {
                query += "EXEC SP_SHIP_CUST_PLAN ";
                query += "     'COL_NAD_ETC'";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
                query += "    ,''";
            }
            dt = db.ExcuteQuery(query);

            int i = 0;

            //datatable의 내용을 그리드에 display
            foreach (DataRow row in dt.Rows)
            {
                dataGridView1.Columns[i].Name = row["COL_NM"].ToString();
                //sGridView1.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable;

                //숫자컬럼은 앞에*를 붙였기때문에 숫자컬럼은 모두 오른쪽 정렬을 취함
                if (row["COL_NM"].ToString().Substring(0, 1) == "*")
                {
                    dataGridView1.Columns[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;  //우측정렬
                }
                //문자열은 좌측정렬구분자를 공백으로 처리
                else if (row["COL_NM"].ToString().Substring(0, 1) == " ")
                {
                    dataGridView1.Columns[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;  //좌측정렬
                }
                else
                {
                    dataGridView1.Columns[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;  //가운데정렬
                }

                i++;
            }

            this.Cursor = Cursors.Default;
            dataGridView1.AllowUserToAddRows = false;
        }

 

여기서 MSSQL DB에 접속하기 위한 프로바이더는 별도 함수로 작성해서 사용하였습니다

 

함수 제작하는 방법은 아래 링크 페이지에서 확인 하시기 바랍니다

 

https://codingman.tistory.com/73

 

[C#] MSSQL 접속하고 사용하기

안녕하세요 C# 컨텐츠로 블로그를 운영중인 코딩 연습생입니다 이번 포스팅에서는 C#으로 MSSQL를 접속하고 쿼리문을 전송시켜 연동시키기까지 한번 해보도록 하겠습니다 일반적인 방법으로는 1) 접속정보 생성 2)..

codingman.tistory.com

 

이렇게 타입에 따른 그리드뷰 상세 옵션을 MSSQL에서 불러와서 그리드를 그려준뒤에 각 컬럼에 맞게 뿌려주면 됩니다

 

저는 유동적으로 생성된 그리드뷰에 엑셀파일을 불러오기로 구현하였습니다

 

private void hoverGradientButton3_Click(object sender, EventArgs e)
        {
            OpenFileDialog oFileDialog = new OpenFileDialog();
            oFileDialog.Filter = "Excel (*.xlsx)|*.xlsx|Excel 97-2003 (*.xls)|*.xls";

            if (oFileDialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            Excel.Application xlApp;
            Excel.Workbook xlWorkBook;
            Excel.Worksheet xlWorkSheet;
            Excel.Range range;

            string str;
            int rCnt = 0;
            int cCnt = 0;
            string sCellData = "";
            double dCellData;

            xlApp = new Excel.Application();
            xlApp.DisplayAlerts = false;
            xlApp.Visible = false;
            xlApp.ScreenUpdating = false;
            xlApp.DisplayStatusBar = false;
            xlApp.EnableEvents = false;

            SplashWnd.SplashShow();

            try
            {
                xlWorkBook = xlApp.Workbooks.Open(oFileDialog.FileName, 0, true, 5, "", "", true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
                xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

                range = xlWorkSheet.UsedRange;

                DataTable dt = new DataTable();

                // 첫 행을 제목으로
                for (cCnt = 1; cCnt <= range.Columns.Count; cCnt++)
                {
                    str = (string)(range.Cells[1, cCnt] as Excel.Range).Value2;
                    dt.Columns.Add(str, typeof(string));
                }

                for (rCnt = 3; rCnt <= range.Rows.Count; rCnt++)
                {
                    string sData = "";
                    for (cCnt = 1; cCnt <= range.Columns.Count; cCnt++)
                    {
                        try
                        {
                            sCellData = (string)(range.Cells[rCnt, cCnt] as Excel.Range).Value2;
                            sData += sCellData + "|";
                        }
                        catch (Exception ex)
                        {
                            dCellData = (double)(range.Cells[rCnt, cCnt] as Excel.Range).Value2;
                            sData += dCellData.ToString() + "|";
                        }
                    }
                    sData = sData.Remove(sData.Length - 1, 1);
                    dt.Rows.Add(sData.Split('|'));
                }

                int i = 0;

                if (radioButton1.Checked == true)
                {
                    foreach (DataRow row in dt.Rows)
                    {
                        dataGridView1.Rows.Add(1);

                        for (int j=0; j<= 34; j++)
                        {    
                            dataGridView1.Rows[i].Cells[j].Value = dt.DefaultView[i][j].ToString();
                        }
                       
                        i++;
                    }
                }
                else
                {
                    foreach (DataRow row in dt.Rows)
                    {
                        dataGridView1.Rows.Add(1);

                        for (int j = 0; j <= 20; j++)
                        {
                            dataGridView1.Rows[i].Cells[j].Value = dt.DefaultView[i][j].ToString();
                        }


                        i++;
                    }
                }
                
                //dataGridView1.DataSource = dt.DefaultView;

                xlWorkBook.Close(true, null, null);
                xlApp.Quit();

                releaseObject(xlWorkSheet);
                releaseObject(xlWorkBook);
                releaseObject(xlApp);

                SplashWnd.SplashClose(this);

            }
            catch (Exception ex)
            {
                MessageBox.Show("파일 열기 실패! : " + ex.Message);
                return;
            }
        }

        private void releaseObject(object obj)
        {
            try
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
                obj = null;
            }
            catch (Exception ex)
            {
                obj = null;
                MessageBox.Show("Unable to release the Object " + ex.ToString());
            }
            finally
            {
                GC.Collect();
            }
        }

 

이렇게 되면 불러오고자 하는 엑셀 문서의 타입에 따라 데이터그리드뷰를 생성시켜 주고 그 위에 엑셀의 내용을 

 

불러오기 하여 보여질수 있게 됩니다

 

엑셀 양식 불러오기를 사용할때 고객의 종류? 양식의 타입?에 따라 변동이 많을시에 이렇게 데이터그리드뷰를 

 

유동적으로 변화시킬수 있다면 굳이 여러개의 폼을 만들지 않고 하나의 폼에서 처리가 가능하니 조금 사용자 입장에서

 

편리할수 있다고 생각해서 구현해 봤습니다

 

 

반응형

+ Recent posts