바로 전 포스팅에서는 데이터 소스에 바인딩 하여 컬럼명만 출력했다면


이번에는 객체에 값을 넣어 버튼을 클릭 했을 때 행을 추가하려고 합니다.


값이 입력된 객체를 List<SampleInfo> 에 넣고 이것을 GridControl의 DataSource에 반영하면 됩니다.


그리고 GridControl의 데이터 소스를 RefreshDataSource()를 이용하여 갱신 해주면 됩니다.


그래야 데이터소스를 새로 불러와 화면에 출력하기 때문입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public partial class MainForm : Form
{
        private List<SampleInfo> sourceList;
        public MainForm()
        {
            InitializeComponent();
 
            #region 그리드 컨트롤을 초기화 합니다.
 
            this.sourceList = new List<SampleInfo>();
            this.resultGridControl.DataSource = this.sourceList;
 
            #endregion  
        }
}
 
private void simpleButton1_Click(object sender, EventArgs e)
{
            SampleInfo sampleInfo = new SampleInfo();
 
            sampleInfo.ID = "Kim";
            sampleInfo.Subject = "Subject";
            sampleInfo.CreateTime = DateTime.Now;
 
            this.sourceList.Add(sampleInfo);
 
            resultGridControl.RefreshDataSource();
 
}
 
public class SampleInfo
{
        public string ID { get; set; }
        public string Subject { get; set; }
        public DateTime CreateTime { get; set; }
}
cs


결과는 아래와 같이 나옵니다.



클래스에 있는 ID, Subject, CreateDate 를 List<T>를 이용하여 바인딩 하는 방법 입니다.


컬럼 이름들이 위의 객체에 있는 값의 이름으로 설정이 되며 객체를 생성하면서


추가 / 삭제 / 수정 이 가능합니다.


지금은 바인딩 하여 컬럼 이름만 출력되도록 하였습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public partial class MainForm : Form
{
        private List<SampleInfo> sourceList;
        public MainForm()
        {
            InitializeComponent();
 
            #region 그리드 컨트롤을 초기화 합니다.
 
            this.sourceList = new List<SampleInfo>();
            this.resultGridControl.DataSource = this.sourceList;
 
            #endregion  
        }
}
 
public class SampleInfo
{
        public string ID { get; set; }
        public string Subject { get; set; }
        public DateTime CreateTime { get; set; }
}
cs



결과는 아래와 같이 출력됩니다.



폼 생성 후 컬럼들을 추가 한 뒤에 행들을 추가할 때 별도로 설정을 안했을 경우 각 행의 내용의 길이에 상관 없이

 

정해진 크기로만 컬럼이 설정됩니다.

 

BestFitColumns() 메서드를 사용하면 행의 길이에 맞춰 컬럼의 너비가 바뀝니다.

 

원하는 위치에 

 

gridView.BestFitColumns(); 만 추가해 주면 됩니다.

 

gridView.BestFitColumns() 반영 전

 

gridView.BestFitColumns() 반영 후

이전 포스팅에서는 각각의 행에 내용을 직접 코드로 작성을 했는데


이번에는 텍스트박스와 콤보 박스 그리고 DateTimePicker를 이용해서 데이터를 넣는 방법의 예제를 만들어봤습니다.


우선 아래와 같이 간단하게 폼을 만듭니다.


각 컨트롤들의 값은 변경 없이 생성될 때의 이름 그대로 사용하였습니다.





그리고 아래와 같이 코드를 작성합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System.Data;
using System.Windows.Forms;
 
namespace WindowsFormsApp3
{
    public partial class Form1 : Form
    {
        // 데이터를 삽입할 데이터 테이블을 생성합니다.
        DataTable table = new DataTable();
 
        public Form1()
        {
            InitializeComponent();
 
            // Table에 column을 추가합니다.
            table.Columns.Add("ID"typeof(string));
            table.Columns.Add("제목"typeof(string));
            table.Columns.Add("구분"typeof(string));
            table.Columns.Add("생성일"typeof(string));
            table.Columns.Add("수정일"typeof(string));
 
            // Column들이 추가된 Table을 DataGridView에 추가합니다.
            dataGridView1.DataSource = table;
 
            // 클릭 이벤트 입니다.
            button1.Click += Button1_Click;
        }
 
        /// <summary>
        /// 추가 버튼을 누르면 동작합니다.
        /// </summary>
        private void Button1_Click(object sender, System.EventArgs e)
        {
            // 입력된 값들을 Table에 추가합니다.
            table.Rows.Add(textBox1.Text, textBox2.Text, 
                           comboBox1.SelectedItem, dateTimePicker1.Value, dateTimePicker2.Value);
            
            // 값들이 추가된 Table을 DataGridView에 추가합니다.
            dataGridView1.DataSource = table;
 
        }
    }
}
 
