[C# WPF] C# WPF MVVM 패턴 예제 프로그램

안녕하세요.

 

저는 요새 최근에 WPF 공부를 시작하게 되었습니다. 그리고 WPF 하면 MVVM 패턴과 데이터 바인딩 속성 등을 이용하여 프로젝트를 많이들 진행한다고 들어서 개인적으로 MVVM 패턴을 공부할 겸 인터넷을 참고 하면서 MVVM 패턴 예제 코드를 작성해 보았습니다.

 

책이랑, 인터넷 소스들을 많이 참고하면서 짜집기? 식으로도 된 코드들이 많기 때문에 이점 참고하시고 봐주시면 좋겠습니다!^^

 

 

제가 MVVM 패턴으로 만든 예제 프로그램은 SQL DB 서버 접속 후, 해당 DB의 데이터를 불러와서 DataGrid 컨트롤에 각 내용들을 바인딩 해줘서 보여주는 프로그램을 만들어 보았습니다.

 

그럼 바로 예제 코드를 보여 드리도록 하겠습니다.

 

View
MainWindow.xaml
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
<Window x:Class="WPFDBTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPFDBTest"
        xmlns:ViewModel="clr-namespace:WPFDBTest.ViewModel"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
 
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding LoadedCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    
    <Window.DataContext>
        <ViewModel:MainViewModel/>
    </Window.DataContext>
 
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="150"/>
            <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>
        
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="70"/>
        </Grid.RowDefinitions>
 
        <DataGrid x:Name="uiGrid_Main" Grid.ColumnSpan="3" Margin="5"
                  AutoGenerateColumns="False"
                  ItemsSource="{Binding Path= SampleDatas, Mode=TwoWay, 
            NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True}">
            <DataGrid.Columns>
                <DataGridTextColumn MinWidth="10" Width="Auto" Header="NAME" Binding="{Binding NAME}"/>
                <DataGridTextColumn MinWidth ="100" Width="Auto" Header="AGE" Binding="{Binding AGE}"/>
                <DataGridTextColumn MinWidth="100" Width="Auto" Header="GRADE" Binding="{Binding GRADE}"/>
                <DataGridTextColumn MinWidth="200" Width="*" Header="SCORE" Binding="{Binding SCORE}"/>
            </DataGrid.Columns>
        </DataGrid>
 
        <Button Grid.Row="1" Grid.Column="0" Margin="5"
                Content="Connect"
                Command="{Binding ConnectCommand}"/>
        <Button Grid.Row="1" Grid.Column="1" Margin="5"
                Content="조회"
                Command="{Binding SelectCommand}"/>
        <Button Grid.Row="1" Grid.Column="2" Margin="5"
                Content="Update"/>
    </Grid>
</Window>
 
cs

 

Model
Student.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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace WPFDBTest.Model
{
    public class Student
    {
        public string NAME
        {
            get;
            set;
        }
 
        public string AGE
        {
            get;
            set;
        }
 
        public string GRADE
        {
            get;
            set;
        }
 
        public string SCORE
        {
            get;
            set;
        }
    }
}
 
cs

 

ViewModel
DelegateCommand.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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
 
namespace WPFDBTest.ViewModel
{
    public class DelegateCommand : ICommand
    {
        private readonly Func<bool> canExecute;
        private readonly Action execute;
 
        public DelegateCommand(Action exectue) : this(exectue, null)
        {
 
        }
 
        public DelegateCommand(Action execute, Func<bool> canExecute)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }
 
        /// <summary>
        /// can executes event handler
        /// </summary>
        public event EventHandler CanExecuteChanged;
 
        /// <summary>
        /// implement of icommand can execute method
        /// </summary>
        /// <param name="o">parameter by default of icomand interface</param>
        /// <returns>can execute or not</returns>
        public bool CanExecute(object o)
        {
            if (this.canExecute == null)
            {
                return true;
            }
            return this.canExecute();
        }
 
        /// <summary>
        /// implement of icommand interface execute method
        /// </summary>
        /// <param name="o">parameter by default of icomand interface</param>
        public void Execute(object o)
        {
            this.execute();
        }
 
        /// <summary>
        /// raise ca excute changed when property changed
        /// </summary>
        public void RaiseCanExecuteChanged()
        {
            if (this.CanExecuteChanged != null)
            {
                this.CanExecuteChanged(this, EventArgs.Empty);
            }
        }
    }
}
 
cs

 

MainViewModel.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using WPFDBTest.Model;
 
namespace WPFDBTest.ViewModel
{
    public class MainViewModel : INotifyPropertyChanged
    {
        Student _stu = new Student();
 
        public string NAME
        {
            get
            {
                return _stu.NAME;
            }
            set
            {
                _stu.NAME = value;
                OnPropertyChanged("NAME");
            }
        }
 
        public string AGE
        {
            get
            {
                return _stu.AGE;
            }
            set
            {
                _stu.AGE = value;
                OnPropertyChanged("AGE");
            }
        }
 
