본문 바로가기

C# Form

도서관 관리 프로그램

이 프로그램은 한빛아카데미, IT CookBook C# 프로그래밍, 윤인성저의 13장 예제를 구현하였음

몇가지 책과 다른 점이 있음

  • DataGridView의 이벤트를 책에서는 CurrentCellChanged() 이벤트를 사용하였으나 여기서는 CellClick()을 사용함. CurrentCellChanged() 이벤트를 사용할 경우 에러 나옴
  • Form3.cs 구현에서 람다를 사용하여 button1_Click += (sender, e) => 로 사용했으나 여기서는 btnInsert_Click() 식으로 코딩함
  • 기타 각 창을 끝내는 단추를 삽입하고, 대여자 숫자의 변경을 반영하는 등 약간 수정하였음

(주의)
- XML 파일(Books.xml, Users.xml)이 ./bin/Debug/에 있어야 함
- 또한 이 파일들에 데이터가 하나씩이라도 들어가 있어야 함
- XML이 조금이라도 틀리면 에러가 생김


BookManager.zip

전체 프로그램은 3개의 폼으로 구성되어 있음(Form1, Form2, Form3)
또한 3개의 클래스를 각각 다른 파일에 정의하였음
우선, 3개의 클래스를 살펴보면 다음과 같음

1. Book.cs : Book 클래스를 정의한 파일

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
 
namespace BookManager
{
    class Book
    {
            public string Isbn { get; set; }
            public string Name { get; set; }
            public string Publisher { get; set; }
            public int Page { get; set; }
 
            public int UserId { get; set; }
            public string UserName { get; set; }
            public bool IsBorrowed { get; set; }
            public DateTime BorrowedAt { get; set; }
    }
}
cs

2. User.cs : User클래스를 정의한 파일


1
2
3
4
5
6
7
8
namespace BookManager
{
    class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
cs

3. DataManager.cs : DataManager 클래스를 정의한 파일

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;    // FileLoad...
using System.Xml.Linq;  // XML
 
namespace BookManager
{
    class DataManager
    {
        public static List<Book> Books = new List<Book>();
        public static List<User> Users = new List<User>();
 
        static DataManager()
        {
            Load();
        }
 
        private static void Load()
        {
            try
            {
                string booksOutput = File.ReadAllText(@"./Books.xml");
                XElement booksXElement = XElement.Parse(booksOutput);
                Books = (from item in booksXElement.Descendants("book")
                         select new Book()
                         {
                             Isbn = item.Element("isbn").Value,
                             Name = item.Element("name").Value,
                             Publisher = item.Element("publisher").Value,
                             Page = int.Parse(item.Element("page").Value),
                             BorrowedAt = DateTime.Parse(item.Element("borrowedAt").Value),
                             IsBorrowed = item.Element("isBorrowed").Value != "0" ? true : false,
                             UserId = int.Parse(item.Element("userId").Value),
                             UserName = item.Element("userName").Value
                         }).ToList<Book>();
 
                string usersOutput = File.ReadAllText(@"./Users.xml");
                XElement usersXElement = XElement.Parse(usersOutput);
                Users = (from item in usersXElement.Descendants("user")
                         select new User()
                         {
                             Id = int.Parse(item.Element("id").Value),
                             Name = item.Element("name").Value
                         }).ToList<User>();
            }
            catch (FileLoadException ex)
            {
                Save();
            }
        }
 
