PROGRAMMING WORKSHOP

.Net FrameWork,VB.Net |

무언가를 알아 가는 과정이 한번에 알지 못한다
특히 프로그래밍의 개체들의 하는 일과 성질머리 그리고 새로운 언어의 구조가 그렇다
한번에 딱찍어서 명확하게 머리에 그려지지는 않지만
조금씩, 조금씩 안개속에서 벗어나서 아주 명확해져 가는 것이다
특히 무엇을 알려면 , 그 이전에 또 무엇을 먼저 이해해야 하고
서로 얽키고 설켜있다
하지만, VBA를 이미 많이 숙달된 분들은 프로그래밍이라는 기본은 잡혀 있다
새로운 개체와 좀더 편리하게 하려고 노력하는 언어의 발전을 따라가면 된다
앞페이지의 맛보기....OrderBy(Function(x) x) 와 같은 것이
새로운 .NetFrameWork환경이 제공하는 새로운 개체와 그에 따른 언어의 발전인 것이다
좀더 편리하게 떼거리로 몰려 있는 집합체 정보를 처리할수 없을까??
그런 생각에 몰입하면서 발전되어 가는 것이다

용어가 새로운 것이 나오는 것을 즐겁게 생각하시면 좋을 것이다
한번에 이해할수 없는 것이 용어끼리의 기술이 상호 얽혀있어서
어떤 것을 먼저 이해할지 헷갈리는 것이기때문에..
몇번을 상호 참조이해하면서 가는 것이다

Class Module | Event | RaiseEvent | WithEvents | Delegate

VBA에서 볼수 없었던
그런 헷갈리는 단어중에..
Delegate라는 단어가 있다..
대행자,위임을 받은 대행자,
일을 잘하려면 자신이 하는 일을 부하직원에 Delegating을 잘하라!!
라는 말이 있다
그런의미의 단어다
VBA를 하였던 사람은 이 말이 이해하기가 조금쉽다
예를 들어서 여러분이 프로그램적으로 버튼을 만들어서 시트에 붙인후
OnAction 속성에 실행하려고 하는 프로시져를 연결하여
크릭하면 실행된다
예를 들어서 아래와 같이
어떤 때는 myProcedure1을 호출하고 또 어떤 때는 myProcedure2를
호출하게 할 수 있을 것이다

Sub makeButton()
Dim oBtn As Button
Set oBtn = Me.Buttons.Add(10, 10, 50, 20)
oBtn.Caption = "xx"
If (Int(Rnd * 2)) Mod 2 = 0 Then
    oBtn.OnAction = Me.CodeName & ".myProcedure1"
Else
    oBtn.OnAction = Me.CodeName & ".myProcedure2"
End If
End Sub
Sub myProcedure1()
MsgBox "you called myProcedure1"
End Sub
Sub myProcedure2()
MsgBox "you called myProcedure2"
End Sub

어떤 프로시져를 대신하는 이름을 OnAction속성에 연결한 것이다
VBA에서는 이것에 대한 특별한 용어는 없지만
실은 우리가 모르는 뒤켵에서 Delegate라는 개념이 작동한 것이다
해당프로시져명을 참조하여 작업을 배당한 셈이다
Delegating을 하였다고 할수 있을 것이다
VB.Net에서는 이 Delegate를 좀더 구체적으로 사용하고 다양하게 활용하는 셈이다

위에서 한 내용을 VB.Net에서 한다면
우선 크래스모듈이라는 것을 사용하자
크래스모듈이라고 너무 복잡하게 생각하지 말고
프로시져를 복합적으로 작성하는 하나의 모듈시트를 작성한다고 생각하시는 것이 좋다
좀더 많은 다양한 기능을 갖고 있는 하나의 모듈시트라고 보셔도 좋다
VBA에서 프로시져를 모듈시트에 여러개 만들어서 사용하다 보면
소루션이 점점 복잡해지다 보면 좀더 체계적으로 변수들이나 프로시져를 관리하고 싶어진다
그런 특별한 관리시스템을 크래스모듈로 처리가 된다는 것으로 아시면 된다

