퇴근5분전

## 줌인 아웃 컨트롤 수정.

   : 유튜브를 보다가 ppt처럼 기본 뷰가 있고 줌 인/ 줌 아웃을 하는 경우 센터에 머물며 판넬이 커졌다 작아졌다 하고,

내용 컨텐츠도 크기가 변하는 걸 만들어보고 싶어서 만들어봤다. ( 사실 전부터 만들고 있었으나... )

   자기전에 유튜브를 보다가 고치면 어떨까 한거라서 자기전에 고민해보고 일어나서 바로 수정하고 테스트 하는데 2시간 정도 걸린것 같다.

   스크롤위치 땜시롱 ... 오늘도 생쑈를...

 

# 트랙바에 의해 10% ~ 350% 범위를 가진다.

# 버튼 추가시 기존에 추가된 동일한 크기로 배치되게 만들어두기 했는데... 이건 뭐... 하기 나름이니까.

 

- 100% 일때

- 70% 일때

- 120%로 키웠을때

- 190%로 더 키웠을때

 

( 소스는 첨부파일로 숨겨짐 )

'# 4) .Net ( Vs 2010 ) > C#' 카테고리의 다른 글

[배열 회전] 배열 회전하기.  (0) 2018.08.09
html table 만들어서 엑셀에 붙여넣기  (0) 2018.06.13
컨트롤 Zoom In Out 기능 기초.  (0) 2018.03.06
Prezi 흉내내기...  (0) 2017.07.13
VsPackage ] 개발 방법!  (0) 2017.01.18

 

음... 컨트롤을 올려놓고 줌 인, 줌 아웃 기능을 다시 만들어봄.

# 기본 100% 기준일때

# 60%로 줄이고 버튼3을 이용해 버튼 하나를 랜덤 배치함. ( 배치될때 현재 적용된 비율이 적용되어 추가하도록 구현됨 )

음... 뭐 잘 만들어졌는뎅..

NPT, NTP.TEST, PREZI에 기능을 넣어볼까 함...

 

>> 근데 이런 기능 구현된건 왜 찾기가 힘들까??

>> 컨트롤을 사서 쓰면야 괜찮지만...  돈없는 개발자인 난.... 만들어 써야 되는데 ...

 배율 계산 로직 : http://aseuka.tistory.com/entry/Net-%EB%B0%B0%EC%9C%A8-%EB%A7%9E%EC%B6%94%EA%B8%B0-II 

 

 

< 첨부파일로 프로젝트 파일을 숨겨놨음. >

 

 

 

 음 요새 프로세스 흐름 그리는 프로그램을 만들면서 예전에 봐두었던 Prezi를 보게 되었다.

 

좋은 프로그램이지만 내가 쓸일이 없다보니...

 

 특정 영역에 대하여 줌인. 줌아웃 되는 걸 보고... 비슷하게 만들어볼까? 라는 생각으로 흉내를 내봤다.

 

얼토당토 않는 흉내지만...

 

# 컨트롤

         프레지아이콘컨트롤 ( 빨간 사각 상자 )

         프레지판넬컨트롤 ( 배경에 깔려있는 회색 바탕 판넬 )

 

빨간색 박스를 더블 클릭하면 박스와 같은 사각형 박스( 프레지판넬컨트롤 )를 만들어 쭉! 늘려주는 효과로 늘어난다.

접힐때는 쭉~ 접히면서 원래 사각형 박스사이즈로 줄어든다.

 

위 아래 두개의 박스로 각 각 펼쳐지는 효과, 접히는 효과를 테스트 해봤더니 괜찮게 나왔다.

 

영상캡쳐가 안되서 띄울수는 없지만... 써먹을 곳이 생기겠지....

 

후에 나온 판넬은 닫기 버튼이 활성화 된다. 닫으면 접히는 효과로 접히게 된다.

 

 

# 초기화면 #

 

# 펼쳐진 화면 #

# Visual Studio VSPackage 개발관련하여 정리한다.

- 기존 AddIns과 달리 생성방법이 매우 쉬웠다. ( 문서가 너무 어려워 ㅠㅠ... )

- 개발 샘플을 제공해주신 같이 일하는 과장님께 감솨...

 

1. VSIX 프로젝트를 생성한다.

2. 새 항목을 추가한다.

2-1. Visual Studio Package 를 생성해준다.