cs



작성을 다한 뒤 빌드를 하게 되면 아래와 같이 사용이 가능합니다.


각각의 컨트롤에 값을 입력 후 추가 버튼을 누르게 되면 DataGridView에 값이 추가 됩니다.





C#에서 DataGridView 컨트롤에 데이터 삽입하는 방법 입니다.


DataGridView를 사용하게 되면 데이터 삽입하고 나면 엑셀과 같은 형식으로 데이터를 뿌려주게 됩니다.


디자이너에서 Column도 추가하고 그 안에 데이터도 삽입할 수 있으나, 코드로 작성해봤습니다.


그리고 보통 FormLoad 될 때 작성된 코드를 불러오도록 하는 방법도 있으나


저는 그냥 생성자 안에서 모두 작성하였습니다.



우선 Form에 DataGridView 컨트롤을 추가합니다.




그리고 아래와 같이 코드를 작성합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System.Data;
using System.Windows.Forms;
 
namespace WindowsFormsApp3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            DataTable table = new DataTable();
 
            // column을 추가합니다.
            table.Columns.Add("ID"typeof(string));
            table.Columns.Add("제목"typeof(string));
            table.Columns.Add("구분"typeof(string));
            table.Columns.Add("생성일"typeof(string));
            table.Columns.Add("수정일"typeof(string));
 
            // 각각의 행에 내용을 입력합니다.
            table.Rows.Add("ID 1""제목 1번""사용중""2019/03/11""2019/03/18");
            table.Rows.Add("ID 2""제목 2번""미사용""2019/03/12""2019/03/18");
            table.Rows.Add("ID 3""제목 3번""미사용""2019/03/13""2019/03/18");
            table.Rows.Add("ID 4""제목 4번""사용중""2019/03/14""2019/03/18");
 
            // 값들이 입력된 테이블을 DataGridView에 입력합니다.
            dataGridView1.DataSource = table;
        }
    }
}
 
cs



코드 작성 완료 후 빌드를 하면 아래와 같이 출력이 됩니다.



기본 셋팅은 하나의 솔루션에 하나의 프로젝트가 존재하고 이 프로젝트를 빌드한다.


혹은 하나의 솔루션에 여러 프로젝트가 있지만 하나의 프로젝트만 빌드할 수 있게 되어 있다.




그런데 간혹 여러개의 프로젝트를 동시 빌드 해야할 경우가 있는데 이럴 경우


솔루션에서 우클릭 --> 속성을 선택하게 되면 솔루션 속성 페이지가 출력 된다.


속성 페이지에서 여러개의 시작 프로젝트를 선택하고 작업을 모두 시작으로 변경하고 확인 후


빌드를 하면 두개의 프로젝트가 같이 빌드가 된다.



Visual Studio 실행 후 프로젝트 생성에 들어가서


콘솔 앱(.NET Framework), 클래스 라이브러리(.NET Framework), Windows Form 앱(.NET Framework)


등을 선택해서 프로젝트를 만들면 되는데


우측 아래에 보면 솔루션용 디렉토리 체크를 하는 곳이 있다.


예를 들어 이름을 Sample1로 작성하고 솔루션용 디렉토리에 체크 후 프로젝트를 생성 시


Sample1(Sample1.sln) 이라는 폴더 안에 다시 새로운 Sample1 폴더와 Sample1.sln 이라는 솔루션 폴더가 생성된다.


솔루션 파일과 같이 있는 Sample1 폴더는 프로젝트 폴더로써 이 폴더 안에 프로젝트 파일(Sample1.csproj) 과 cs 파일 등이 있다.




Sample2로 이름을 작성 후 솔루션용 디렉토리 체크 해제를 한 상태에서 프로젝트를 생성하게 되면 Sample2라는 폴더 안에


솔루션 파일(Sample2.sln)과 프로젝트 파일(Sample2.csproj)과 내용들이 같이 존재하게 된다.



솔루션 안에 여러개의 프로젝트가 존재할 수 있는데 이럴 때 솔루션에 새로 만들 프로젝트를 하나하나 추가해주면 된다.


기타 프로젝트 --> Visual Studio 솔루션 선택하여 빈 솔루션을 생성한 후, 빈 솔루션에 프로젝트들을 하나하나 추가를 해주는 방법이 있다.


프로젝트 새로 만들기에서 하단의 솔루션 항목에 솔루션에 추가로 바꾸고 프로젝트 생성하면 빈 솔루션에 새로운 프로젝트가 추가가 된다.