        public string GRADE
        {
            get
            {
                return _stu.GRADE;
            }
            set
            {
                _stu.GRADE = value;
                OnPropertyChanged("GRADE");
            }
        }
 
        public string SCORE
        {
            get
            {
                return _stu.SCORE;
            }
            set
            {
                _stu.SCORE = value;
                OnPropertyChanged("SCORE");
            }
        }
 
        ObservableCollection<Student> _sampleDatas = null;
        public ObservableCollection<Student> SampleDatas
        {
            get
            {
                if (_sampleDatas == null)
                {
                    _sampleDatas = new ObservableCollection<Student>();
                }
                return _sampleDatas;
            }
            set
            {
                _sampleDatas = value;
            }
        }
 
        //PropertyChaneged 이벤트 선언 및 이벤트 핸들러
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            this.PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(propertyName));
        }
 
        /// <summary>
        /// Connect Command 선언
        /// </summary>
        private ICommand connectCommand;
        public ICommand ConnectCommand
        {
            get
            {
                return (this.connectCommand) ?? (this.connectCommand = new DelegateCommand(Connect));
            }
        }
 
        private ICommand selectCommand;
        public ICommand SelectCommand
        {
            get
            {
                return (this.selectCommand) ?? (this.selectCommand = new DelegateCommand(DataSearch));
            }
        }
 
        private ICommand loadedCommand;
        public ICommand LoadedCommand
        {
            get
            {
                return (this.loadedCommand) ?? (this.loadedCommand = new DelegateCommand(LoadEvent));
            }
        }
 
        private void LoadEvent()
        {
            //Connect to DB
            if (SqlDBManager.Instance.GetConnection() == false)
            {
                string msg = $"Failed to Connect to Database";
                MessageBox.Show(msg, "Error");
                return;
            }
            else
            {
                string msg = $"Success to Connect to Database";
                MessageBox.Show(msg, "Inform");
            }
        }
 
        private void DataSearch()
        {
            
            DataSet ds = new DataSet();
 
            string query = @"
SELECT '범범조조' AS NAME, '28' AS AGE, '4' AS GRADE, '90' AS SCORE
UNION ALL
SELECT '안정환' AS NAME, '26' AS AGE, '4' AS GRADE, '80' AS SCORE
UNION ALL
SELECT '김성주' AS NAME, '36' AS AGE, '4' AS GRADE, '87' AS SCORE
UNION ALL
SELECT '정형돈' AS NAME, '46' AS AGE, '3' AS GRADE, '40' AS SCORE
UNION ALL
SELECT '아이유' AS NAME, '26' AS AGE, '2' AS GRADE, '62' AS SCORE
UNION ALL
SELECT '이기자' AS NAME, '22' AS AGE, '1' AS GRADE, '100' AS SCORE
";
 
            SqlDBManager.Instance.ExecuteDsQuery(ds, query);
 
            for(int idx = 0; idx < ds.Tables[0].Rows.Count; idx++)
            {
                 Student obj = new Student();
                 obj.NAME = ds.Tables[0].Rows[idx]["NAME"].ToString();
                 obj.AGE = ds.Tables[0].Rows[idx]["AGE"].ToString();
                 obj.GRADE = ds.Tables[0].Rows[idx]["GRADE"].ToString();
                 obj.SCORE = ds.Tables[0].Rows[idx]["SCORE"].ToString();
 
                SampleDatas.Add(obj);
            }
        }
 
        /// <summary>
        /// DB Connect
        /// </summary>
        private void Connect()
        {
            //Connect to DB
            if (SqlDBManager.Instance.GetConnection() == false)
            {
                string msg = $"Failed to Connect to Database";
                MessageBox.Show(msg, "Error");
                return;
            }
            else
            {
                string msg = $"Success to Connect to Database";
                MessageBox.Show(msg, "Inform");
            }
        }
    }
}
 
cs

 

SqlDBManager.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
 
namespace WPFDBTest.ViewModel
{
    public sealed class SqlDBManager
    {
        public enum ExcuteResult { Fail = -2, Success };
 
        public string ConnectionString = string.Empty;
        public string InitFileName { get; set; }
 
        public string Address { get; private set; }
        public string Port { get; private set; }
        public string LastException { get; private set; }
 
        public bool IsRunning { get { return Connection.State == ConnectionState.Open ? true : false; } }
 
        public SqlConnection Connection { get; private set; }
 
        private static SqlDBManager instance;
 
        public static SqlDBManager Instance
        {
            get
            {
                if (instance == null) instance = new SqlDBManager();
 
                return instance;
            }
        }
 
        private SqlCommand _sqlCmd = null;
 
        public SqlDBManager()
        {
            _sqlCmd = new SqlCommand();
        }
 
        public bool GetConnection()
        {
            try
            {
                if (ConnectionString == string.Empty)
                    SetConnectionString();
 
                Connection = new SqlConnection(ConnectionString);
 
                Connection.Open();
            }
            catch (Exception ex)
            {
                string msg = string.Format("{0}\r\nMessage : {1}", ex.StackTrace, ex.Message);
 
                LastException = ex.Message;
 
                return false;
            }
 
            if (Connection.State == ConnectionState.Open)
                return true;
            else
                return false;
        }
 