        public static void Save()
        {
            string booksOutput = "";
            booksOutput += "<Books>\n";
            foreach (var item in Books)
            {
                booksOutput += "<book>\n";
                booksOutput += "  <isbn>" + item.Isbn + "</isbn>\n";
                booksOutput += "  <name>" + item.Name + "</name>\n";
                booksOutput += "  <publisher>" + item.Publisher + "</publisher>\n";
                booksOutput += "  <page>" + item.Page + "</page>\n";
                booksOutput += "  <borrowedAt>" + item.BorrowedAt.ToLongDateString() + "</borrowedAt>\n";
                booksOutput += "  <isBorrowed>" + (item.IsBorrowed ? 1 : 0+ "</isBorrowed>\n";
                booksOutput += "  <userId>" + item.UserId + "</userId>\n";
                booksOutput += "  <userName>" + item.UserName + "</userName>\n";
                booksOutput += "</book>\n";
            }
            booksOutput += "</Books>\n";
 
            string usersOutput = "";
            usersOutput += "<users>\n";
            foreach (var item in Users)
            {
                usersOutput += "<user>\n";
                usersOutput += "  <id>" + item.Id + "</id>\n";
                usersOutput += "  <name>" + item.Name + "</name>\n";
                usersOutput += "</user>\n";
            }
            usersOutput += "</users>\n";
 
            File.WriteAllText(@"./Books.xml", booksOutput);
            File.WriteAllText(@"./Users.xml", usersOutput);
        }
    }
}
 
cs

Load()는 DataManager 클래스의 생성자에서 호출한다. Books.xml 파일을 읽어 XML Parsing을 하는 메소드이다.
25번 줄을 보면 읽은 값은 Linq 를 사용하여 Books<book> 리스트에 저장된다.
또 같은 방법으로 ./Users.xml 파일을 읽어 Users<User> 리스트를 만든다. XML 파서는 string으로 부터 처리한다.
XML 파일은 다음과 같은 모습으로 저장된다. 처음에 하나 이상의 데이터를 만들어 두어야 에러없이 프로그램이 수행된다.

Books.XML

1
2
3
4
5
6
7
8
9
10
11
12
<books>
<book>
  <isbn>9791156641452</isbn>
  <name>IT CookBook 실전에 강한 PLC</name>
  <publisher>한빛아카데미</publisher>
  <page>384</page>
  <borrowedAt>0001년 1월 1일 월요일</borrowedAt>
  <isBorrowed>0</isBorrowed>
  <userId>0</userId>
  <userName></userName>
</book>
</books>
cs

Users.XML

1
2
3
4
5
6
7
8
9
10
<users>
  <user>
    <id>1</id>
    <name>연하진</name>
  </user>
  <user>
    <id>2</id>
    <name>윤인성</name>
  </user>
</users>
cs

Form1은 다음과 같이 디자인 한다.


DataGridView는 2개가 있는데, 각각 Books<Book>과 Users<User>를 연결한다.


이를 위해 데이터 소스 창에서 "개체"를 선택하고 다음을 누른 후, BookManager 아래에 있는 Book과 User를 선택해준다.

그림으로 보자. 단, 이를 위해서는 일단 한번 빌드를 해서 클래스들이 있음을 알아야 한다.





이렇게 하면 데이터 소스창이 다음과 같이 보인다.



도서관리 폼인 Form2는 다음과 같이 디자인한다.




사용자관리 폼인 Form3는 다음과 같이 디자인한다.




소스를 살펴보자. Form1.cs는 다음과 같다.


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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System;
using System.Data;
using System.Linq;
using System.Windows.Forms;
 
namespace BookManager
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Text = "도서관 관리";
 
            // 레이블 설정
            label5.Text = DataManager.Books.Count.ToString();
            label6.Text = DataManager.Users.Count.ToString();
            label7.Text = DataManager.Books.Where((x) => x.IsBorrowed).Count().ToString();
            label8.Text = DataManager.Books.Where((x) =>
                { return x.IsBorrowed && x.BorrowedAt.AddDays(7< DateTime.Now; }).Count().ToString();
 
            // 데이터 그리드 설정
            dataGridView1.DataSource = DataManager.Books;
            dataGridView2.DataSource = DataManager.Users;
        }
 
        // 대여 버튼 클릭
        private void btnBorrow_Click(object sender, EventArgs e)
        {
            if (txtIsbn.Text == "")
                MessageBox.Show("Isbn을 입력해주세요");
            else if (txtUserId.Text == "")
                MessageBox.Show("사용자 Id를 입력해주세요");
            else
            {
                Book book = DataManager.Books.Single((x) => x.Isbn == txtIsbn.Text);
                if (book.IsBorrowed)
                    MessageBox.Show("이미 대여 중인 도서입니다");
                else
                {
                    User user = DataManager.Users.Single((x) => x.Id.ToString() == txtUserId.Text);
                    book.UserId = user.Id;
                    book.UserName = user.Name;
                    book.IsBorrowed = true;
                    book.BorrowedAt = DateTime.Now;
 
                    dataGridView1.DataSource = null;
                    dataGridView1.DataSource = DataManager.Books;
                    DataManager.Save();
 
                    MessageBox.Show("/" + book.Name + "/이 " + user.Name + "/님께 대여되었습니다");
 
                    // 대여자 숫자 표시 변경
                    label7.Text = DataManager.Books.Where((x) => x.IsBorrowed).Count().ToString();
                }
            }
        }
 
        // 반납 버튼 클릭
        private void btnReturn_Click(object sender, EventArgs e)
        {
            if (txtIsbn.Text == "")
                MessageBox.Show("Isbn을 입력해주세요");
            else
            {
                // DataManager.Books 에서 Isbn이 txtIsbn과 같은 객체 하나를 추출하여 book 이라 한다
                Book book = DataManager.Books.Single((x) => x.Isbn == txtIsbn.Text);
                if (book.IsBorrowed)
                {
                    // 사용자Id, 즉 txtUserId 와 관계없이 책을 반납함
                    User user = DataManager.Users.Single((x) => x.Id.ToString() == book.UserId.ToString());
                    book.UserId = 0;
                    book.UserName = "";
                    book.IsBorrowed = false;
                    book.BorrowedAt = new DateTime();
 
                    dataGridView1.DataSource = null;
                    dataGridView1.DataSource = DataManager.Books;
                    DataManager.Save();
 
                    if (book.BorrowedAt.AddDays(7> DateTime.Now)
                        MessageBox.Show("/" + book.Name + "/이 연체 상태로 반납되었습니다");
                    else
                        MessageBox.Show("/" + book.Name + "/이 반납되었습니다");
 
                    // 대여자 숫자 표시 변경
                    label7.Text = DataManager.Books.Where((x) => x.IsBorrowed).Count().ToString();
                }
                else
                    MessageBox.Show("대여 상태가 아닙니다");
            }
        }
 
        // Books DataGridView
        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                Book book = dataGridView1.CurrentRow.DataBoundItem as Book;
                txtIsbn.Text = book.Isbn;
                txtName.Text = book.Name;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
 
        // Users DataGridView
        private void dataGridView2_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                User user = dataGridView2.CurrentRow.DataBoundItem as User;
                txtUserId.Text = user.Id.ToString();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
 
        // 도서관리 메뉴
        private void 도서관리ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form form = new Form2();
            form.ShowDialog();
        }
 