2-2. 생성 후에 다시 새 항목 추가를 이용하여 Custom Command를 추가한다.

- VSPackage 내에 CustomCommand.Initialize( this ); 가 자동으로 추가됨을 볼 수 있다.

3.  파일목록중   VsPackage.vsct 파일에서 추가된 커맨드가 어디에 뜰지를 결정하는 Parent ID 를 지정해준다.

왼쪽은 IDM_VS_MENU_TOOLS 로 기본 지정되어 있다. 이것은 메뉴중에 도구 > 해당 커맨드 메뉴가 뜨는 것이다.

우측엔 각 위치별로 ID를 찾아서 정리해 둔 것 이다. ( 제일 아래 참조!!! )

4. 해당 명령에 대한 기능을 MenuItemCallback 이벤트 핸들러에 구현하면 된다.

5. 아래는 해당 위치를 바꿔주었다. IDM_VS_CTXT_CODEWIN 으로 코드 편집창에서 메뉴를 띄워준다.

6. 아래는 Invoke CustomCommand 라는 메뉴가 뜬것을 볼 수 있다.

 

## Group ID 목록 ( Parent 는 1개를 지정해야 하므로 주석을 확인하며 필요한 ID를 복사해서 사용하면 됨 )

 - 정의된 내용을 자세히 보기 위해서는 .vsct 파일내에 정의된

  <!--This is the file that defines the IDs for all the commands exposed by VisualStudio. -->
  <Extern href="stdidcmd.h"/>

  <!--This header contains the command ids for the menus provided by the shell. -->
  <Extern href="vsshlids.h"/>

저 두 파일중 vsshlids.h 을 찾아서 보면 된다.  

C:\Program Files\Microsoft Visual Studio 14.0\VSSDK\VisualStudioIntegration\Common\Inc\

폴더내에 정의된 파일들이 있다.

 


       <Groups>
          <Group guid = "guidVSPackageCmdSet" id="MyMenuGroup" priority="0x0600">
              <Parent guid = "guidXamlUiCmds" id="IDM_XAML_EDITOR" />
              <!-- 코드편집창(.xaml)에서의 컨텍스트 메뉴, 아래 IDSymbol과 같이 써야 함. -->
              <!--<Parent guid = "guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN"/>-->
              <!-- 코드편집창(.cs)에서의 컨텍스트메뉴-->
              <!--<Parent guid = "guidSHLMainMenu" id="IDM_VS_CTXT_REFERENCE"/>-->
              <!--솔루션탐색기 : 참조파일-->
              <!--<Parent guid = "guidSHLMainMenu" id="IDM_VS_CTXT_ITEMNODE"/>-->
              <!--솔루션탐색기 : 파일-->
              <!--<Parent guid = "guidSHLMainMenu" id="IDM_VS_CTXT_PROJNODE"/> -->
              <!--솔루션탐색기 : 프로젝트 노드-->
              <!--<Parent guid = "guidSHLMainMenu" id="IDM_VS_MENU_PROJECT"/> -->
              <!--메뉴 : 프로젝트 > 아래-->
              <!--<Parent guid = "guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>-->
              <!--메뉴 : 도구 > 아래..-->
          </Group>
      </Groups>  
      
    <GuidSymbol name = "guidXamlUiCmds" value="{4c87b692-1202-46aa-b64c-ef01faec53da}">
          <IDSymbol name = "IDM_XAML_EDITOR" value="0x103" />
    </GuidSymbol>

 