        public int ExecuteNonQuery(string query)
        {
            lock (this)
            {
                return Execute_NonQuery(query);
            }
        }
 
        public bool HasRows(string query)
        {
            lock (this)
            {
                SqlDataReader result = ExecuteReader(query);
 
                return result.HasRows;
            }
        }
 
        public SqlDataReader ExecuteReaderQuery(string query)
        {
            lock (this)
            {
                SqlDataReader result = ExecuteReader(query);
 
                return result;
            }
        }
 
        public DataSet ExecuteDsQuery(DataSet ds, string query)
        {
            ds.Reset();
 
            lock (this)
            {
                //dbLoger.WriteLog(LogType.Inform, string.Format("ExecuteDsQuery - {0}", query));
 
                return ExecuteDataAdt(ds, query);
            }
        }
 
        public DataSet ExecuteProcedure(DataSet ds, string procName, params string[] pValues)
        {
            lock (this)
            {
                return ExecuteProcedureAdt(ds, procName, pValues);
            }
        }
 
        public void CancelQuery()
        {
            _sqlCmd.Cancel();
        }
 
        public void Close()
        {
            Connection.Close();
        }
 
        #region private..........................................................
 
        [DllImport("wininet.dll")]
        private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);
 
        private bool CheckConnection()
        {
            bool result = true;
 
            if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable() == false)
            {
                this.LastException = "네트워크 연결이 끊어졌습니다.";
                MessageBox.Show(this.LastException, "Error");
                result = false;
            }
            else if (this.Connection == null || this.Connection.State == ConnectionState.Closed)
            {
                result = this.GetConnection();
            }
 
            return result;
        }
 
        private void SetConnectionString()
        {
            string user = "win";
            string pwd = "dnlsvh";
            string svr = "Thyssen";
            string addr01 = "127.0.0.1";
 
            string dataSource = string.Format(@"Data Source={0};Database={1};User Id={2};Password={3}", addr01, svr, user, pwd);
 
            this.Address = addr01;
            this.ConnectionString = dataSource;
        }
 
        private int Execute_NonQuery(string query)
        {
            int result = (int)ExcuteResult.Fail;
 
            try
            {
                _sqlCmd = new SqlCommand();
                _sqlCmd.Connection = this.Connection;
                _sqlCmd.CommandText = query;
                result = _sqlCmd.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                string msg = string.Format("{0}\r\nMessage : {1}", ex.StackTrace, ex.Message);
 
                LastException = ex.Message;
 
                if (CheckConnection() == falsereturn result;
            }
 
            return result;
        }
 
        private SqlDataReader ExecuteReader(string query)
        {
            SqlDataReader result = null;
 
            try
            {
                _sqlCmd = new SqlCommand();
                _sqlCmd.Connection = this.Connection;
                _sqlCmd.CommandText = query;
                result = _sqlCmd.ExecuteReader();
            }
            catch (Exception ex)
            {
                string msg = string.Format("{0}\r\nMessage : {1}", ex.StackTrace, ex.Message);
 
                LastException = ex.Message;
 
                if (CheckConnection() == falsereturn result;
            }
 
            return result;
        }
 
        private DataSet ExecuteDataAdt(DataSet ds, string query)
        {
            try
            {
                SqlDataAdapter cmd = new SqlDataAdapter();
                cmd.SelectCommand = _sqlCmd;
                cmd.SelectCommand.Connection = this.Connection;
                cmd.SelectCommand.CommandText = query;
                cmd.Fill(ds);
            }
            catch (Exception ex)
            {
                string msg = string.Format("{0}\r\nMessage : {1}", ex.StackTrace, ex.Message);
 
                LastException = ex.Message;
 
                if (CheckConnection() == falsereturn null;
            }
 
            return ds;
        }
 
        private DataSet ExecuteProcedureAdt(DataSet ds, string query, params string[] values)
        {
            try
            {
                SqlDataAdapter adapter = new SqlDataAdapter();
                adapter.SelectCommand = _sqlCmd;
                adapter.SelectCommand.CommandText = query;
                adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
                adapter.SelectCommand.Connection = this.Connection;
 
                for (int i = 0; i < values.Length; ++i)
                {
                    adapter.SelectCommand.Parameters.Add(values[i]);
                    //adapter.SelectCommand.Parameters.Add("params", values[i]);
                }
 
                adapter.Fill(ds);
 
                return ds;
            }
            catch (Exception ex)
            {
                string msg = string.Format("{0}\r\nMessage : {1}", ex.StackTrace, ex.Message);
 
                this.LastException = ex.Message;
 
                if (CheckConnection() == falsereturn null;
            }
 
            return ds;
        }
 
        #endregion private..................................................................
    }
}
 
cs

 

실행 결과

 

 

위와 같이 Grid 컨트롤에 데이터들이 알맞게 바인딩 돼서 출력되는 것을 확인하실 수 있습니다.

감사합니다.^^

728x90

이 글을 공유하기

댓글

Designed by JB FACTORY