        // 사용자 관리 메뉴
        private void 사용자관리ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new Form3().ShowDialog();
        }
 
        private void 끝내기ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
cs



Form2.cs는 도서관리를 위한 프로그램으로 다음과 같다.


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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
using System;
using System.Linq;
using System.Windows.Forms;
 
namespace BookManager
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
 
            dgvBooks.DataSource = DataManager.Books;
        }
 
        // dataGridView에서 셀이 클릭되면...
        private void dgvBooks_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            Book book = dgvBooks.CurrentRow.DataBoundItem as Book;
            txtIsbn.Text = book.Isbn;
            txtName.Text = book.Name;
            txtPage.Text = book.Page.ToString();
            txtPublisher.Text = book.Publisher;
        }
 
        // 추가
        private void btnInsert_Click(object sender, EventArgs e)
        {
            if (DataManager.Books.Exists((x) => x.Isbn == txtIsbn.Text))
                MessageBox.Show("이미 존재하는 도서입니다");
            else
            {
                Book book = new Book();
                book.Isbn = txtIsbn.Text;
                book.Name = txtName.Text;
                book.Publisher = txtPublisher.Text;
                book.Page = int.Parse(txtPage.Text);
                DataManager.Books.Add(book);
 
                dgvBooks.DataSource = null;
                dgvBooks.DataSource = DataManager.Books;
                DataManager.Save();
            }     
        }
 
        // 수정
        private void btnModify_Click(object sender, EventArgs e)
        {
            if (txtIsbn.Text == "")
                MessageBox.Show("Isbn을 입력해야 합니다");
            else
            {
                Book book = DataManager.Books.Single((x) => x.Isbn == txtIsbn.Text);
                book.Name = txtName.Text;
                book.Publisher = txtPublisher.Text;
                book.Page = int.Parse(txtPage.Text);
 
                dgvBooks.DataSource = null;
                dgvBooks.DataSource = DataManager.Books;
                DataManager.Save();
            }
        }
 
        // 삭제
        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (txtIsbn.Text == "")
                MessageBox.Show("Isbn을 입력해야 합니다");
            else
            {
                Book book = DataManager.Books.Single((x) => x.Isbn == txtIsbn.Text);
 
                DataManager.Books.Remove(book);
 
                dgvBooks.DataSource = null;
                dgvBooks.DataSource = DataManager.Books;
                DataManager.Save();
            }
        }
 
        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
 
cs


Form3.cs는 사용자관리를 위한 프로그램으로 다음과 같다.


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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using System;
using System.Linq;
using System.Windows.Forms;
 
namespace BookManager
{
    public partial class Form3 : Form
    {
        public Form3()
        {
            InitializeComponent();
            dgvUser.DataSource = DataManager.Users;
        }
 
        // 추가
        private void btnAdd_Click(object sender, EventArgs e)
        {
            if (txtUserId.Text == "")
                MessageBox.Show("Id를 입력해야 합니다");
            else if (DataManager.Users.Exists((x) => int.Parse(txtUserId.Text) == x.Id))
                MessageBox.Show("사용자 Id 가 겹칩니다");
            else
            {
                User user = new User();
                user.Id = int.Parse(txtUserId.Text);
                user.Name = txtName.Text;
                DataManager.Users.Add(user);
 
                dgvUser.DataSource = null;
                dgvUser.DataSource = DataManager.Users;
                DataManager.Save();
            }
        }
 
        // 수정
        private void btnUpdate_Click(object sender, EventArgs e)
        {
            User user = DataManager.Users.Single((x) => int.Parse(txtUserId.Text) == x.Id);
            user.Name = txtName.Text;
 
            dgvUser.DataSource = null;
            dgvUser.DataSource = DataManager.Users;
        }
 
        // 삭제
        private void btnDelete_Click(object sender, EventArgs e)
        {
            User user = DataManager.Users.Single((x) => int.Parse(txtUserId.Text) == x.Id);
            DataManager.Users.Remove(user);
 
            dgvUser.DataSource = null;
            dgvUser.DataSource = DataManager.Users;
        }
 
        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
 
cs



프로그램의 실행 화면 중 첫번째 창은 다음과 같다.




데이터베이스를 사용하지 않고 XML을 사용하여 데이터를 관리하는 프로그램은 이 프로그램을 기준으로 만들 수 있을 것이다.


Beeeye Dmu