# 소스 편집에 필요한 간단한 소스

  Command에는 ServiceProvider 프로퍼티가 있음.

        private string GetSelection()
        {
            string setting = "";
            EnvDTE80.DTE2 _applicationObject = ServiceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;
            //Check active document
            if (_applicationObject.ActiveDocument != null)
            {
                //Get active document
                EnvDTE.TextDocument objTextDocument = (EnvDTE.TextDocument)_applicationObject.ActiveDocument.Object("");
                EnvDTE.TextSelection objTextSelection = objTextDocument.Selection;

                if (!String.IsNullOrEmpty(objTextSelection.Text))
                {
                    //Get selected text
                    setting = objTextSelection.Text;
                }
            }
            return setting;
        }

        private void SetSelection(string txt)
        {
            EnvDTE80.DTE2 _applicationObject = ServiceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;
            //Check active document
            if (_applicationObject.ActiveDocument != null)
            {
                //Get active document
                EnvDTE.TextDocument objTextDocument = (EnvDTE.TextDocument)_applicationObject.ActiveDocument.Object("");
                EnvDTE.TextSelection objTextSelection = objTextDocument.Selection;

                if (!String.IsNullOrEmpty(txt))
                {
                    objTextSelection.Insert(txt, (int)EnvDTE.vsInsertFlags.vsInsertFlagsContainNewText);
                    //  objTextDocument.Selection.Text = txt;
                }
            }
        }

    솔루션 탐색기에서 선택된 아이템!!

            EnvDTE80.DTE2 _applicationObject = ServiceProvider.GetService(typeof(EnvDTE.DTE)) as EnvDTE80.DTE2;
            EnvDTE.Projects prjs = _applicationObject.ActiveSolutionProjects as EnvDTE.Projects;
            EnvDTE.UIHierarchy UIH = _applicationObject.ToolWindows.SolutionExplorer;
            Array SelectItems = (Array)UIH.SelectedItems;
            if (SelectItems != null)
            {
                foreach (EnvDTE.UIHierarchyItem item in SelectItems)
                {
                    EnvDTE.ProjectItem prj = item.Object as EnvDTE.ProjectItem;
                    string projectName = prj.ContainingProject.Name;
                    string projectPath = "" + prj.Properties.Item("FullPath").Value;
                }
            }

 

 

 

 

 

 

친구의 프로그램에 사용한 내용이다.

 

0시~9시까지 <시간외근무>, 9시~18시까지 < 시간내근무(점심 12시~13시제외) >, 18시~24시 <시간외근무>

 

18시 이후에 저녁식사시간을 체크해야함. 18시가 될수도 있고 19시가 될수도... 또 30분동안먹을수도 있고 1시간을 먹을수도 있고.

 

그시간을 계산해서 각각 포인트 및 메모를 한다.

 

근무시간을 이리 저리 바꿔가며 테스트함. 저녁시간도 이리 저리 바꾸며 테스트

 

- 09:00 ~ 18:00

- 07:00 ~ 10:00

- 11:00 ~ 14:00

- 15:00 ~ 19:00 ( 저녁 먹은날, 안먹은날 )

- 08:00 ~ 20:00 ( 저녁 먹은날, 안먹은날 )

- 16:00 ~ 19:30 ( 저녁 먹은날 18:30분 부터 1시간 or 30분, 저녁안먹은날 )

 

# 테스트를 위한 시간설정 {

- 09:00 ~ 12:30 ( 점심시간 12시부터이므로 30분을 빼버림 ㅡ.ㅡ;; 밥은 꼭 12시에 먹어야 한다! )

- 11:30 ~ 13:00

- 12:00 ~ 12:30

- 12:30 ~ 13:00

# 테스트를 위한 시간설정 }

 

기타 시간을 바꿔가면서 테스트 했음.

 

점심시간에 대해 무조건 12시 ~ 13시 한시간으로 처리하다보니...

12시부터 13시는 무조건 제외하도록 만들었다.

 

 

