PROGRAMMING WORKSHOP

COMAddIns | VSTO

VSTO로 Addin을 개발할때 항상 이부분과 친해 져야 한다
항상 살펴보고 필요없는 것은 지워버리도록 하는 것이 좋다
그림과 같이 지난회개발하던것도 로딩이 될 것이다



COM관리대화상자와 제어판두개를 항상 관심갖고 있는 것이 좋다

이제 아래와 같이 쌤플테이블이 만들어졌지만



실은 사용자가 자신의 상황에 맞는 작업내용을 입력하여야 할것이다
이때 사용자가 작업내용을 입력하면서
여러가지 자동제어를 하게 할 것인가?? 말것인가??의 문제가 있다
에이..그냥 사용자가 알아서 입력하게 하고 분석테이블 만들때
그냥 잘못된 것을 걸러내지..뭐!!! 라고 할수도 있고
아니야..그래서 시작날짜를 입력하고 기간을 입력하면 자동으로
종료날짜가 계산되게 하는 것이 좋겠지..라던가..
다양한 생각을 하게 되는 부분일 것이다
아무튼 이문제는 각자의 상황에 따라 실무적으로 결정을 하면 되겠지만
여기에서는 학습차원에서 몇가지 제어를 넣어 보도록 하자

VBA에서 워크시트에 정보를 입력할때 발생하는 Change이벤트를
VSTO에서는 어떻게 활용하나??!!
혹시 VBA에서 엑셀의 Application개체의 이벤트프로시셔
사용하는 것을 해보신 분이 있으신지..
물론 우노싸이트 이곳,저곳에서 참 많이 이야기하였지만
아마도 별로 관심을 갖고 보신분은 얼마 없으실 것이다
그림과 같이 VBA편집기에서 Class모듈을 하나 삽입하고



아래와 같이 선언부에 변수를 Application타입으로 선언하면

Public WithEvent oApp As Application

목록상자에 Application개체의 이벤트가 줄줄이 나타날 것이다
이것을 사용할줄 알아야 엑셀에서 다른 새로운 통합문서가
열리거나 닫히거나 하는 것을 통제 할수 있는 최상위콘트롤
타워가 되는 것이다

지금 만들고 있는 VSTO AddIn은 Application레벨의 소루션이다
하나의 통합문서에서만 이루어지는 것이 아니고
모든 통합문서를 통제하고 관리하는 소루션이라고 보셔야 하는 것이다
그래서 VBA 강좌에서 자주 사용하던 Workbook개체 레벨에서의 이벤트나
Worksheet개체 레벨에서의 이벤트는 없이 모두 Application개체단위의
이벤트에서 총합적으로 관리를 하게 되는 것이다

그럼 VSTO AddIn에서는 어디에서 Application개체의 이벤트를 작성할 것인가?
ThisAddIn.vb 화일의 모듈의 개체목록에서



그림과 같이 Application개체를 선택하면 오른쪽 목록상자에



VBA에서 크래스모듈에 WithEvents 로 선언하였던 것에서 보는 것과
똑같은 것들을 줄줄이 볼수 있다

워크시트의 이벤트를 활용하여, 아래의 그림과 같이
시작날짜나 종료날짜열을 더블크릭하면 (SheetBeforeDoubleClick 이벤트)
카렌다폼(윈도우의 카렌다콘트롤을 활용)을 띄워서 좀더 자동화를 해보자



물론 이것은 uno_weekly의 내용과 같은 것이다

그런데 더블크릭을 하니 아래와 같이 카렌다윈도우가 두개가 뜬다



이것은 공교롭게도 UNO_WEEKLY 에드인과 같은 시트명에
같은 양식을 사용하니까..UNO_WEEKLY도 로드되어 있고 , 현재 학습화일도
열려 있으니까..당연히 열리게 된다
두개의 에드인에서 같이 반응을 한 것이다
결국은 시트의 이름을 각 에드인에서 특별히 이름을 생각하고
잘 정하는 것이 중요할 것이고, 또한 그래도 공교롭게 같은 조건이
되지 않게 검문, 검색을 각각의 에드인데서 궁리하면서 개발하여야 할 것이다