코드 작성 중 모든 예외를 다 처리할 수는 없을 것이다.


예상치 못한 예외가 발생했을 때 알 수 있도록 메시지로 출력되도록 할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void Main()
{
    Application.ThreadException += Application_ThreadException;
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm());
}
 
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
    MessageBox.Show($"{e.Exception.Message}{Constants.HardCoding.lineDivision}{e.Exception.StackTrace}",
                     Constants.HardCoding.messageCaption, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
 
cs


Application.ThreadException  이벤트를 추가하고 그 안에 메시지를 출력하는 코드를 작성하면 된다.

프로그램 실행 시 폼이 출력 안되고 트레이 아이콘만 출력되게 해야할 경우가 있다.


그래서 처음에 시도해본 방법이


폼 생성되었을 때 Visible 값을 fasle로 하였는데 이렇게 했음에도 그대로 화면이 출력 되었다.(opacity = 0 으로 하는 방법도 있으나 이 방법은 제외 하였다.)


찾아보니 Visible 속성이 매우 중요한 속성이라 하면서 실제로는 OnLoad()가 실행된다고 한다.


그래서 Visible 속성을 아무리 바꾸려는 시도가 무시된다고 한다.



그래서 찾아보니 SetVisibleCore 를 사용하여 폼 출력 안되게 하였다.


문제는 이렇게 하니 종료할 때 아래의 동작이 한번 더 되는 문제가 발생하였다. 찾다보면 해결 방법이 있겠지만 잠시 테스트 해본거라 아


직은 모르겠다.


1
2
3
4
protected override void SetVisibleCore(bool value)
{
    base.SetVisibleCore(value);
}
cs



그 다음에 찾아보고 적용한게 기존의 메인폼을 뒤로 두고 새로 만들 폼을 메인으로 만드는 방법이다.


ApplicationContext를 상속 받는 클래스를 만들고 그 클래스를 메인으로 두면 된다.


그리고 나서 새로 만든 클래스에서 트레이 아이콘이나 컨텍스트 메뉴를 추가 하고 옵션으로 기존 메인폼을 보여주게 하면 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TraySample : ApplicationContext
{
    public TraySample()
    {
        // 알림 영역에서의 아이콘의 값들을 설정합니다.
        notifyIcon.Visible = true;
        notifyIcon.Icon = null;
        notifyIcon.ContextMenuStrip.Items.Add("Show");
        notifyIcon.ContextMenuStrip.Items.Add("Exit");
 
        // 이벤트를 생성합니다.
        notifyIcon.ContextMenuStrip.ItemClicked += ContextMenuStrip_ItemClicked;
    }
 
    NotifyIcon notifyIcon = new NotifyIcon();
}
cs


중복 실행 방지 2가지 방법


생성된 실행파일을 반복해서 실행하니까 실행 시키는 족족 계속 프로그램이 열립니다.


이럴 필요까지는 없는데 말이죠...


찾아보니 어려운 내용들도 아닙니다. 4가지 정도 있던데 그 중 두개만 테스트 해보고, 첫번째 것을 적용 했습니다.



1. 프로세스를 가져와서 프로세스의 이름으로 중복 실행을 방지합니다.


같은 이름의 프로세스 이름이 2개 이상 있으면 경고 메시지 출력 되게 하였습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void Main()
{
    Process[] procs = Process.GetProcessesByName("실행될 프로세스 이름");
    // 두번 이상 실행되었을 때 처리할 내용을 작성합니다.
    if (procs.Length > 1)
    {
        MessageBox.Show("프로그램이 이미 실행되고 있습니다.\n다시 한번 확인해주시기 바랍니다.");
        return;
    }
    // 정상 동작 될 내용을 작성하면 됩니다.
    else
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}
cs


2. Mutex 사용


특정 코드, 특정 자원에 대해 동시 접근을 차단하고 한번에 하나의 쓰레드만 수행하도록 하는 것이 뮤텍스라 한다 합니다.


그래서 아래의 코드 처럼 작성해보니 진짜 동시 실행이 안됩니다.


그냥 느낌상 뮤텍스는 안끌려서 저는 프로세스 이름 검색하는 걸로 중복 실행 방지 했습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    bool createdNew;
    // mutex 객체 생성합니다. 아래와 같이 생성해두면 된다.
    Mutex mutex = new Mutex(true"프로그램 이름"out createdNew);
    if (createdNew)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new TrayApplication());
        mutex.ReleaseMutex();
    }
    else
    {
        MessageBox.Show("프로그램이 이미 실행되고 있습니다.");
        return;
    }
cs


+ Recent posts