* Method내에 있는 memo는 여기서 사용하지 않음. 다른곳 Method를 복사해와서 그냥 두었다.

    private decimal Calc(string gubun)
        {
            // todo: 9to6 에 맞춰 8hour 이후 시간은 OT로 잡는다.
            decimal sumWT_Value = 0m;
            decimal sumOT_Value = 0m;

            Dictionary<string, decimal> TimeTables = new Dictionary<string, decimal>() {
                {"", 0.0m},
                {"00:00",  0.0m}, {"00:30",  0.5m},
                {"01:00",  1.0m}, {"01:30",  1.5m},
                {"02:00",  2.0m}, {"02:30",  2.5m},
                {"03:00",  3.0m}, {"03:30",  3.5m},
                {"04:00",  4.0m}, {"04:30",  4.5m},
                {"05:00",  5.0m}, {"05:30",  5.5m},
                {"06:00",  6.0m}, {"06:30",  6.5m},
                {"07:00",  7.0m}, {"07:30",  7.5m},
                {"08:00",  8.0m}, {"08:30",  8.5m},
                {"09:00",  9.0m}, {"09:30",  9.5m},
                {"10:00", 10.0m}, {"10:30", 10.5m},
                {"11:00", 11.0m}, {"11:30", 11.5m},
                {"12:00", 12.0m}, {"12:30", 12.5m},
                {"13:00", 13.0m}, {"13:30", 13.5m},
                {"14:00", 14.0m}, {"14:30", 14.5m},
                {"15:00", 15.0m}, {"15:30", 15.5m},
                {"16:00", 16.0m}, {"16:30", 16.5m},
                {"17:00", 17.0m}, {"17:30", 17.5m},
                {"18:00", 18.0m}, {"18:30", 18.5m},
                {"19:00", 19.0m}, {"19:30", 19.5m},
                {"20:00", 20.0m}, {"20:30", 20.5m},
                {"21:00", 21.0m}, {"21:30", 21.5m},
                {"22:00", 22.0m}, {"22:30", 22.5m},
                {"23:00", 23.0m}, {"23:30", 23.5m},
                {"24:00", 24.0m}
            };

            string fromTime = From;  // 근무시작시간
            string toTime = To;         // 근무종료시간
            
            string fromdinner = ("" + FromDinner).Trim(), todinner = ""; //  밥먹기 시작시간, 종료시간.( toDinner는 소스에서 구한다 )

            string hourMinute = ( "" + DinnerHourMinute).Trim();          // 밥먹는 시간 H: 1시간, M: 30분
            
            var getAfterTime = new Func<string, string, string>((fdTime, HM) =>
            {

                // todo : 밥먹는 시간 구함,  todinner 구할때 쓴다.

                string afterTime = "";
                DateTime tmpTime;
                if (DateTime.TryParseExact(DateTime.Today.ToShortDateString() + " " + fdTime, "yyyy-MM-dd HH:mm", null, System.Globalization.DateTimeStyles.AssumeLocal, out tmpTime))
                {
                    if (HM == "H")
                    {
                        afterTime = tmpTime.AddHours(1).ToString("HH:mm");
                    }
                    else
                    {
                        afterTime = tmpTime.AddMinutes(30).ToString("HH:mm");
                    }
                }
                return afterTime;
            });

            decimal val1 = TimeTables[fromTime];
            decimal val2 = TimeTables[toTime];
            decimal val = val2 - val1;

            string memo = "";

            string _from = fromTime;
            string _to = toTime;

            if ("09:00".CompareTo(toTime) <= 0 && fromTime.CompareTo("09:00") < 0)
            {
                // 아침 OT 계산!
                val1 = TimeTables[fromTime];
                val2 = TimeTables["09:00"];
                val = val2 - val1;
                _from = fromTime;
                _to = "09:00";
                sumOT_Value += val;
                memo += string.Format("{0}~{1} > {2}", _from, _to, val);
                memo += Environment.NewLine;
            }

            if ("09:00".CompareTo(toTime) <= 0)
            {
                if ("09:00".CompareTo(fromTime) < 0)
                {
                    val1 = TimeTables[fromTime];
                    _from = fromTime;
                }
                else
                {

                    val1 = TimeTables["09:00"];
                    _from = "09:00";
                }

                if ("18:00".CompareTo(toTime) <= 0)
                {
                    val2 = TimeTables["18:00"];
                    _to = "18:00";
                }
                else
                {
                    val2 = TimeTables[toTime];
                    _to = toTime;
                }


                val = val2 - val1;

                decimal offset1 = 0m;
                decimal offset2 = 0m;

                if (_from.CompareTo("12:00") <= 0 && "12:30".CompareTo(_to) <= 0)
                {
                    offset1 = TimeTables["12:00"];
                }
                else if (_from.CompareTo("12:30") <= 0 && "12:30".CompareTo(_to) <= 0)
                {
                    offset1 = TimeTables["12:30"];
                }
                if ("13:00".CompareTo(_to) <= 0 && _from.CompareTo("12:30") <= 0)
                {
                    offset2 = TimeTables["13:00"];
                }
                else if ("12:30".CompareTo(_to) <= 0 && _from.CompareTo("12:30") <= 0)
                {
                    offset2 = TimeTables["12:30"];
                }
                val = val - (offset2 - offset1);

                sumWT_Value += val;
                memo += string.Format("{0}~{1} > {2}", _from, _to, val);
                memo += Environment.NewLine;
            }

            // 오후 OT
            if ("18:00".CompareTo(toTime) <= 0)
            {
                if (string.IsNullOrEmpty(fromdinner.Trim()) == false)
                {
                    if ("18:00".CompareTo(fromdinner) >= 0)
                    {
                        // 식사시간이 18시면
                        todinner = getAfterTime(fromdinner, hourMinute);
                        if (todinner.CompareTo(_to) < 0)
                        {
                            val1 = TimeTables[fromdinner];
                            val2 = TimeTables[todinner];

                            _from = fromdinner;
                            _to = todinner;
                            val = val2 - val1;
                            if (val > 0)
                            {
                                memo += string.Format("{0}~{1} <밥> {2}", _from, _to, val);
                                memo += Environment.NewLine;
                            }
                        }
                    }
                    else
                    {
                        if (fromdinner.CompareTo(_to) < 0)
                        {
                            // 식사시간이 18시가 지나서 18시 30분이라면...
                            //# 밥먹기 전까지 일한 시간
                            val1 = TimeTables["18:00"];
                            val2 = TimeTables[fromdinner];
                            _from = "18:00";
                            _to = fromdinner;
                            val = val2 - val1;
                            memo += string.Format("{0}~{1} > {2}", _from, _to, val);
                            memo += Environment.NewLine;
                            // 밥먹은시간..
                            todinner = getAfterTime(fromdinner, hourMinute);
                            if (todinner.CompareTo(_to) < 0)
                            {
                                val1 = TimeTables[fromdinner];
                                val2 = TimeTables[todinner];

                                _from = fromdinner;
                                _to = todinner;
                                val = val2 - val1;
                                if (val > 0)
                                {
                                    memo += string.Format("{0}~{1} <밥> {2}", _from, _to, val);
                                    memo += Environment.NewLine;
                                }
                            }
                        }
                    }

                    if (todinner.CompareTo(toTime) < 0)
                    {
                        if (fromdinner.CompareTo(toTime) < 0)
                        {
                            todinner = getAfterTime(fromdinner, hourMinute);

                            val1 = TimeTables[todinner];
                            val2 = TimeTables[toTime];
                            _from = todinner;
                            _to = toTime;
                            val = val2 - val1;
                            if (val > 0)
                            {
                                sumOT_Value += val;
                                memo += string.Format("{0}~{1} > {2}", _from, _to, val);
                                memo += Environment.NewLine;
                            }
                        }
                    }
                }
                else
                {
                    if (todinner.CompareTo(_to) < 0)
                    {
                        // 저녁식사 X
                        val1 = TimeTables["18:00"];
                        val2 = TimeTables[toTime];
                        _from = "18:00";
                        _to = toTime;
                        val = val2 - val1;
                        if (val > 0)
                        {
                            sumOT_Value += val;
                            memo += string.Format("{0}~{1} > {2}", _from, _to, val);
                            memo += Environment.NewLine;
                        }
                    }
                }
            }

            if (gubun == "Total")
            {
                return sumOT_Value + sumWT_Value;
            }
            else
            {
                return sumOT_Value;
            }
        }

 

 이번에 친구 프로그램 만들면서 epplus로 여러 시트를 만들어야 했었다.