또한 이렇게 논리를 세운 것도 문제가 되었었다

Sub GanttSheetBeforeDoubleClickEventWork(ByVal Target_ As Excel.Range)
	Try
		Dim rTarget As Excel.Range = Target_
		Dim sValue As String = rTarget.Value
		' 시트의 이름이 유효한 시트명일때 윈도우폼을 띄운다
		If rTarget.Worksheet.Name = clsGantt.GANTT_BASIC_SHT_NAME Then
			If oGantt.TableDataRange Is Nothing Then
				If oGantt.TableNewRange Is Nothing Then
					GoTo SKIP
				End If
			End If
			oGantt.TableSelectedCell = rTarget
			sValue = rTarget.Value
			If rTarget.Column = oGantt.iStartDate_Col Then
				showCalendarForm("StartDate", sValue)
			ElseIf rTarget.Column = oGantt.iEndDate_Col Then
				showCalendarForm("EndDate", sValue)
			ElseIf rTarget.Column = oGantt.iDur_Col Then
				showCalendarForm("Duration", sValue)
			End If
		Else
		' 시트명이 유효한 시트가 아니지만 셀의 서식이 날자정보일때는
		' 일반시트에서도 편리하게 하기위하여 카렌다폼을 띄워준다
		' 친절하게 한다고 하였지만, UNO_WEEKLY에서 작업을 할때
		' 이 부분에서 또 폼을 띄우게 되는 것이다
		
			If isDateFormat(rTarget.Cells(1)) Then
				showCalendarForm("General", sValue)
			End If
		
		End If

SKIP:
	Catch ex As Exception
		MsgBox(ex.Message)
	Finally

	End Try
End Sub

이 윈도우폼은 기본정보시트의 날짜열을 더블크릭하면 나타나게 한다

이렇게 나타나게 할 개체를 만들어줄 Class를 하나 만들자
Class는 Winodow폼이다 , 모든 것은 크래스로 구성된다는 점, 감각을 키우시고



폼에 또 작은 개체들을 담자, 하나는 MonthCalendar,
또 다른 하나는 CheckBox
또 다른 하나는 Timer

그런데 위의 윈도우폼을 다용도로 써먹자..
기간부분을 더블크릭할때는 아래의 그림과 같이 변하게 하도록 한다



조금만 화면에 여러개의 콘트롤을 그려넣으려면
경험이 없으면 애먹는다
그림과 같이 속성창을 보면 모든 개체의 목록이 있으니
원하는 것을 선택하면 해당 콘트롤이 활성화된다



아래의 그림과 같이 시작날짜와 종료날짜와 기간은 서로 상관관계가
있다..각 정보를 입력할때마다, oGantt크래스모듈의 SetDates()메소드를
불러서 값이 바뀜에 따라서 다른 두개의 값도 자동으로
조정하게 해보자

Sub setDates(ByVal sType As String, ByVal bChecked As Boolean)
        Dim rRow As Excel.Range = TableSelectedCell.EntireRow.Cells(1).resize(, iFldCount)
        Dim iDur As Integer
        Dim datEnd As Date
        Dim datStart As Date
        With rRow
            Try
                iDur = CInt(rRow.Cells(iDur_Col).value)
            Catch ex As Exception
                iDur = 0
            End Try
            Try
                datStart = DateValue(rRow.Cells(iStartDate_Col).value)
            Catch ex As Exception
                datStart = Nothing
            End Try
            Try
                datEnd = DateValue(rRow.Cells(iEndDate_Col).value)
            Catch ex As Exception
                datEnd = Nothing
            End Try
        End With
        Dim oT As Excel.Range = TableSelectedCell
        Select Case sType
            Case "Start"
                Select Case True
                    Case (datEnd <> Nothing) And (iDur > 0)
                        If bChecked Then
                            oT.Offset(, 1).Value = DateAdd(DateInterval.Day, iDur - 1, datStart)
                        Else
                            GoTo X
                        End If
                    Case (datEnd <> Nothing) And (iDur = 0)