크래스모듈을 하나 만들어 보자
복잡하게 생각할 필요없다
새로운 윈도우프로젝트를 하나 만들고
만들어진 폼의 모듈(이것도 역시 크래스모듈이다)의 코드를 보면
아래와 같이 황량한 빈탕의 아무것도 없다
나는 크래스모듈이다!!! 그리고 이름은 Form1 이라고 하는 것 밖에 없다
이곳에 우리가 사용할 크래스모듈을 하나 만들어 보자
새로운 모듈시트를 넣어도 좋으니 그냥 하나의 크래스모듈에 수백개의 자기가
사용할 크래스모듈을 만들수 있다
이것이 VB.Net의 편리한점이다 분산하여 만들던 하나의 크래스모듈에 여러개의 것으로
구성하던, 컴파일이 되면 모두 각각의 크래스로 처리관리하니까..아무 걱정할것도 없다

Public Class Form1
    ...
    ...
    ...
End Class

크래스를 아래와 같이 추가한다
이름을 myFirstClass라고 지어주던 우리가 VBA에서 함수나 프로시져에 이름을 지어주던
나름대로 의미있는 이름을 지어주면 된다
프로그래밍은 Naming이 전부라고 할만큼 이름짓기는 자기가 만드는 소루션에 의미를
부여하는 작업이다

Public Class Form1
    ...
    ...
    ...
End Class
Class myFirstClass
    ...
    ...
End Class
 

이것도 역시 빈탕이다..
크래스모듈은 VBA의 모듈보다 지능적이고 쎄련된 것이라고 했다
쎄련된 작업을 해보자

버튼을 주문수량만큼 만들어주는 크래스모듈을 구성해 보자
100개를 만들어 달라고 하면 100개를 만들고, 1000개를 만들어 달라고 하면 1000개를 만들고
그런데 한꺼번에 100개를 공급받으면서 자..이제 하나 갑니다
또 다른 것 하나 갑니다
또 다른 것 하나 갑니다
이렇게 버튼을 하나씩 공급받으면서 이번에는 받는 쪽에서
무언가 추가작업을 공급받은 버튼에 하고 싶을수 있을 것이다
프로그래밍은 실제 사람이 하는 작업을 똑같이 구현하려고 노력하는 것이다
그러니 실제로 어떤 물건을 하나씩 납품받아서 받을때마다
물건에 상표를 붙여서 정해진 위치에 차곡차곡 쌓던가 할수도 있는 것이다
그것을 구현해 보도록 하자
그러려며 하나가 만들어졌다는 것을 알려주는 무엇인가가 필요 할 것이다
그래서 아래와 같이 추가한다

Public Class Form1
    WithEvents oMyObj As myFirstClass
    ...
    ...
End Class

Class myFirstClass
    Public Event myFirstEvent(oX As Button,iNum As Integer)
    ...
End Class
    

무언가 작업이 발생할때, 이것을 알려주는 것, 이것이 이벤트인것이다
VBA에서 워크시트의 어떤 범위를 크릭하면 크릭하는 순간 무슨 작업을 할수 있게 이벤트프로시져를
VBA의 워크시트 크래스모듈시트에서 작업을 할수 있는 것을 생각하시면 된다
그런데 VBA에서는 주어진 것을 받아만 먹는 것이고
물론크래스모듈에서 위와 같은 흉내는 내지만 엑셀을 위한 프로그래밍을 하는 작업의 성격이
다른 것이라도 별 큰 의미가 없다
하지만 VB.Net은 우리가 워크시트크래스를 만들어서 사용하듯이 작업을 할수 있는 것이다
즉 이벤트프로시져를 만들어서 사용할수 있는 것이다

위의 크래스모듈에 Public Event myFirstEvent(oX As Button) 이라고 한 것은
우리가 만드는 크래스의 개체에서 이벤트를 발생하겠다는 것이다
즉 이벤트 프로시져를 우리가 만드는 크래스모듈을 사용하는 누구나 사용할수 있는 것이다
이 이벤트를 사용하겠다는 것을 폼의 크래스모듈상에
WithEvents oMyObj As myFirstClass
라고 선언하면



아하..크래스개체변수를 WithEvents를 사용하면 해당크래스에서 생성된개체에서
이벤트프로시져를 사용할수 있구나..
물론 크래스에서 제공할 이벤트를 만들겠다고 그렇게 구성한것이니까..
Public Event myFirstEvent(oX As Button,iNum As Integer) 와 같이
그렇지 않다면 WithEvent라고 해도 아무 프로시져를 제공받을수 없을 것이고
매개변수를 생성한 버튼을 전달하고, 몇번째 버튼이라는 값도 매개변수로 보내준다면
받는 쪽에서도 기분좋게 일일이 셀 필요없이 번호가 붙어 오는 셈이다
크래스모듈은 사용자가 기분좋게 사용할수 있게 서비스를 제공하는 개체를 만들어 주는 것이다
그런데
이제 완성된 것을 보도록 하자