그래서 하나 만든게 있다. 엑셀의 특정 시트를 지정해서 읽어서 epplus 구문으로 똑같이 생성하는 코드를 만들어주 주는 소스다.

 

워낙 셀도 많고, 수식도 많이 걸려있고... 그걸 하나 하나 치려니 너무 빡시니까...

 

단, 챠트, 이미지, 등등 객체정보는 대상으로 하지 않았다. 작업 대상 시트엔 없는 내용이었으니...

 

250라인정도 되넹...

 

#파일 오픈.

   using (ExcelPackage package = new ExcelPackage(newTempFile, true))

 

#엑셀에 따로 정의된 스타일 정보. ( xml로 따로 빼서 생성시 넣어주면 스타일 정보가 똑같이 뜬다. )

   string xml = package.Workbook.StylesXml.OuterXml;

 

# 시트 탭 컬러

   @"sheet.TabColor = Color.FromArgb({0}, {1}, {2});",

 

#셀 배경색 넣을때 먼저 지정! ( 없으면 배경색 넣을때 에러! )

   @"sheet.Cells[""{0}""].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.{1};"

#셀 배경색

   @"sheet.Cells[""{0}""].Style.Fill.BackgroundColor.SetColor(ColorTranslator.FromHtml(""#{1}""));"

 