X:
                        Dim iDays As Integer = DateDiff(DateInterval.Day, datStart, datEnd) + 1
                        If iDays < 1 Then
                            MsgBox("작업기간이 1 보다 작을수 없습니다")
                            oT.ClearContents()
                            GoTo out
                        Else
                            oT.Offset(, 2).Value = iDays
                        End If
                    Case (datEnd = Nothing) And (iDur > 0)
                        oT.Offset(, 1).Value = DateAdd(DateInterval.Day, iDur - 1, datStart)
                    Case (datEnd = Nothing) And (iDur = 0)
                End Select
            Case "End"
                Select Case True
                    Case (datStart <> Nothing) And (iDur > 0)
                        If bChecked Then
                            oT.Offset(, -1).Value = DateAdd(DateInterval.Day, -(iDur - 1), datEnd)
                        Else
                            GoTo Y
                        End If
                    Case (datStart <> Nothing) And (iDur = 0)
Y:
                        Dim iDays As Integer = DateDiff(DateInterval.Day, datStart, datEnd) + 1
                        If iDays < 1 Then
                            MsgBox("작업기간이 1 보다 작을수 없습니다")
                            oT.ClearContents()
                            GoTo out
                        Else
                            oT.Offset(, 1).Value = iDays
                        End If
                    Case (datStart = Nothing) And (iDur > 0)
                        oT.Offset(, -1).Value = DateAdd(DateInterval.Day, -(iDur - 1), datEnd)
                    Case (datStart = Nothing) And (iDur = 0)
                End Select
            Case "Duration"
                Select Case True
                    Case datStart <> Nothing And datEnd <> Nothing
                        If bChecked Then
                            oT.Offset(, -1).Value = DateAdd(DateInterval.Day, iDur - 1, oT.Offset(, -2).Value)
                        Else
                            oT.Offset(, -2).Value = DateAdd(DateInterval.Day, -(iDur - 1), oT.Offset(, -1).Value)
                        End If
                    Case datStart <> Nothing And datEnd = Nothing
                        oT.Offset(, -1).Value = DateAdd(DateInterval.Day, iDur - 1, oT.Offset(, -2).Value)

                    Case datStart = Nothing And datEnd <> Nothing
                        oT.Offset(, -2).Value = DateAdd(DateInterval.Day, -(iDur - 1), oT.Offset(, -1).Value)
                End Select
        End Select
    End Sub

한꺼번에 많이 올리면 질릴 것 같아서
3개의 셀과 카렌다폼과의 관계만 따져보는 정도만 정리하여 올린다

VB.Net편집기의 좋은 점 하나는..
개체이름을 만약 calendarFrom 이라는 스펠이 잘못된 것을 넣었을때
프로젝트창에서 해당개체이름을 바꾸면 이 개체와 관련된 코드의
모든 곳을 찾아서 고쳐준다.
만약 VBA에서 했다면 일일이 찾아서 수정해주어야 한다

위와 같이 간단하게 출발하지만, 프로젝트가 점점 확장된다면
더블크릭이벤트를 활용하여야할 다른 용도의 시트도 있게 될 것이다
그러면 또 어떤 시트의 경우는 어떻게 하고, 어떤 다른 시트는 또
다른 것을 하여야 하는 작업흐름을 결정하는 검문소들이 세워져야 할 것이다

또 calendarForm이 뜨면서 스스로 자체내에서 또한 여러가지
내용을 초기화하면서 화면에 뜨게 될 것이다

그러니 무슨일을 어떻게 어떤 개체가 할 것인지
복잡하면 종이에 그려야하고, 간단하면 머리로 그리고..
흥미를 잃지 마시고..

***[LOG-IN]***