Public Class Form1 
    WithEvents oMyObj As myFirstClass

    Const SIZE_ As Integer = 30
    Const GAP As Integer = 3

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        oMyObj = New myFirstClass
        oMyObj.createButtons(100)
        Dim iTop As Integer = Me.Controls(99).Top + SIZE_ + GAP
        Me.ClientSize = New Size(Me.ClientSize.Width, iTop)
    End Sub

    
    Private Sub oMyObj_myFirstEvent(oX As System.Windows.Forms.Button, iNum As Integer) Handles oMyObj.myFirstEvent
        Me.Controls.Add(oX)
        Dim iX = iNum - 1
        Dim iLeft As Integer = GAP + (iX Mod 10) * (SIZE_ + GAP)
        Dim iTop As Integer = GAP + (iX \ 10) * (SIZE_ + GAP)
        oX.Location = New Size(iLeft, iTop)
        oX.Size = New Size(SIZE_, SIZE_)
        oX.Text = Format(iX, "00")
    End Sub
End Class


Class myFirstClass 
    Public Event myFirstEvent(oX As Button, iNum As Integer)
    Sub createButtons(iButtonNum As Integer)
        Dim oBtn As Button = Nothing
        For iX As Integer = 1 To iButtonNum
            oBtn = New Button
            oBtn.Font = New Font("맑은 고딕", 9) 
            RaiseEvent myFirstEvent(oBtn, iX)
        Next
    End Sub
End Class

아하..버튼의 기본을 공장에서 만들고 나머지는 공급받으면서 추가 작업을
조금씩하면 간편하구나..
그래도 아마도, 아니 왜 그래스모듈을 작성하고 번잡을 떠나??!!라고 할수 있다
왜냐면 우노도 예전에 그런 소리를 했으니까..
하지만 많은 복잡한 것을 다루다 보면 필요함을 느끼게 된다
뭔소리??!!
예를 들어서 그냥 혼자서 보고서를 만드는 작업을 한다고 치자..
이때는 그냥 VBA에서 하듯이 모듈시트에 프로시져로 기능별로 나누어서 하면 뭐..별일 없다
하지만 여러분이 좀 높은 위치에서 본다면
인사과도 있고,총부과도 있고, 영업부서도 있고, 다양한 부서에서 일을 한다
그런데 회사의 모든 보고서의 기본이 되는 형식을 표준화되어 있게 마련이다
이런 기본이 되는 것도 각각의 부서별로 만들어서 사용한다면 끔찍해진다
그래서 기본프레임은 본부에서 만들고, 나머지 예하부대에서는
이 기본프레임에 자신들만의 고유업무에 필요한 것을 추가하면 일이 당연히 쭐게 되고
보고서의 모양도 통일감을 유지하게 되는 셈이다

위의 간단한 버튼이지만
A라는 사람이 버튼이 500개가 필요하고, B라는 사람은 20개가 필요하고
그리고 A라는 사람은 바탕색을 빨강색으로 하고 싶은 B라는 사람은 파랑색으로 하고 싶고
그런 일의 성격을 분석하여
공통된 것만 추려서 크래스모듈을 만들어서 개체를 생성하여 공급하면
A나 B는 자신만의 특성을 버튼에 추가적으로 주면 되는 것 아니겠는가?!

실은 위의 작업은 그냥 일반모듈에서 해도 아무 상관없다
하지만 어떻게 이벤트를 일으키는가.. 말그대로 Raise Event--> RaiseEvent라던가,
크래스모듈내에서 Event 선언과 이것을 어떻게 활용하는가에 대한
요약본 쌤플을 만들다 보니까.. 그런 점을 잘 접수하시고..

이제 좀더 중요한 것으로 가자
Delegate를 이야기 하다가, Event로 오니까 헷갈리셨을 것이다
실은 Event라는 키워드는 Delegate라는 것을 구현하는 특별한 키워드다
위에서

Public Event myFirstEvent(oX As Button, iNum As Integer)
라고 한 내용을 아래와 같이 바꿔서 사용해도 된다