#폰트

   @"sheet.Cells[""{0}""].Style.Font.SetFromFont( new Font(""{1}"", {2}f, FontStyle.{3}));"

 

#폰트색

   @"sheet.Cells[""{0}""].Style.Font.Color.SetColor(ColorTranslator.FromHtml(""#{1}""));"

 

#수식

   @"sheet.Cells[""{0}""].Formula = ""{1}"";"

 

#값

   @"sheet.Cells[""{0}""].Value = {1};"

 

#리치텍스트 ( 셀 안에 컨텐츠에 별도 서식을 지정했을때 value대신 쓴다. )

   @"var excelRich{1} = sheet.Cells[""{0}""].RichText.Add(@""{2}"");"

   @"excelRich{0}.FontName = ""{1}"";"

   @"excelRich{0}.Color = Color.FromArgb({1});"

   @"excelRich{0}.Size = {1};"

   @"excelRich{0}.Bold = {1};"

   @"excelRich{0}.UnderLine = {1};"

   @"sheet.Cells[""{0}""].IsRichText = true;"

 

#숫자포맷 ( 이게 좀 거지 같다.  날짜로 된 컬럼이 숫자로 넘어온다. 다른 숫자와 구분이 안되어 직접 핸들링 해야 함. )

   @"sheet.Cells[""{0}""].Style.Numberformat.Format = @""{1}"";"

 

#셀 병합

   @"sheet.Cells[""{0}""].Merge = {1};"

 

#외곽선 ( 이것도.. 대부분 비슷하게 가져오는데 다른 경우는 만들어진 시트 보면서 직접 변경해줘야 한다. )

   @"sheet.Cells[""{0}""].Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.{1};"
   @"sheet.Cells[""{0}""].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.{1};"
   @"sheet.Cells[""{0}""].Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.{1};"
   @"sheet.Cells[""{0}""].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.{1};"

 

#셀 가로, 세로 정렬 ( 이것도 다르게 가져오기도 한다. )

   @"sheet.Cells[""{0}""].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.{1};"

   @"sheet.Cells[""{0}""].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.{1};",

 

#컨텐츠가 셀 넘어가지 않게 처리 할때. (=true)

   @"sheet.Cells[""{0}""].Style.WrapText = {1};"

 

#컬럼정보

   @"sheet.Column({0}).BestFit = {1};"
   @"sheet.Column({0}).Collapsed = {1};"
   @"sheet.Column({0}).Width = {1}d;"
   @"sheet.Column({0}).Hidden = {1};"

 

#행정보

   @"sheet.Row({0}).CustomHeight = {1};"
   @"sheet.Row({0}).Collapsed = {1};"
   @"sheet.Row({0}).Height = {1}d;"
   @"sheet.Row({0}).Hidden = {1};"

 

#페이지프린트영역

   @"sheet.PrinterSettings.PrintArea = sheet.Cells[""{0}""];"

 

#정렬인데.. ( 에러날때가 있어..try{}catch{}로 묶어서 사용 )

   @"sheet.PrinterSettings.Orientation = eOrientation.{0};"

 

#페이지정보(기타)

   @"sheet.PrinterSettings.PageOrder = ePageOrder.{0};"
   @"sheet.PrinterSettings.PaperSize = ePaperSize.{0};"
   @"sheet.PrinterSettings.FitToPage = {0};"

   @"sheet.PrinterSettings.FooterMargin = {0}m;"
   @"sheet.PrinterSettings.HeaderMargin = {0}m;"
   @"sheet.PrinterSettings.LeftMargin = {0}m;"
   @"sheet.PrinterSettings.TopMargin = {0}m;"
   @"sheet.PrinterSettings.RightMargin = {0}m;"
   @"sheet.PrinterSettings.BottomMargin = {0}m;"

 

#페이지레이아웃보기

   @"sheet.View.PageBreakView = true;"

#확대비율

   @"sheet.View.ZoomScale = {0};"


 

위 정보를 조합으로 소스를 만들면 휘리릭... 1초만에 소스코드를 얻고 바로 시트작업을 할 수 가 있다.

 

 

epplus는 왜? 저장하고 나서 열면...

 

아무것도 안하고 닫는데, "저장하시겠습니까?" 가 뜰까?

 

저장을 한건데... 왜? 못찾겠다.

 

 

## 중요..

 

 Cell 병합관련해서 삽질을 하던 중...

 

 Merge 되는 셀 정보값은 시작되는 셀에만 값을 넣어야 된다.

 

  Sheent.Cells[ 시작되는 셀 ].Value = 값 또는 .Formula = 수식

 

 시작되는 셀이 아니고 병합되는 전체 셀을 모두 지정하면 각 셀에 모두 값을 넣게 되고

 

이 병합된 셀들을 다른 셀에서 수식으로 연계 할 경우 값이 원하는 값이 나오지 않게 된다.

  

  string.Format( @"sheet.Cells[ ""{0}"" ].Value = {1};",  cell.Start.Address, 100 );

 

 

 

 

 

 

 

 
 

 

친구가 필요하다는 프로그램을 만들었다.

 

프로그램은 매우 단순하다. 프로젝트별로 작업자의 일일 작업시간을 관리하는 프로그램!

 

등록화면은 찍을 수 없고... 몇가지 작업화면만 찍었다.

 

DB없이 파일로 관리한다. 

 

간만에 DataGridView를 이용해서 만들었다. ( 라이센스 있는 컨트롤들을 사용할수 없으니... 순수 컨트롤들을 재정의해서 만들어 사용했다. )

 

 

<메인화면 >

<상세화면>

<일별작업시간 기록화면>

 

저 일별 시간체크할때 저녁시간 빼고 구하는데 애먹었다. 3시간 날려먹었음..

 

이렇게 저장된 데이타들은 한번에 엑셀로 떨어진다.

많은 수식을 담고 떨어지니까 epplus를 사용해서 엑셀을 생성하였다. ( 시트는 찍어 올릴수 없으니... )

 

 epplus에 세로쓰기 << 프로퍼티는 끝내 찾지 못했다. 

 

추가요청사항이 있어서 모두 수정을 끝냈다.

 

 epplus로 새 파일을 생성하고 저장! 했는데??? 왜???? 파일을 열고 아무것도 안하고 닫는데 "저장하시겠습니까?" 가 뜰까??? 썩을... 못찾겠따.

 

 

 

 

http://www.sqler.com/876327#0

 

 

string 파싱하는데 늦다는 거였음.

 

12263,2,3,18321,2,1,19323,3,2,23152,5,4,27354,4,5  요런 문자열을 key1, key2, key3으로 분해하여 테이블형태로 변환하는 문제.

 

 string str = "12263,2,3,18321,2,1,19323,3,2,23152,5,4,27354,4,5";
            DataTable dt = new DataTable();
            dt.Columns.Add("Key1");
            dt.Columns.Add("Key2");
            dt.Columns.Add("Key3");

            string[] data = str.Split(',');
            for (int loop = 0; loop < data.Length; loop += dt.Columns.Count)
            {
                DataRow newRow = dt.NewRow();
                for (int col = 0; col < dt.Columns.Count; col++)
                {
                    newRow[col] = data[(dt.Rows.Count * dt.Columns.Count) + col];
                }
                dt.Rows.Add(newRow);
            }

 

요렇게 하면... 빠른데... 얼마나 많길래... 느리다고 하는 걸까? 거기에 xml파싱? 인가로 하면 더 빠를까?

 

 

음... 다시 가보니 쿼리로 풀어진 답글들이 있다..

 

그래서 나도...

 

declare @data xml = '<ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">' +
                             '<num>' + Replace( '12263,2,3,18321,2,1,19323,3,2,23152,5,4,27354,4,5',',','</num><num>')+  '</num>' +
                             '</ROOT>'
 
SELECT  ( [key] - 1 ) / 3 AS ord
       ,sum( CASE WHEN [key] % 3 = 1 THEN [value] END ) AS key1
       ,sum( CASE WHEN [key] % 3 = 2 THEN [value] END ) AS key2
       ,sum( CASE WHEN [key] % 3 = 0 THEN [value] END ) AS key3
  FROM  (
            SELECT  ROW_NUMBER() OVER( ORDER BY num1 ,num2 ,num3 ) AS [key]
                   ,M.tb.query( '.' )  .value( '.' , 'int' ) AS [value]
              FROM  @data.nodes( '/ROOT/num' ) AS M ( tb )
            ,(
                 SELECT  1 num1
                        ,2 num2
                        ,3 num3
             )AS nums
        ) tot
 GROUP  BY ( [key] - 1 ) /3
 

 

 

 

 

 프로그램을 만들때 비동기로 처리하고 싶다거나

 프로그래스 바로 진행율같은걸 표시하고 싶을때나...

 