Public Event myFirstEvent As Q
Public Delegate Sub Q(oX As Button, iNum As Integer)


작업내용은 없는 제목만 붙은 프로시져인 셈이다
이것을 Delegate라고 한다
대표적인 것이 Event가 Delegate인 셈이다..특별히 이름을 Event라고 한것이고..
즉 빈 템프릿만 만들어 놓고, 나머지는 사용자가 필요할때 이프로시져를 사용할지 , 저 프로시져의 내용을
사용할지 결정하는 셈이다
아하, 별것아니구나...라고 생각하시고!!!

아래 화일에서 이 부분을 주석처리하였으니 해제하고 해보시면서 이해를 조금씩
발전하시기 바란다

***[LOG-IN]***

Delegate라는 것이 뭔지 이해하기 위하여 덤으로 Event와 EventHandler를 해보았다
이제 Delegte를 일반적으로 사용하는 것을 보도록 하자
우선 아래의 코드를 새로운 윈도우프로젝트에
TextBox하나(TextBox1), Button 두개(Button1, Button2)를 그려 넣고
아래의 코드를 모두 복사하여 붙이고 실행시켜보시고..

Public Class Form1
    Delegate Function myDelegate(sX As String)
    Dim oX As New System.Random(CType(System.DateTime.Now.Ticks Mod System.Int32.MaxValue, Integer))

    Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        Dim oFont As New Font("맑은 고딕", 9)
        Button1.Font = oFont
        Button2.Font = oFont
        TextBox1.Font = oFont

        For iX As Integer = 1 To 10
            TextBox1.Text &= Chr(oX.Next(65, 91)) & Chr(oX.Next(97, 122))
        Next
    End Sub
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim oQ As New myDelegate(AddressOf toLower)
        TextBox1.Text = oQ.Invoke(TextBox1.Text)

    End Sub
    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        Dim oQ As New myDelegate(AddressOf toUpper)
        TextBox1.Text = oQ.Invoke(TextBox1.Text)
    End Sub

    Function toLower(sX As String)
        Dim sQ As String = ""
        sQ = sX.ToLower
        Return sQ
    End Function
    Function toUpper(sX As String)
        Dim sQ As String = ""
        sQ = sX.ToUpper
        Return sQ
    End Function
End Class
    

VBA에서 하던 것과 뭐가 다른지 비교해 보자..
Delegate라고 하는 것을 사용했다
Delegate는 아주 작은 하나의 크래스이다 그래서 사용할때
Dim oSome As New Delegate_Name(AddressOf 사용하고자 하는 함수나 프로시져) 으로 개체를 생성하고 사용한다
이것은 이벤트에서도
Dim oBtn As New Button
AddHandler oBtn.Click, New EventHandler(AddressOf ....) 와 같은 것이다
물론 이것도 VBA에서와 같이 일반적인 프로시져로 사용해도 되는것이지만
쉽게 Delegate라는 것이 뭣에 사용하는지 이해를 돕기 위한 예이다

다음 화일에서 EventHandler도 delegate라는 것을 보기 위하여
아래와 같이 버튼을 하나 달고 이벤트를 달아서 사용자가 정의한 Delegate를
보시면,아하.. 하실것이다

Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
		...
		...
		...
        Dim oBtn As New Button
        oBtn.Left = Button1.Left
        oBtn.Top = Button2.Top + Button2.Height + 10
        oBtn.Text = oX.Next
        oBtn.Font = oFont
        oBtn.AutoSize = True
        If oX.Next Mod 2 = 0 Then
            oBtn.Text = oX.Next
            AddHandler oBtn.Click, New EventHandler(AddressOf callByButtonClickEvent1)
        Else
            oBtn.Text = oX.Next(65, 90)
            AddHandler oBtn.Click, New EventHandler(AddressOf callByButtonClickEvent2)
        End If
        Me.Controls.Add(oBtn)
 End Sub

Sub callByButtonClickEvent1(sender As Button, e As EventArgs)
	MsgBox("버튼의 텍스트는 [" & sender.Text & "]")
	sender.Text = oX.Next()
End Sub

Sub callByButtonClickEvent2(sender As Button, e As EventArgs)
	MsgBox("버튼의 텍스트는 [" & sender.Text & "]")
	sender.Text = Chr(oX.Next(65, 90))
End Sub

***[LOG-IN]***