사용하면 엄청 편하게 사용이 가능하다.

 

task나 await 같은 비동기... 처리도 있지만... ( 머리가 나쁘니 이해하는데 오래 걸리긴 한데... )

 

## 소스 사용예제

                       // todo : Excel Export
                        AsyncManagerClass async = new AsyncManagerClass();
                        async.BeforeAsyncCall = () => {
                            button1.DoInvoke(b => b.Enabled = false);  <-- 크로스 쓰레드를 회피! 하는 Invoke!
                            progressBar1.DoInvoke(p =>
                            {
                                p.Minimum = 0;
                                p.Maximum = src.Rows.Count -1;
                            });
                        };
                        async.AfterAsyncCall = () => {
                            button1.DoInvoke(b => b.Enabled = true);
                        };
                        async.Async(() => {
                            ExportToExcel(src);   <--- 비동기로 뭔가 열심히 처리 할수 있는 Method!
                        });

 

 

async.Async 내에서 호출되는 컨트롤들은 모두

             .DoInvoke( c => ... );  로 묶어서 처리 해주면 된다.

 

private void ExportToExcel(DataTable src)
{

    ... 생략 ...
    try
    {

        for (int row = 0; row < src.Rows.Count; row++)
        {
            progressBar1.DoInvoke( p => p.Value = row );

            ... 생략 ...   

        }
    }
    catch (Exception exc)
    {
        MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }

}

 

 

 #region 비동기 처리
    public class AsyncManagerClass
    {
        public Action BeforeAsyncCall = null;

        public Action AfterAsyncCall = null;

        public void Async(Action doActionMethod)
        {
            if (BeforeAsyncCall != null)
                BeforeAsyncCall();

            IsRun = true;
            if (doActionMethod != null)
            {
                doActionMethod.BeginInvoke(ir =>
                {
                    try
                    {
                        doActionMethod.EndInvoke(ir);

                        if (AfterAsyncCall != null)
                        {
                            AfterAsyncCall();
                        }
                    }
                    catch
                    {
                        // 작업 중!! 예외
                    }
                    IsRun = false;
                }, null);
            }

        }

        public void Stop()
        {
            IsRun = false;
        }

        public bool IsRun { get; set; }
    }

    public static class Ex
    {
        public static void DoInvoke<T>(this T ctrl, Action<T> callMethod) where T : Control
        {
            if (ctrl.InvokeRequired)
            {
                ctrl.Invoke(new Action<T, Action<T>>(DoInvoke), ctrl, callMethod);
            }
            else
            {
                callMethod(ctrl);
            }
        }
    }
    #endregion

 

# 데이타 테이블 정의서를 엑셀에 뽑아내는 프로그램.

 

 

  -- 나한테도 이미 돌아다니며 구한 몇가지 버젼이 있지만...

     이번에 새로이 만들었다.

 

 object Like에는 like문 그대로 입력해주면... 필터링 가능하다.

   ex ) D[w|a]    ( '%'는 뒤에만 소스 주석에서 걸려있음, 파라미터로 전달하니까... )

 

내려받기를 클릭하면 프로그래스로 진행율을 표시하고...  아래 양식으로 테이블별로 만들어진다.

 

Column 명( C열 ) 또는 Table 명( E열 )  을 입력하면

   I열은 설명을 추가하는 스크립트가 나온다.

   J열은 설명을 삭제하는 스크립트가 나온다.

       

 

   음 추가가 필요한 기능은 메타!!  ( 시간될때 또... 넣자. )

'# 4) .Net ( Vs 2010 ) > C#' 카테고리의 다른 글

Sqler 에 올라온 질문 글...  (0) 2016.10.21
비동기 처리...를 간단히!!!  (0) 2016.10.18
로또 체크기...?  (0) 2016.10.18
Class를 XML변환, XML을 Class변환  (0) 2016.09.12
DevExpress WinForm] Layout 보완...  (0) 2014.10.12