'C#'에 해당되는 글 11건

  1. 2008.12.29 :: ListView에서 Drag & Drop
  2. 2008.11.22 :: C#의 Setting Class
  3. 2008.11.21 :: 시리얼 장비 통신에 대한 짧은 이야기
  4. 2008.11.14 :: 폼안의 컨트롤을 foreach로 돌리는법 2
  5. 2008.11.14 :: 크리스털 리포트 4
  6. 2008.11.14 :: 크리스털 리포트 3
  7. 2008.11.14 :: 크리스털 리포트 2
  8. 2008.11.14 :: 크리스털리포트 1
  9. 2008.11.14 :: 가르쳐 줬잖아.
  10. 2008.11.14 :: Spread Setting 2
  11. 2008.11.14 :: Spread Setting 1
C#/일반적인코딩 2008. 12. 29. 00:02

리스트 뷰에서 드래그 드랍을.. 하려고 한다.

 

http://blog.naver.com/pino93?Redirect=Log&logNo=30009078322

 

이 글에 보면 리스트뷰에서 드래그 드랍을 설명하는데 문제는 스트링을 값을 넘기도록 한다는것이다.

 

윈도우의 객체들은 아니.. 뭐냐 여러가지 컨트롤들은 객체단위로 쪼갤수 있는 개념을 가지고 구조를 가지고 있다.

예를 들어서 TreeView의 경우 TreeView는 실제적인 표현만 할뿐 우리가 사용할것은 TreeNode 란 각 개체가 주가 된다.

 

마찬가지로 ListView의 경우에도 ListViewItem 이 주가되도록 되어 있다는 것이다.

그러니까 결국 넘길때도 당연히 리스트뷰가 주가 아닌 아이템을 넘겨야 한다는 이야기다.

아마도 이런 컨트롤이 닷넷 2.0이후에 나왔다면.. list<ListViewItem> 같은 컬랙션을 가지지 않았을까 짐작을 하지만 대략의 버전들이 이전에 만들어진 상태에서 변경자체를 두려워 할수 밖에 없다면 어쩔수 없이 그때의 가지고 있는 자체 컬랙션에 담겨있게되는것이다.

ListViewItemCollection도 아닌 ListView.SelectedListViewItemCollection 이란곳에 담겨져 있다. 나중에 클래스내부를 한번 열어보고 싶은데 listview의 내부에 다시금 컬랙션을 선언해서 이렇게 한 이유가 있겠지만 하여간 이전버전에 컨트롤을 만들면서 왜 이럴수 밖에 없었는지 매우 궁금하다. 아마도 요즘에 만들었다면 IEnum쪽으로 Item들의 select 특성을 뒤져서 List<> 컬랙션에 넣어서 반환하지 않았을까 하는 짐작을 하지만 옛날에는 나름 셀렉션? 적인 문제가 있었거나 그런문제들을 복합적으로 해결하기 위해서 개체가 따로 있는 방식이 아닌 Livew의 내부클래스로 선언해서 처리하지 않았나 하고 짐작해본다. 새롭게 만들면 이것도 GridView가 DataGridView 처럼 바뀌어야 될테니.. 하여간 아마도 그럴일은 없겠지만..

 

드레그 드랍시도 이것을 넘겨줘야 한다. 왜냐면 우리가 선택한 아이템은 하나가 아니고 여러개일수 있기 때문이다.

그래서 넘겨주는 곳에는 마우스 다운이나 또는 마우스 무브에...(일반적으로 다운에 서술한다. 왜냐면..불필요한 코딩을 처리하지 않기 위해서이다.)

   1: private void listView1_MouseDown(object sender, MouseEventArgs e)
   2: {
   3:     DragDropEffects effect;          
   4:     effect = this.DoDragDrop((sender as ListView).SelectedItems, DragDropEffects.Copy);
   5: }
 

이런식의 삽입처리를 해주고

 

이것을 받는곳에는..다소황당하겠지만 이미 설명했듯이 이전버전의 닷넷에서 가질수 없는 컬랙션을 자체적으로 가지기 위해서는 어쩔수 없었다고 이해하는것이 맞다고 본다.

 

   1: private void listView2_DragDrop(object sender, DragEventArgs e)
   2: {
   3:     ListView.SelectedListViewItemCollection lvCollection = 
   4:         (ListView.SelectedListViewItemCollection)e.Data.GetData(typeof(ListView.SelectedListViewItemCollection));
   5:  
   6:     foreach (ListViewItem item in lvCollection) listView2.Items.Add(item);
   7: }

 

이런식의 삽입이 이루어 져야한다.

황당한 캐스팅으로 값을 가져오지만.. 이렇게 처리함으로 인해서 정상적으로 선택한 리스트뷰의 값들을 가져와서

쉽게 추가할수 있는것이다.

'C# > 일반적인코딩' 카테고리의 다른 글

C#의 Setting Class  (0) 2008.11.22
시리얼 장비 통신에 대한 짧은 이야기  (0) 2008.11.21
폼안의 컨트롤을 foreach로 돌리는법  (2) 2008.11.14
posted by 삶의여유로움
:
C#/일반적인코딩 2008. 11. 22. 21:34

이글을 적는 이유는..

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=17&MAEULNO=8&no=100533&ref=100533&page=2

전적으로 이글때문이다.

이글을 적으신분의 성함이 내가 아는분과 같기때문이다.

왠지.. 답을줘야 될것같은.. 막연한.. 의무감 같은거 말이다.

일단 커피한잔 때리고 와서 더 적자..

 

시작하면서..

우리의 아련한 기억속에..

WritePrivateProfileString / GetPrivateProfileString

이녀석들의 API가 남아 있는지 모르겠다. 뭐 나야 한번도 사용을 안해본거라서 저게 당최 뭔지 모른다만 아시는분들이 보시면.. 흐~ 하고 미소를 지을듯 싶다.

 

GetPrivateProfileString("거시기", "어라시구", "뭐니", "xxx.ini") 같은 이상한것들을 적어두고.. 제일뒤에 xxx.ini만 있으면..

그 프로그램마다 ini를 만들고 저장하던게 아니였나 싶다. 상세한건 당근 생략이다.

지금에 와서 저걸 사용하는 사람들도 거의 없기도 하거니와 요즘은. XML이란 요물단지덕분에 세상이 많이 변했기 때문이다.

캬~~ 또 예제를 만들어야 하다니.. 안습이다.

 

심심풀이로 콘솔을 만들어보도록 하자..

clip_image001

어디에도 셋팅이 보이지 않는다.

clip_image002

조금 보일까 말까한다.

clip_image003

흐흐..

clip_image004

그렇다.. 이건 뭐 너무 쉬운이야기들이라서.. 모르는사람이 거의 없을 수준이라고 본다만..

그래도 일일이 그림으로 적어본다.

clip_image005

 

저걸 눌러서 MSDN을 보길 바란다.

 

거기에 상세히 읽어보면 된다.

자.. 내가 글을 적으면 뭐하겠냐.. 얼른.. 빠르게 넘어가자.

횡설수설만 늘어날뿐..

개념도 쉬우니 금방 이해될것이다.

기본활용중 하나..

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNO=8&no=1576&page=1

이렇듯 다들 잘 사용하는것에 대해서 굳이 내가 적을글이 뭐가 있을까.?

그렇다. 그러니 링크들로 이야기를 대신하자.

http://csharp-projects.blogspot.com/2008/01/windows-forms-user-settings-in-c.html

이글을 읽게되면.. 즉 INI의 대용적인 프로그램의 시작위치와 폼의 크기를 다시 셋팅하는것을 이야기 한다.

아.. 혹시나. 질문을 할까봐 미리 대답의 링크를 적어두자면

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=17&MAEULNO=8&no=99697&ref=99672

셋팅된 xml파일은 여기에 저장이 된다.

Msdn의 글

http://msdn.microsoft.com/en-us/library/aa730869(VS.80).aspx

 

//-------------------------------------------------------------------------------------------------------

 

자 이제부터 내이야기를 적어보자..

뭐 이미 저정도 풀었으니 알만큼 알았을테고… 하지만..안습이게도 영어거부증과

몇몇 아티클을 대충읽는 이들이 많으니 어쩔수 없이 그들을 낚기 위해서는 뭔가 있어보이는걸 뿌려야 한다는것이다.

 

참.. 안습이다.

그러나 이미 콘솔로 시작했으니 뭐.. 낚을게 별로 없다.

하여간.. 기본적으로 어풀리케이션의 값을 저장해서 다시 시작할때 다시 그값을 자동적으로 셋팅해서 사용할수 있다는것이 핵심이다.

그것을 위해서 가볍게 음… 어떤 예제가 좋을까 음………………

콘솔이다 보니 쉽게 이런것을 예제로 하자 당신이 프로그램을 종료할때의 시간을 기록해서

다시 시작할때 보여주는것이다.

(예제로는 정말. 별로이긴 하다 ㅠ.ㅠ)

 

 

자 코딩을 해보자.

clip_image006

clip_image007

clip_image008

자.. 이렇게 될것이다.

이제 우리는 저장루틴을.. 또 첨부하자.

저장은.. 뭐 어려운게 없다.

clip_image009

자 시간을 비교해 봐라..

몇십초 차이가 나지 않는가?

static void Main(string[] args)

{

Console.WriteLine("현재시간은 : " + DateTime.Now.ToString());

Console.WriteLine("당신의 마지막 로긴시간은 : " + Settings.Default.LonginTime.ToString());

Settings.Default.LonginTime = DateTime.Now;

Settings.Default.Save();

}

 

//-----------------------------------------------

 

이렇게 간단하게 값을 저장하는것이 가능하다.

Save란 호출 하나로 말이다.

당연히 자동으로 불러와서 셋팅까지 되니 예전의 INI에 비하면.. 천국이 아닐수 없다.

여기서.. 바로 다음과정으로 가도 되겠지만 게으른 당신을위해서 저것이 저장되는 모습을 살짝이 살펴보자.

clip_image010

실제적인 저장은.. 이렇게 된다.

XML인 것이다.

그렇다. 당연히 이런것은 당신에게 무지 익숙할것이고 이정도라면.. 당연히 DataSet같은건 말밥으로 들어갈꺼란 이야기다. 그러나 질문자의 의도는 무엇이였나?

그렇다. 그넘의 해쉬~ 테이블이였다.

clip_image011

 

위의 글을 상세히 보면.. Serialize가. AS.. 즉. String이란거다. 만약 데이터 테이블같은걸 넣었다면.. XML 이라고 될것이다.

그럼.. 해쉬는 안될까?

일단은.. 이 클래스를 살펴봐야겠다.

clip_image012

우리가 셋팅이란 클래스를 만들게 되면.. 위에 그림으로 설명한.

clip_image003[1]

이걸 누르게 되면..

위의 솔류션에 Setting이란.. CS파일이 생긴다. 저 파일을 보면.

clip_image013

대충.. 이런게 생성이 된다.

 

요걸 잘 조물딱 거리면.. 우리는 이 난국을 해쳐 나갈수도 있을것이다.

 

그러기 위한 테스트를 하나 더 만들어야 겠다.

clip_image014

요렇게 만들면..

clip_image015

요렇게 만들어 질것이다.

일단은.. 시도를 해보자.

clip_image016

 

이런.. 안된다. 역쉬다.

clip_image017

코드야.. 뻔한 이야기고..

안된다는 것이다.

 

------------------------

[SerializableAttribute]

[ComVisibleAttribute(true)]

public class Hashtable : IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ICloneable

처음에 해쉬테이블의 ISerializable, IDeserializationCallback, 라고 적힌걸 못 보았다.

덕분에 이걸 만들어야 하나.. 졸라 짜증이 밀려왔더랬다.

두번째 보니 이게 보이더라는..

------------------------

 

그러나.. 포기를 하면되겠는가.. 안되는거 알지만 한번더 해보자.

clip_image018

스트링도 안된다.

막판이다.. 그렇다. 바이너리 함 찍어보자.

clip_image019

졸 삽질이다.

그렇다. 된다.

clip_image020

 

//-----------------------------------------------------

 

[SerializableAttribute]

[ComVisibleAttribute(true)]

public class Hashtable : IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ICloneable

 

IXmlSerializable 는 XML로.. 구현을 뽑고

Iserialiable는 Binary로 뽑아서 사용하자.

 

상세한 설명은.

http://msdn.microsoft.com/ko-kr/library/system.configuration.settingsserializeasattribute.settingsserializeasattribute.aspx

 

 

 

 

posted by 삶의여유로움
:
C#/일반적인코딩 2008. 11. 21. 00:34

Serial에 대한 볼거없는 MSDN

http://msdn.microsoft.com/ko-kr/library/system.io.ports.serialport.aspx

Serial에 대한 반드시 읽어봐야 하는 문서

http://msmvps.com/blogs/coad/archive/2005/03/23/SerialPort-_2800_RS_2D00_232-Serial-COM-Port_2900_-in-C_2300_-.NET.aspx

크로스쓰레드에 대한 MSDN

http://msdn.microsoft.com/ko-kr/library/ms171728(VS.80).aspx

 

 

세상에는 나처럼 든거없이 떠드는 빈깡통이 있는반면

항상진중하게 자기 할것만 하고 다른이가 정리한것만 보는 착실한 친구들이 있다.

누가 옳고 그른것들은 없다. 세상의 구성원이란게 원래 그런거니까. 그렇게 그렇게 무엇인가가 조화롭게 이루어져 나가는것이 좋은것이라 생각한다.

두개체가 적정비율이 되는것이 가장 중요한것 같다. 비율이 한쪽으로 쏠린다면 결국 서로 좋은게 없지 않을까 한다.

 

상상은 스스로 하기로 하고

지금부터 떠들 깡통의 소리는..

시리얼에 대한것이다. 정말 쉽다.

별게 없다.

 

이글은 단지 심풀하게 시리얼에서 데이터를 받는것을 보여주고자 한다.

왜냐면 내가 해야되는일중에 하나가 전화가 오면 그 전화번호를 화면에서 보여주는데 검색을 통해서 누가 전화를 한지 알려주기 위한것이기 때문이다.

clip_image001

아주 간단하게.. 코딩이 완료되었다.

하지만.. 여기서..

에러를 발견하게 될것인데.

clip_image002

이런에러가 발생될것이다.

이건.. 너무나도 일반적인 이야기 임에도 아직도 질문을 하는 인간들이 많으니.. 상세~~~ 하게 이야기 해보자.

clip_image003

아마도 2.0부터 이렇게 되고.. 그 하위버전에서 처리한다면.. 델리게이트를 외부에서 선언해주고 함수또한 외부에 넣어주고.

구문내에서는.. 호출함수를 적어주면 될것이다.(물론 하위버전에서는 저런 오류가 나오지 않는다.)

굳이 이렇게 귀찮게 코딩을 하는것은 폼클래스에서 돌고있는 쓰레드와

우리가 생성한 시리얼포트에서 처리되는 쓰레드가 말그대로 교차되기 때문이다.

그럴때 교차의 순서를 정해주는 입장이라고 생각하면 되는데…. 즉.. 시리얼에서 데이터를 받아서 그것을 택스트박스에 뿌려주는것을

폼쓰레드의 this.Invoke는 폼의 함수호출을 의미한다.

거기내에서 실제 실행되어야 하는것을 넣어주는것이다.

clip_image004

clip_image005

물론… 폼쓰레드에 넣는게 황당하다고 생각된다면..

clip_image006

이런식으로 textBox의 쓰레드에 넣어도 된다..

여전히 뭔말인지 모르겠다면..

clip_image007

이렇게 만든 아주 간단한.. 폼 파일인데…

이녀석의 쓰레드 개수는

clip_image008

clip_image009

이렇게 15개나 된다. 그냥.. 폼만 만들면.. 대략 9개던가?의 쓰레드가 돌아가는데..

하여간.. 심풀한 폼에도.. 이렇게 쓰레드가 많이 돈다는 이야기다.

그러니 그 녀석들간의 충돌이 문제가 없게 하기위해서는 서로간의 일종의 동기화가 맞아야 하는것이고

 

동기화를 맞춰 주기위해서 저렇게 처리해주는것이다. 물론.. 무식하게.. 동기화고 뭐고

내맘이다 할때는 그럴때를 위해서.. MS이런것도 만들어 두었다.

clip_image010

     

 

using System.IO.Ports;

 

namespace WindowsApplication9

{

    public partial class Form1 : Form

    {

 

        SerialPort port = new SerialPort("COM3", 19200, Parity.None, 8, StopBits.One);

 

        public Form1()

        {

            InitializeComponent();

            port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);

            port.Open();

            CheckForIllegalCrossThreadCalls = false;

        }

 

        void port_DataReceived(object sender, SerialDataReceivedEventArgs e)

        {

            textBox1.Text += port.ReadExisting();

        }

 

    }

}

 

 

참고로.. 포트 COM3라고 적은것처럼.. 저것과 속도 19200<--- 등등은 장비에 따라 다르니 저게 틀린다면..

들어오는 정보는.. 잡음이라고 생각해야 할것이다.

 

 

위의 크로스 쓰레드에 대한이야기는 네트웍의 채팅프로그램같은것을 만들때도 반드시 알아야 하니..

꼭 숙지(?)고 뭐고 이미 다 알고 있을거라 믿는다.

 

귀차니즘을 무릎쓰고…

image

내부에서 함수로 처리되지 않고 실제적인 델리게이트의 모습으로 이쁘게 처리된다면… 요렇게 해야겠지.

'C# > 일반적인코딩' 카테고리의 다른 글

ListView에서 Drag &amp; Drop  (0) 2008.12.29
C#의 Setting Class  (0) 2008.11.22
폼안의 컨트롤을 foreach로 돌리는법  (2) 2008.11.14
posted by 삶의여유로움
:
C#/일반적인코딩 2008. 11. 14. 21:58

     

    이 글을 적은지도 꽤 지났는데 어느날..

    http://mkexdev.net/Article/Content.aspx?parentCategoryID=1&categoryID=25&ID=322

    이글을 봤다.

    흐흐.. 저기 적혀 있는게 더 나은 루틴이다.

     

    모양이 똑같다 그런데 흐흐 잠시 흠칫 놀랐더랬다.

    뭐 그리 똑같지는 않다만..

     

    실제 업무에서 쓸때는 DB쪽 강좌에 적은 Reflection을 이용한것을 사용해 보길 권한다.

    개인적으로 루틴돌리기에는 그것도 나쁘지 않은듯 보여진다.

    우째도 내가 저 링크보다 좀 더 아는척 해보고 싶다. ㅋㅋㅋ

    사실 아는건 쥐뿔도 없다는 다들 알꺼고..

     

    개인적으로 저 사이트 참 괜찮다. 공부할게 많으니 들러서 모든 글을 싸그리 다 읽어버리길 권한다.

     

    내가 적은 여기 블러그는 저 사이트에 비하면.. 조족지혈이다.

     

    휠씬 더 나은방법을 사용하고 있으니 잘.. 참고하길 바란다.

     

    ------------------------------------------------

     

    참 부족한 프로그래머로서 남의코드에 이러쿵 저러쿵 할말은 없으나

    그래도 항상 하는짓이 꼭 남의코드 수정이나 해야되는 입장에서

    되도록 그분들의 코드가 잘~ 작성되었으면 하는 바램이 있다.

    http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=17&MAEULNO=8&no=97314&ref=97314&page=1

    이글을 읽다가 문득 마음이 아파왔다.

    일전에 약 70여개의 컨트롤들의 탭이나 입력값을 제어하는 코드를 수정해 줘야했는데

    그 코드가 마치 하나하나 대입하거나 IF문을 사용했던것이

    수정을 위해서도 어찌그리나 피곤하던지 말이다.

    믿어지지않겠지만 35번째를 수정하면 그 이하 코드를 다 수정해야 되도록 코딩을 해 두셨다.

    게다가 폼만.. 30개쯤 되었으니.. 어림잡아.. 300여개정도.. 코딩으로 1000줄은 수정해 줘야했던듯 했다.

    참 마음아프게도 이 코드를 수정을 해줘야 겠는데 다 지우고 그냥 몇줄 적으면 되는것을

    지워야 하나 아님 새로 만들어야 하나를 두고 고민했었다.

    지우자니 굴러온돌(?) 박힌돌의 코드를 맘대로 수정했다고 욕먹을듯 눈치는 보이고

    그렇다고 양해를 구해보니 절대 수정하지 말라는 황당한 요청은 들어오고

    그렇다고 이걸 수정하자니 너무 많은 수정이 있었다.

    일단 기초적 방법은 두가지가 있다.

    하나는 Collection에서 foreach를 이용하는것이고

    두번째로는

    그 응용으로 컬랙션의 값을 다시금 컬랙션으로 만드는것이다.

    전자의 방법은 collection내부에 다시금 collection이 포함된경우 그 내부의 컬랙션안에 들어간것을 처리할수가 없다.

    이말 조차 이해를 못하는 사람들이 있을까봐 다시금 풀어서 이야기하자면

    폼은 하나의 컬랙션개체이고 그룹박스, 패널, 탭컨트롤 등등도 컬랙션 개체이다.

    즉 잘 풀어서 이야기 하면 폼에 라벨을 두고 그룹박스 않에 라벨을 두면

    두개의 개체에 있는 라벨을 foreach로 모두 처리하기에는 피곤하다는 이야기다.

    그래서 즉.. 두번째 방법을 사용하게 된다.

    미래에 내가 또 어느곳에 가서 코드를 수정해 주고 있을지 모르나

    그분들의 코드가 조금은 수정하기 쉽게 만들어지길 바라는 조그만 소망으로 이글을 적어본다.

    clip_image001

    그림은 일반적으로 쉽게 볼수 있는 형태이다.

    여기서 좌측에 있는 label1,2,3에대가 1,2,3을 대입해 보도록 하자.

    그러기 위해서 저 라벨을 포함한 컬랙션에서 끄집에 내면 될것이다.

    foreach (Control x in this.Controls )

    처럼 적게되면.. 폼에 포함된 모든 컨트롤을 가져오게 된다.

    예를 들어서

    clip_image002

    이런 코드를 작성했다고 하자.

    그럼..

    clip_image003

    이런 화면이 나타날것이다.

    여기서 그룹박스에 숫자 "2"가 나오는것을 유심히 보고

    또한 그룹박스 이내에 있는것들은 아무런 변화가 없는것을

    확실히 인지하기 바란다.

    자.. 일단은 뭔가 될것 같기는 하다. 그럼 여기서 우리가 원하는 라벨에만 숫자를 생성시켜야 한다는것이 두번째 과제일것이다.

    그것은 어떻게 해야할까? 그것도 그리 어렵지 않다. 그 컨트롤이 단지 라벨인가만 확인해주면 되는것이다.

    clip_image004

    clip_image005

    여기까지 해줬음에도 불구하고 또 질문이 들어온다.

    난 위에서 부터 1,2,3을 처리하고 싶은데 어떻게 해야하냐고

    i--처럼 역순으로 해야하나고 말이다.

    이글의 앞에 컬랙션이라고 이야기 했듯이

    이 컬랙션들은 ADD형태로 내부에 사용되는 녀석들을 대입해줘야 한다.

    그 대입의 순서에 따라서 위와 같은 형태가 나타나게 되는것이다.

    clip_image006

    디자이너에 가서.. 컬랙션 대입하는곳을 찾아보자.

    clip_image007

    자 보이듯이 라벨1이 가장 늦게 들어가니 순서가 늦게 되는것이다.

    이 순서를 원하는데로 변경해 두자.

    사용하는 ADD 이런매서드로 말이다.

    clip_image008

    자 이제.. Foreach의 설명을 마칠까 한다.

    Foreach로 그룹박스안에것도 돌리기 위해서 다시금 foreach안에 또 foreach구분을 넣어서 그룹박스일때 돌려야 할것이다.

    뭐.. 그렇게 한들 어떻다고 생각한다면.. 어쩔수 없다.

    나야.. 그렇게 작성된 소스 수정한다고 또 고생길이 열리는수 밖에..

    윈폼프로그램에 빠질수 없는것이 있다면 위와같은 폼에서 입력후

    모든 입력값을 지워야 하는것이다.

    초기화란 어디가나 꼭 있어야 하는것이니 모두들 동감하리라 믿는다.

    위의 예제에서 보듯이 그룹박스내에 포함된 택스트 박스는 foreach만으로는 초기화가 되지 않을것이다.

    그럼 어떻게 해야 하는가? 바로 그 두번째 방법을 사용해야될것같다.

    뭐 대단한 방법이라고 기것해봐야 재귀호출일뿐인데 말이다.

    코드는 두어줄이라서 설명할것이 없다만

    그래도 모르겠다면 질답란에 적어두면 누군가 상세히 설명을 해줄것이다.

    함수는 이것이고

    private void getControls(Control.ControlCollection Ocontrol, ref ArrayList Space)

    {

    for (int i = 0; i < Ocontrol.Count; i++)

    {

    Space.Add(Ocontrol[i]);

    if (Ocontrol[i].Controls.Count > 0) getControls(Ocontrol[i].Controls, ref Space);

    }

    }

    호출은 이렇게 하자.

    ArrayList AL = new ArrayList();

    getControls(this.Controls , ref AL);

    for (int i = 0; i < AL.Count; i++)

    {

    if (AL[i] is TextBox)

    ((Control)AL[i]).Text = "초기화";

    }

    자 이렇게 하면 결과는..?

    clip_image009

    그룹박스 안에 있는것까지 깔끔하게 처리가 된다.

    이럼에도 시비(?)를 거는 친구들이 가끔 있을듯 해서

    조금 더 복잡하게 만들어서 테스트를 해보자.

    clip_image010

    아주 가볍게 처리가 되지 않는가?

    폼에.. 탭에.. 패널에 그룹박스에 다시 그룹박스에 탭에 등등

    을 해도 잘 처리가 된다.

    참고로.. 귀찮아서 적지는 않았지만..

    this.Controls["textBox1"].Text = "ddd";

    이런식으로 사용하거나 또는 find를 가지고 바로 컬랙션안의 포함된 컬랙션내부 개체를 억세스 하거나

    하는 방법이 있다.

    this.Controls[0].Text = "ddd";

    문제는 이건 적을만한 수준이 아니란 거다..

    이렇게 쉽게(?) 적었는데도 모르겠다면. C#책에서. Collection 에 대해서 공부해 보길 권한다.

    ps) 노파심에 끄적이자면.. 실무에서는 이것보다는 좀 더 세련된 형태로 함수를 만들어서 사용한다.

    잘.. 다듬어서 사용하길 권한다.

    ps2) 예외 사항에 대처하는법에 대해서 몇가지 더 끄적여 보자. (댓글 덕분에 더 적어본다.)

    예외사항은.. 여러가지가 있겠는데 결론적으로 말해서 특정한 녀석만 위의 루틴이 돌아갈때 처리가 되지 않아야 된다는 이야기다.

    만약 그런것이 아주 많다면..  IF를 이용해야 겠지만.

    하나 둘의 경우 Find를 사용해 주는게 좋다.

    강좌를 적고 이미 이 프로젝트를 날린 입장이라.. 예제를 더 못 보여주는것은 아쉬우나.

    --> this.Controls.Find("textBox1", true);

    이런형태를 통해서 대부분 예외를 처리하는걸로 알고 있다.

    여기서 핵심은 뒤에 true 를 주는것이고 내부적으로(c#)에서 재귀호출함수를 이용해서 컬랙션개체 안에 있는것들까지

    찾아서 그 인스턴스값을 돌려준다. 단지 문제는 귀찮게도 control[] 배열로 돌려준다는것이긴 하지만..

    그래서 개인적인 입장에서는 앞에서 만든 ArrayList 에서 특정값을 제거한다. remove 를 통해서 돌아야 하는것중

    예외사항을 제거하고 돌린다.

    위의 재귀호출함수는 이해를 위해서 3줄로 작성되어 있지만.. 실제적으로 사용하고 있는것은.. 함수가 아닌 클래스로

    대략.. 30댓줄의 몇몇개의 기능이 추가되어 있다. 귀찮게 arraylist를 선언하지도 않고.. 이런 예외를 편하게 제거하도록 말이다. 개인적 취향에 맞도록 잘 만들면 되지 않을까 한다.

    ps3) 댓글의 관심에 감사함을 전한다.

'C# > 일반적인코딩' 카테고리의 다른 글

ListView에서 Drag &amp; Drop  (0) 2008.12.29
C#의 Setting Class  (0) 2008.11.22
시리얼 장비 통신에 대한 짧은 이야기  (0) 2008.11.21
posted by 삶의여유로움
:
C#/크리스털리포트 2008. 11. 14. 17:51
   1: using CrystalDecisions.CrystalReports.Engine;
   2: using CrystalDecisions.ReportAppServer.ReportDefModel;
   3: using CrystalDecisions.ReportAppServer.ClientDoc;
   4:  
   5:     public class AutoReport
   6:     {
   7:         //전체 표의 위치를 의미한다.
   8:         int GridMarginTop = 0;
   9:         int GridMarginLeft = 500;//왼쪽마진을 의미
  10:         int GridMarginRight = 500;
  11:         int GridMarginBottom = 0;
  12:         int GridWidth = 0;
  13:         
  14:         //셀 내부의 공간을 의미한다. 
  15:         int CellMarginTop = 70;  
  16:         int CellMarginLeft = 70;
  17:         int CellMarginRight = 70; // 셀 내부의 오른쪽 마진을 의미
  18:         int CellMarginBottom = 70;
  19:         int PageWidth = 0; //페이지의 가로길이
  20:         int FontSize = 10;
  21:         //기초상수들..
  22:         const int FontToCrystal = 20; //폰트크기와 크리스탈리포트변환 크기상수
  23:         const int SpreadSizeToCrystal = 20;  //스프레드의 컬럼사이즈크기를 크리스털로 넘길때.
  24:         const int LINETHICKNESS = 5;
  25:         
  26:         //----------------------------------
  27:         List<int> _GridColumnPoint = new List<int>();
  28:         List<string> _HeadName = new List<string>();
  29:         List<string> _FieldName = new List<string>();      
  30:         CrystalDecisions.CrystalReports.Engine.ReportDocument _Report;
  31:         ISCDReportClientDocument IReport;
  32:         CrystalDecisions.ReportAppServer.ReportDefModel.Section ReportHeadSection;
  33:         CrystalDecisions.ReportAppServer.ReportDefModel.Section ReportFooterSection;
  34:         CrystalDecisions.ReportAppServer.ReportDefModel.Section PageHeadSection;
  35:         CrystalDecisions.ReportAppServer.ReportDefModel.Section PageFooterSection;
  36:         CrystalDecisions.ReportAppServer.ReportDefModel.Section DetailSection;
  37:         DataSet _DataSource = null;
  38:         string dataTableName = "";
  39:         //데이타 소스 프러퍼티
  40:         public DataSet DataSource
  41:         {
  42:             get { return _DataSource; }
  43:             set 
  44:             {
  45:                 _DataSource = value;
  46:                 dataTableName = _DataSource.Tables[0].TableName;
  47:                 _Report.ReportClientDocument.DatabaseController.AddDataSource(
  48:                 CrystalDecisions.ReportAppServer.DataSetConversion.DataSetConverter.Convert(_DataSource) );     
  49:             }
  50:         }
  51:         // 생성자.
  52:         public AutoReport(CrystalDecisions.CrystalReports.Engine.ReportDocument Report)
  53:         {
  54:             _Report = Report;
  55:             
  56:             //------------------------------            
  57:             IReport = _Report.ReportClientDocument;
  58:             DetailSection = IReport.ReportDefController.ReportDefinition.DetailArea.Sections[0];
  59:             PageHeadSection = IReport.ReportDefController.ReportDefinition.PageHeaderArea.Sections[0];
  60:             PageFooterSection = IReport.ReportDefController.ReportDefinition.PageFooterArea.Sections[0];            
  61:             ReportHeadSection = IReport.ReportDefController.ReportDefinition.ReportHeaderArea.Sections[0];
  62:             ReportFooterSection = IReport.ReportDefController.ReportDefinition.ReportFooterArea.Sections[0];
  63:             PageWidth = ReportHeadSection.Width; //페이지 가로길이
  64:             GridMarginTop = PageHeadSection.Height - (FontSize * FontToCrystal) - CellMarginTop - CellMarginBottom;
  65:             _GridColumnPoint.Add(GridMarginLeft);
  66:         }
  67:         //선을 추가한다.
  68:         public void AddLine(int leftPoint, int topPoint, int rightPoint, int bottomPoint, int lineThickness, string Position)
  69:         {
  70:             CrystalDecisions.ReportAppServer.ReportDefModel.LineObject Line = new CrystalDecisions.ReportAppServer.ReportDefModel.LineObject();
  71:             Line.Left = leftPoint;
  72:             Line.Top = topPoint;
  73:             Line.Right = rightPoint;
  74:             Line.Bottom = bottomPoint;
  75:             Line.LineThickness = lineThickness;
  76:             Line.LineStyle = CrystalDecisions.ReportAppServer.ReportDefModel.CrLineStyleEnum.crLineStyleSingle;
  77:             Line.EnableExtendToBottomOfSection = false;
  78:             if (Position.ToUpper() == "HEAD")
  79:             {
  80:                 Line.SectionName = PageHeadSection.Name;
  81:                 Line.EndSectionName = PageHeadSection.Name;
  82:                 _Report.ReportClientDocument.ReportDefController.ReportObjectController.Add(Line, PageHeadSection, -1);
  83:             }
  84:             if (Position.ToUpper() == "DETAIL")
  85:             {
  86:                 Line.SectionName = DetailSection.Name;
  87:                 Line.EndSectionName = DetailSection.Name;
  88:                 _Report.ReportClientDocument.ReportDefController.ReportObjectController.Add(Line, DetailSection, 1);
  89:             }
  90:         }
  91:  
  92:         //필드를 추가한다.
  93:         public void AddField(int leftPoint,int topPoint, int height, int width, string fieldName)
  94:         {
  95:             CrystalDecisions.ReportAppServer.ReportDefModel.FieldObject Field = new CrystalDecisions.ReportAppServer.ReportDefModel.FieldObject();
  96:             Field.Left = leftPoint;
  97:             Field.Top = topPoint;
  98:             Field.Height = height;
  99:             Field.Width = width;
 100:             Field.SectionName = DetailSection.Name;
 101:             Field.Format.HorizontalAlignment = CrAlignmentEnum.crAlignmentHorizontalCenter;
 102:             Field.FieldValueType = CrystalDecisions.ReportAppServer.DataDefModel.CrFieldValueTypeEnum.crFieldValueTypeStringField;
 103:             Field.DataSourceName = "{" + dataTableName + "." + fieldName + "}";
 104:             _Report.ReportClientDocument.ReportDefController.ReportObjectController.Add(Field, DetailSection, 1);
 105:         }
 106:         //택스트를 추가한다.
 107:         public void AddText(int leftPoint, int topPoint, int height, int width , int fontSize , string sText)
 108:         {
 109:             CrystalDecisions.ReportAppServer.ReportDefModel.TextObject Text = new CrystalDecisions.ReportAppServer.ReportDefModel.TextObject();
 110:             CrystalDecisions.ReportAppServer.ReportDefModel.Paragraph Para = new CrystalDecisions.ReportAppServer.ReportDefModel.Paragraph();
 111:             CrystalDecisions.ReportAppServer.ReportDefModel.ParagraphElements ParaE = new CrystalDecisions.ReportAppServer.ReportDefModel.ParagraphElements();
 112:             CrystalDecisions.ReportAppServer.ReportDefModel.ParagraphTextElement ParaText = new CrystalDecisions.ReportAppServer.ReportDefModel.ParagraphTextElement();
 113:             ParaText.Text = sText;
 114:             ParaE.Add(ParaText);
 115:             Para.ParagraphElements = ParaE;
 116:             Text.Paragraphs.Add(Para);           
 117:             Text.Left = leftPoint;
 118:             Text.Top = topPoint;
 119:             Text.Height = height;
 120:             Text.Width = width;
 121:             Text.FontColor.Font.Size = fontSize;
 122:             Text.SectionName = PageHeadSection.Name;
 123:             _Report.ReportClientDocument.ReportDefController.ReportObjectController.Add(Text, PageHeadSection, -1);
 124:         }
 125:  
 126:         //리포트 파일을 돌려준다.
 127:         public CrystalDecisions.CrystalReports.Engine.ReportDocument getReport()
 128:         {
 129:             //리포트 파일을 돌려주기 전에 기본적인 선과 필드 타이틀을 모두 생성한다.
 130:             //제일상단 윗선
 131:             AddLine(GridMarginLeft, GridMarginTop, _GridColumnPoint[_GridColumnPoint.Count - 1], GridMarginTop, 15, "head");
 132:             //제목과 내용이 분리되는 중단선
 133:             AddLine(GridMarginLeft, PageHeadSection.Height, _GridColumnPoint[_GridColumnPoint.Count - 1], PageHeadSection.Height, 15, "head");
 134:             //세로선 셋팅
 135:             for (int i = 0; i < _GridColumnPoint.Count; i++)
 136:                 AddLine(_GridColumnPoint[i], GridMarginTop, _GridColumnPoint[i], PageHeadSection.Height, 15, "head");
 137:             //그리드 제목줄 글자 표시
 138:             for (int i = 0; i < _GridColumnPoint.Count - 1; i++)
 139:                 AddText(_GridColumnPoint[i], GridMarginTop + CellMarginTop, FontSize * FontToCrystal, _GridColumnPoint[i + 1] - _GridColumnPoint[i], FontSize, _HeadName[i]);
 140:             
 141:             //-------------------------------------------------
 142:             //detail 영역
 143:             //-------------------------------------------------
 144:             //세로선의 긋기
 145:             for (int i = 0; i < _GridColumnPoint.Count; i++)
 146:                 AddLine(_GridColumnPoint[i], 0, _GridColumnPoint[i], DetailSection.Height, 15, "detail");
 147:             
 148:             //컬럼의 셋팅
 149:             for (int i = 0; i < _GridColumnPoint.Count - 1; i++)
 150:                 AddField(_GridColumnPoint[i], 0 + CellMarginTop, FontSize * FontToCrystal, _GridColumnPoint[i + 1] - _GridColumnPoint[i], _FieldName[i]);
 151:             //값 표시후 그어지는 디테일영역의 마지막에 가로줄
 152:             AddLine(GridMarginLeft, DetailSection.Height, _GridColumnPoint[_GridColumnPoint.Count - 1], DetailSection.Height, 15, "detail");
 153:             return _Report;
 154:         }
 155:         /// <summary>
 156:         /// 실제적으로 외부로 열어놓을 함수
 157:         /// </summary>
 158:         /// <param name="HeadName">제목으로 표시될 문자 addtext를 호출해서 표기할것이다.</param>
 159:         /// <param name="FieldName">dataset과 연계되는 column명</param>
 160:         /// <param name="Width">넓이</param>
 161:         /// 
 162:         public void AddElement(string HeadName, string FieldName, int Width)
 163:         {
 164:             _GridColumnPoint.Add(_GridColumnPoint[_GridColumnPoint.Count-1] + SpreadSizeToCrystal * Width);
 165:             _HeadName.Add(HeadName);
 166:             _FieldName.Add(FieldName);
 167:         }
 168:     }

몇가지 기능을 빼고..

게다가 버그까지 하나 심어서.. 클래스를 적어본다.

버그의 해결 힌트는. 그 에러가 나는 줄을.. 어디로(?) 잘 이동하면.. 된다.

그냥.. 가져다가 사용하려고 하는 Copy & Paste족을 위한 하나의 배려다.

지금 클래스만으로도 잘 사용이 되겠지만.. 두어번쯤 사용하다보면.. 이상한.. 에러가 생길것이다.

그럴때 그 에러나는줄을 어디론가 잘 이동만 하면.. 그 에러가 사라질것이다.

일단.. 페이지 전체에 배치가 이쁘게 "배분"정렬형태로 도표가 나오게 하고 싶다면..GridColumnPoint값이 키 포인트다.

넣는 수치값을 잘 .. 배분이 되도록.. 계산해서 넣으면 된다. 옵션으로 해야겠지(?)

그러면.. 화면단에서 바로 배분형태와 그렇치 않은 형태를 번갈아 보면서 처리할수 있다.

clip_image001

clip_image002

자동배분에 따른 모습이다.

지금 소스에.. 딱.. 4줄? 추가하면된다. 옵션으로 이렇게 볼 수도 있고 저렇게 볼 수도 있다.

너무.. 맨입에 다 알면 재미없지 않은가?

이런건.. 쉽게 할 수 있어야. 그래도 프로그래머 이지 않을까.

---------------------------------

^^

using CrystalDecisions.CrystalReports.Engine;

using CrystalDecisions.ReportAppServer.ReportDefModel;

using CrystalDecisions.ReportAppServer.ClientDoc;

선언에 이걸 추가해야 하고

참조 추가로는..

clip_image003

대략 이렇게 된다.

문제는.. 클리스털리포트는.. 예전에도 그랬는데. 동적인 제어가 가능한것은 따로 패키지로 팔았다.

아마도 닷넷의 기본에 포함된것은 com 개체(?)형태로 제어하는 reportappserver라는게 없다고 판단된다.

정식으로 설치를 해야지만 될것이다.

'C# > 크리스털리포트' 카테고리의 다른 글

크리스털 리포트 3  (0) 2008.11.14
크리스털 리포트 2  (0) 2008.11.14
크리스털리포트 1  (0) 2008.11.14
posted by 삶의여유로움
:
C#/크리스털리포트 2008. 11. 14. 17:48

    지금 내가 적고 있는 이글은 아마도 누군가도 똑같은 생각을 했을것이라 믿는다.

    10년이 넘도록 아무도 이런생각을 하지 않았을리는 없을테고

    게다가 크리스털은 웹, 자바, 닷넷등등.. 아주 많은 부분에서 사용되어지고 있다.

    누군가 자바로 한번쯤 이렇게 만들어 줄 생각은 없을까?

    나 같은 사이비(?) 보다는 좀 더 매끄러운 코딩을 해줄분이 있었으면 좋겠다.

    -------------------

    기초 요구사항으로 돌아가서..

    요구사항에서 말하는것처럼 데이터 셋을 받으면 그것을 가지고

    알아서 저녀석들을 내부적으로 호출하여

    1. 데이타셋의 정보를 기반으로 자동으로 라인을 그어주고

    2. 데이타셋의 컬럼제목으로 또는 입력해주는 컬럼제목값으로 알아서 택스트형태로 제목을 달아줄것이며

    3. 또한 그 아래는 자동적으로 필드를 만들어 주기만 하면 된다.

    순서까지 해주는것이 당연하겠지만.. 앞서 스프레드에서 넘겨주는 단계의 강좌를 뛰어 넘는덕에 그부분은 다음기회(?)에 해주겠다. 참고삼아 이야기 하자면.. Dataset에 sort를 이용해서 처리한다.

    MS에서 친절(?)하게도 만들어 두었다. Msdn을 잘 뒤져보길 바란다.

    (하지만 지금 적는 이 강좌에서는 DB처리와 앞쪽강좌가 사라진 입장이여서 add매서드를 호출하는 순서로 처리될것이다. 뭐 똑같은 말이다.)

    하여간.. 앞강의에 적은 스프레드의 테이블을 잘 보면 지금예제를 위한 값들을 현재의 코딩처럼 적을필요가 없다는것을 알것이다. 즉.. 이것마져도 DB에 값들로 자동으로 매핑이 처리되어 출력이 될것이다.

    우리가 스프레드화면과 출력물까지도 소스수정없이 DB데이타만으로 순서와 필요한 필드를 조정할수 있다는 이야기가 된다.

    단지 지금은.. 그냥 예제이니 잘 참고해서 유용한 클래스를 만들어 많은 공유가 되길 바란다.

    일단은.. 결과물 부터 보자..

    그래야 혹(?)해서 공부를 할게 아닌가..

    코딩보다 어려운게 예제 만들기라고 누가 그랬던가 ㅠ.ㅠ.

    clip_image001

    clip_image002

    두개의 차이점을 느낄수 있을런지 모르겠다.

    사실.. 당연히 되어야 되는것을 구현하기 위해 코딩을 한다는것 자체가 좀 한스럽기도 하다.

    위의것은 내가 아무렇게나 만든 데이타셋을 그냥 넘긴것이다.

    하나는

    ReportClass.AddElement("연습1", "ColName", 100);

    ReportClass.AddElement("아하", "Size", 140);

    ReportClass.AddElement("된다는거 아니겠니", "CellType", 150);

    ReportClass.AddElement("신기하니?", "CellTypeINIT", 100);

    이렇게

    또 하나는..

    ReportClass.AddElement("연습1", "HeadName", 80);

    ReportClass.AddElement("연습1", "ColName", 140);

    ReportClass.AddElement("된다는거 아니겠니", "CellType", 100);

    ReportClass.AddElement("아하", "Size", 40);

    ReportClass.AddElement("신기하니?", "CellTypeINIT", 10);

    이렇게 말이다.

    헤드네임과.. 뒷족에 적은 넓이에 따라서.. 그리드(?) 넓이가 조정됨을 보라..

    뭐 이건 예제를 위한것이니.. 종이의 100%에 맞도록 자동변환하는 루틴은 아직 첨부하지 않았다.

    이런 클래스 하나만 만들어 둬도 사실상 손이가는일들을 굉장히 많이 줄일수 있다.

    게다가 앞에서 이야기한 테이블이 DB에 구현되어 있으면.. 화면단의 스프레드와 동시에 출력물의 속성을 원하는 형태로 변경이 가능하니 코딩의 스피드가 살아난다.

    (아님말고지 뭐.~~)

    앞 2강에서.. 필드의 셋팅을 빼고 넘어왔다.

    필드의 경우를.. 생각해 보자. 일단은 DB접속이 이루어 진다면 그것은 예전의 고행스러운 크리스털 리포트가 되는것 밖에 없다.

    그럼 XSD를 통한 구조를 만들어 두고 이용하는 방법이 있겠다.

    이건 여러모로 유용하다. 하지만.. 지금 같은 경우는 그리 좋아보이진 않는다.

    왜냐면..우리가 만든 스프레드의 내용을 다시금 정의된 형태로 변화시켜줘야 할테니까 말이다.

    뭐 굳이 나쁘진 않다.

    하여간.. 데이타셋을 이용하는것이 가장 좋은방법인데 이걸 디비접속으로 구할것이냐 아님 구조를 정해둔 상태에서 데이타셋을 넘길것이냐

    아님.. 마지막으로 테이타셋에서 구조를 추출해서 기본형태를 만들고 내가 원하는 필드를 배치할것이냐이다.

    ? 맞나? … 하여간.. 그 3번째 방법과 유사한 방법인것을 시도해 보기로 하자.

    크리스털의 가장 고욕스러운게 DB처리가 아닐까?

    하여간.. 그 DB에 접근도 안하고 출력이 된다는건 매력적이다..

    CrystalDecisions.ReportAppServer.DataSetConversion.DataSetConverter.Convert(_DataSource);

    이런.. 매서드가 이미 구현이 되어 있기 때문일것이다.

    즉.. 우리는 그냥.. 데이타셋만 떤지면 될것같다.

    기본적으로 크리스털리포트에서 각종필드를 화면단(?)에 배치하려고 하면 먼저 그 구조가 정해져 있어야 한다.

    그러니 AddField란 함수를 열심히 만들어서 사용해 본들 에러만 날 것이다.

    그래서 일단은.. dataSet을 받도록.. 먼저 일을 해야한다.

    //데이타 소스 프러퍼티

    public DataSet DataSource

    {

    get { return _DataSource; }

    set

    {

    _DataSource = value;

    dataTableName =_DataSource.Tables[0].TableName;

    IDS = CrystalDecisions.ReportAppServer.DataSetConversion.DataSetConverter.Convert(_DataSource);

    _Report.ReportClientDocument.DatabaseController.AddDataSource(IDS);

    crTable = _Report.ReportClientDocument.Database.Tables[0];

    _Report.SetDataSource(_DataSource);

    }

    }

    대략 이런 형태라고 할까?

    물론 선언도 되어 있어야 한다.

    CrystalDecisions.ReportAppServer.DataDefModel.ISCRDataSet IDS;

    CrystalDecisions.ReportAppServer.DataDefModel.ISCRTable crTable;

    CrystalDecisions.ReportAppServer.DataDefModel.ISCRField crField;

    그럼 데이타셋을 받았다.

    이제는.. 필드를.. 배열만 하면 될것이리리라..

    //필드를 추가한다.

    public void AddField(int leftPoint,int size, string fieldName)

    {

    CrystalDecisions.ReportAppServer.ReportDefModel.FieldObject Field = new CrystalDecisions.ReportAppServer.ReportDefModel.FieldObject();

    Field.Left = leftPoint;

    Field.Top = 0;

    Field.Height = 500;

    Field.Width = size * 20;

    Field.SectionName = DetailStartSection.Name;

    Field.FieldValueType = CrystalDecisions.ReportAppServer.DataDefModel.CrFieldValueTypeEnum.crFieldValueTypeStringField;

    Field.DataSourceName = "{" + dataTableName + "." + fieldName + "}";

    _Report.ReportClientDocument.ReportDefController.ReportObjectController.Add(Field, DetailStartSection, 1);

    }

    ps)

    그런데 별로 호응이 없는것 같다.

    아무래도 이런글은 크리스털리포트 마을로 가서 적어야 하는것이였나?

    원본 위치 <http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNO=8&no=1572&page=2>

'C# > 크리스털리포트' 카테고리의 다른 글

크리스털 리포트 4  (0) 2008.11.14
크리스털 리포트 2  (0) 2008.11.14
크리스털리포트 1  (0) 2008.11.14
posted by 삶의여유로움
:
C#/크리스털리포트 2008. 11. 14. 17:47

    몇달전에 크리스털 리포트를 가르친적이 있었다.

    아니 가르쳤다기 보다는 그냥 이렇게 이렇게 하면 더 빨리 작업이 될것이라고 말해준적이 있었다.

    돌아온것은? 무엇이었을까?

    "그냥 할래요"

    "선을 그냥 긋는게 더 편한데요"

    "왜 이렇게 해야되요?"

    등등의 말이였다.

    그렇다 절망스럽다.

    스프레드의 DB셋팅기법도 아마도 기것해서 적어줘봐야 저정도 말만 돌아오지 않을까 싶다.

    세상을 사는건 다양한 방식이 있듯이 코딩도 그리고 결과물을 도출하는것도

    당연히 다양한 형태가 있는것이다.

    내가 지금 적는것이 옳다라고 이야기 하진 않는다.

    그리고 당신이 하는 방식처럼 그냥 선을 긋는것이 더 빠를것일수도 있다. 아니 더 빠를것이다.

    하지만.. 언젠가는 알것이라고 믿어본다. 물론 경험상 끝까지 알려고도 안하긴 하더라만..

    코딩을 재미로 하는게 아니라 직업으로 단지 그냥 선긋기위해서 회사를 다니면..

    뭘 하겠는건지 라고 혼자서 한탄해본다.

    자 일단 기초는 선을 긋는것이다.

    뭐하자는 겜인지 모르겠다만.. 선긋는거 그냥.. 마우스 한번 움직이면 된다.

    지금 선을 긋기 위해서 우리는 아주 고난(?)의 코딩을 할것이다. 당최 알아듯지 못할말을 하면서 말이다.

    왜냐면.. 선긋기가 기초이니까 말이다.

    선을 긋는방식은 아주 기초적인 입장에서 인터페이스 또는 추상클래스격인 형태로 제작된것을 이용해서 선을 긋는다. 왜냐면 우리가 만든 리포트파일은 이미 섹션이 다섯개로 정의되어 있지만 실제적으로 코딩하는것은 몇개짜리가 올지 누가 알것인가? 그러니 Adapter패턴격인 형태로 작성을 해줘야 되지 않을까? 뭐 내가 그렇게 한다는것이 아니고 이미 그렇게 만들어져 있다.

    나름대로 크리스털 리포트의 클래스를 설계한 사람이 잘했다고 생각한다.

    물론 10년이 넘은 컨포넌트이다 보니 워낙 지저분하게 각종 뭣들이 많아서 당최 뭐가 뭔지 모르겠다만..

    자.. 모르겠는 소리는 그만하고 선하나 그어보자.

    일단은 선의 개체가 있어야 하겠다.

    그런다음.. 그 개체를 리포트에 대입해 주면 된다.

    이걸 단순히 클래스로 만든다고 생각해보자.

    일단.. 생성자를 통해서 리포트 파일을 넘겨주고

    매서드-선생성

    리포트파일에 대입

    그리고 나서 리포트파일 돌려받음

    화면에 뿌려줌

    즉 클래스는 오로지 선만 만들어서 넣어주는 수준이 될것이다.

    자 호출은

    자동리포트 AR = new 자동리포트();

    AutoReport AddLineClass = new AutoReport(AR);

    AR.SetParameterValue("제목", "안녕하세요");

    AR.SetParameterValue("작업자", "왕자병");

    AR.SetParameterValue("기간", DateTime.Now.ToString("yyyyMMdd") + "~" + DateTime.Now.AddDays(3).ToString("yyyyMMdd"));

    AR.SetParameterValue("출력일", DateTime.Now.ToString());

    crystalReportViewer1.ReportSource = AddLineClass.getReport();

    앞에 코드에 비해서 이렇게 라인을 더하는 클래스를 통해서 다시 보여주도록

    바꾸었다.

    클래스의 설계는

    public class AutoReport

    {

    int StartPoint = 0;

    ReportDocument _Report;

    public AutoReport(ReportDocument Report)

    {

    _Report = Report;

    StartPoint = 0;

    }

    //선을 추가한다.

    public void AddLine()

    {

    }

    //리포트 파일을 돌려준다.

    public ReportDocument getReport()

    {

    return _Report;

    }

    }

    이런모습이 될것이다.

    자.. 아직도 선긋기에 접근도 못하다니 정말.. 난감하다.

    그냥.. 마우스로 찍 긋고 말것을 왜 이짓을 하는건지.

    인터넷에 떠 도는 소스중 하나의 방식으로 일단 진행을 해보자.

    일단은.. 우리는 선긋기 연습을 해야한다.

    clip_image001

    앞 소스에서.. 이렇게 단순히 addline에.. 수치를 넣는것으로 하자.

    그러면..

    clip_image002

    이렇게 선이 그어지게 될것이다. 물론.. 옵션은.. 알아서 설정해야겠지만.

    지금은.. 단순하게 처리를 하자.

    그럼.. 어떻게 선긋이 클래스가 변했는지 좀 더 살펴보자.

    public class AutoReport

    {

    int StartPoint = 0;

    CrystalDecisions.CrystalReports.Engine.ReportDocument _Report;

    ISCDReportClientDocument IReport;

    CrystalDecisions.ReportAppServer.ReportDefModel.Section StartSection;

    CrystalDecisions.ReportAppServer.ReportDefModel.Section EndSection;

    public AutoReport(CrystalDecisions.CrystalReports.Engine.ReportDocument Report)

    {

    _Report = Report;

    //------------------------------

    StartPoint = 0;

    IReport = _Report.ReportClientDocument;

    StartSection = IReport.ReportDefController.ReportDefinition.DetailArea.Sections[0];

    EndSection = IReport.ReportDefController.ReportDefinition.DetailArea.Sections[0];

    }

    //선을 추가한다.

    public void AddLineV(int leftPoint)

    {

    CrystalDecisions.ReportAppServer.ReportDefModel.LineObject Line = new CrystalDecisions.ReportAppServer.ReportDefModel.LineObject();

    Line.Left = leftPoint;

    Line.Top = 0;

    Line.Right = leftPoint;

    Line.Bottom = 1000;

    Line.LineThickness = 20;

    Line.LineStyle = CrystalDecisions.ReportAppServer.ReportDefModel.CrLineStyleEnum.crLineStyleSingle;

    Line.EnableExtendToBottomOfSection = false;

    Line.SectionName = StartSection.Name;

    Line.EndSectionName = EndSection.Name;

    _Report.ReportClientDocument.ReportDefController.ReportObjectController.Add(Line, StartSection, -1);

    }

    //리포트 파일을 돌려준다.

    public CrystalDecisions.CrystalReports.Engine.ReportDocument getReport()

    {

    return _Report;

    }

    어라라 생각외로 많이 변한것 같다.

    뭐가 이리 복잡한것인지 말이다.

    매우 개인적 생각으로 크리스털 리포트의 클래스들은 매우 중구난방이다.

    업그레드가 꾸준히 이어지면서 여러가지 기능이 추가되었기 때문이기도 하겠지만

    사용자 입장에서 사용하는측면에서는 여간 힘든게 아니다.

    게다가 매뉴얼까지 제대로(?) 되어있지도 않아서 피곤함이 몰려온다.

    또한 심각한 버그까지 있어서 잘~~~ 피해서 사용해야 한다.

    하지만 구조적인 설계는 괜찮게 된게 아닌가 싶기도 하다.

    여하튼 그것은 그것이고.. 지금의 형태에 대해서 계속 이야기를 나아가 보자.

    우리의 리포트를 제어하기 위해서 interface형 Crystal Document를 생성하고 거기에 섹션과 interface형태의 라인을 만들어서 그것을 결국 실제의 리포터에 Controller를 이용해서 대입을 시킨다.

    이것이 위의 소스의 전부라고 볼 수 있다.

    위의 소스에서 보듯이 절대적으로(?) 이미 생성되어 있는 자동리포트.rpt파일에 대한것은 어디에도 없다.

    즉 위의 소스자체는 어떤 리포트 파일을 넘겨도 선을 그을수 있다는 이야기다.

    다른형태로 이야기 하면 만약 우리가 모든 리포트에 테투리 라인을 그어야 된다고 생각해보자.

    (또는 모든 리포트에 이미지를 변경한다거나 등등)

    그럴때는 어떻게 해야할것인가?

    위와 같은 형태라면 우리는 단순한게 현재의 출력모듈을 단지 테투리긋기 클래스를 통해서 다시금 출력을 해주는 소스로 두어줄 변경만 하면 된다.

    자.. 여하튼 여기까지는 왔다.

    가로선은 알아서 긋고도 남으리라 생각된다 못하겠다면

    그냥 포기하면 된다 뭐 어렵나?.. 포기도 가끔은 하나의 방법이다. 여러분에게는 좀 더 쉬운 그저 마우스로 가져다 긋기만 하면 되는게 있지 않은가?

    자 이제는 뭘해야하나.

    필드를 추가해야 되는것이다.

    그리고 또 하나는 뭘까?.. 택스트도 추가해야 될것같다.

    추가하는 방식에 있어서 글자개체를 문장개체에 넣어 문장으로 해서 대입하는것이 생소하게만 느껴질것이다. 잘 모르겠다면 그냥 가져다 사용하자.

    //택스트를 추가한다.

    public void AddText(int leftPoint, int topPoint, string sText)

    {

    CrystalDecisions.ReportAppServer.ReportDefModel.TextObject Text = new CrystalDecisions.ReportAppServer.ReportDefModel.TextObject();

    CrystalDecisions.ReportAppServer.ReportDefModel.Paragraph Para = new CrystalDecisions.ReportAppServer.ReportDefModel.Paragraph();

    CrystalDecisions.ReportAppServer.ReportDefModel.ParagraphElements ParaE = new CrystalDecisions.ReportAppServer.ReportDefModel.ParagraphElements();

    CrystalDecisions.ReportAppServer.ReportDefModel.ParagraphTextElement ParaText = new CrystalDecisions.ReportAppServer.ReportDefModel.ParagraphTextElement();

    ParaText.Text = sText;

    ParaE.Add(ParaText);

    Para.ParagraphElements = ParaE;

    Text.Paragraphs.Add(Para);

    Text.Left = leftPoint;

    Text.Top = topPoint;

    Text.Height = 500;

    Text.Width = sText.Length * 500;

    Text.SectionName = StartSection.Name;

    _Report.ReportClientDocument.ReportDefController.ReportObjectController.Add(Text, StartSection, -1);

    }

    하여간.. 되는게 중요하지 않겠는가?..

    그럼 이제 마지막인.. 필드만 구현을 하면 우리가 원하는건 다 되는듯 싶다.

    원본 위치 <http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNO=8&no=1571&page=2>

'C# > 크리스털리포트' 카테고리의 다른 글

크리스털 리포트 4  (0) 2008.11.14
크리스털 리포트 3  (0) 2008.11.14
크리스털리포트 1  (0) 2008.11.14
posted by 삶의여유로움
:
C#/크리스털리포트 2008. 11. 14. 17:46

    이 이야기는 원래 아래에 적은 스프레드의 연장선에 있어야 되는 강의에 속한다.

    스프레드를 아래와 같은 기법으로 DB에서 처리를 하면 상당히 유용하다.

    그 데이터 테이블중에 뒤쪽에 있는부분을 어떻게 활용하게 될것인가에 대해서 설명이 될것이다. 일반적으로 우리는 화면단의 출력으로 스프레드를 이용하고 프린터용의 출력물로 크리스털리포트를 이용해야 되는것이 아주 다반사다. 왜 그런가?

    대부분의 클라이언트는 출력물을 요구하고 한페이지에 나타난 스프레드의 데이터를

    엑셀로 뽑아주는것과 프린터물로 출력해주는것은 피할수 없는 과제이다.

    물론 스프레드 자체의 출력물로 그냥 해주면 되는데 유저란 어찌 그리도 요구사항이 많은지 말이다. 결국 로고도 넣어주고 하는 삽질을 위해서는 크리스털로 돌아오게 만든다.

    일반적으로 하나의 프로젝트 단위에 출력물은.. 거의 수백가지 수준이고

    그중에 대략 30~50%는 그냥 그대로 출력만 해주기만 하면 된다.

    그 대충 해주기만 하면 되는것을 무지하게도 새로운 리포트 파일을 만들고 심지어 끔찍하게도 연동을 위한 데이타셋을 만들지를 않나.

    또한 게다가 각 뷰어까지 새로 만들어서 그 뷰어에다가 DB연결까지 새로 하고 있다.

    이런 이야기가 "설마" 라는 측과 "당연히 그래야 되지 않냐?" 라는 사람으로 엇갈릴것인데 최근에 내가 잠시 몸담았던 프로젝트에서 한 파트에 속하는 부분의 리포트 파일이 대략 40여개이고 RPT 파일또한 40여개이며 뷰어또한 무작스럽게 폼으로 생성해서 10개의 뷰어 폼이 존재하고 게다가 XSD파일까지 생성해서 ado를 연결해 둔게 있다.

    전체 프로젝트라면.. 대략.. 500개의 리포트파일이 존재하지 않을까 하고 어림 추측해 본다.

    (내가 과장된 이야기를 하는것이 아니라는것을 누군가는 알고 있으리라.)

    그렇다고 무조건 하나의 리포트로 모든걸 대처할수는 없다. 단지.. 50%정도는 모두 하나로 통합이 된다는 이야기를 하고 싶은것이다.

    clip_image001

    자. 기본적으로 크리스털 리포트를 이용해서 만들면 위와같은 형태가 가장 일반적이다.

    게다가 지금 하려고 하는 이야기는 엑셀같은 Sheet / 컴포넌트의 스프레드쉬트의 데이터를 바로 dataset으로 만들어서 넘겨주고 이것을 크리스털에서 알아서 처리해서

    제목과 내용을 표시하게 해주는것이다.

    참 별거아닌 스프래드 자체의 프린터루틴을 사용하면 그냥 두어줄 적으면 되는(물론 함수는 하나 만들어둬야겠지만) 마치 문제도 아닌것이 크리스털을 사용해야 함으로써 머리아파지는 이야기다.

    자. 우리가 앞서 데이타셋을 설계했듯이 그것을 변환하는 함수가 있을것이다.

    하지만 지금은 중간강의(?)가 사라졌으니 그것도 넘어가도록 하고

    핵심적으로 3가지 HeadName과 FieldName그리고 넓이의 값을 넘겨주면 알아서 되도록 하고 싶다.

    Image도 ReportObjectController.ImportPicture 를 가지고 넣는것 보다는 생각없이 넘어가도록 하자.. 이렇게 이미지를 넣어야 될 경우는 상용프로그램에서 각 회사들의 이미지를 외부에서 불러와야 되는 경우 이외에는 없다고 봐도 될것이다. 지금은.. 그냥 예제니 넘어가도록 하자.

    제목과 특정값(?) 몇 개는 그냥 파라미터로 넘기도록 하자.

    이야기가 너무 길어지면 재미 없지 않은가? 책도 아닌데 말이다.

    자..

    1. 요구사항 분석

    HeadName / FieldName / 넓이 / 순서 (……. 등등)

    를 넣고나서.. Dataset을 넘기면.. 알아서 나오면 좋겠어요.

    2. 기초설계?

    일단은.. 보아하니 클래스가 아니면 안되겠다.

    값이 대부분 여러 개로 오니 컬랙션으로 받거나 add매서드를 이용해서 하나씩 넣어주도록 하고 그것의 개수를 통해서 Loop를 돌리도록 처리하자.

    마지막으로 dataset은 프로퍼티로 받는형태를 고려하자..

    3. db설계.? 생략

    4. Test

    기본적..db는 테스트를 위한 dataset으로 대충 두어개 만들도록 하자.

    아님 그냥 스프레드걸 가져다가.. 출력하자.

    설마 나에게 DB연결까지 시키진 않으리라 믿는다.(할줄 모른다. -_-;;)

    -------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------

    이 아무것도 아닌것이 왜 이리도 적을게 많은가? 그러게 말이다.

    자 일단은.. 기초 리포트 파일을 만들어 보자.

    clip_image002

    참 주는것도 없는데 데브피아 로고까지 넣어주고.. 나중에 광고비는 줄라나 모르겠다.

    매개 변수는

    clip_image003

    이렇게 만들어 주도록 하자.

    기초바탕은 되었겠다. 그럼 이제 솔류션을 시작하고 작업을 해보자.

    아차차.. 솔류션을 먼저 만들었어야 했나? ^^ 뭐 아무러면 어떤가 알아서 잘 하리라 믿는다.

    clip_image004

    여기다가 클래스 파일을 하나 추가하도록 하자. 왜냐면 이것은 독립적으로 사용하기 위해서 이다. 여기 프로젝트에만 사용할것도 아니고 다른곳에 누누히 계속 사용해야 되지 않겠는가? 그러니 새로 하나 추가하자.

    Form1은 대충

    clip_image005

    이렇게 생성을 하고

    public partial class Form1 : Form

    {

    public Form1()

    {

    InitializeComponent();

    }

    private void Form1_Load(object sender, EventArgs e)

    {

    crystalReportViewer1.DisplayGroupTree = false; //그룹트리 보이지 않게

    자동리포트 AR = new 자동리포트();

    AR.SetParameterValue("제목", "안녕하세요");

    AR.SetParameterValue("작업자", "왕자병");

    AR.SetParameterValue("기간", DateTime.Now.ToString("yyyyMMdd") + "~" + DateTime.Now.AddDays(3).ToString("yyyyMMdd"));

    AR.SetParameterValue("출력일", DateTime.Now.ToString());

    crystalReportViewer1.ReportSource = AR;

    }

    }

    이정도 코딩을 해두자.

    그러면

    clip_image006

    요렇게.. 리포트가 나올것이다.

    자.. 이제 우리가 할것은 저 중간에.. 이쁘장하게 데이터 셋의 내용이 줄이 그어지면서

    나오는것이다.

    데이터 컬럼이.. 3개이던.. 10개이던지 말이다 그리고 레코드수가 알아서..~~

    과연 그게 가능할까?

    누구는 하루에 그거 대충.. 3~4개 만들고 하루를 보내는데 우리는 이제부터

    하루에 20개(?)를 하는척 하고 하루종일 놀아도 똑같은 결과물이 완성될 가능성이 있는것이다. 기쁘지 않는가?

    원본 위치 <http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNO=8&no=1570&page=2>

'C# > 크리스털리포트' 카테고리의 다른 글

크리스털 리포트 4  (0) 2008.11.14
크리스털 리포트 3  (0) 2008.11.14
크리스털 리포트 2  (0) 2008.11.14
posted by 삶의여유로움
:
C#/DB를 이용한 Grid 셋팅 2008. 11. 14. 14:31

http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=17&MAEULNO=8&no=100201&ref=100201&page=1

이곳은 블러그다.

불펌은 당연히 금지고..

욕설이 난무해도 괜찮다는거 왜냐면.. 개인 블러그니까.

보기 싫으면.. 안보면 되는거 아닌가? 이곳은 공공장소가 아닌것이다.

내가 만약 데브에 글을 적으면서도 이따구로 적는다면.. 그건 별로이긴 하다.. 많은 사람이 왔다갔다가 할테니

그곳에서 추태를 보이는것은 그렇찮은가?

만약 글의 링크한 사람이 본다면.. 그건 좀 글타.. / 그래도 어쩌겠는가..

뒤에서는 대통령도 욕한다고 하지 않는가?

(그리고 정말 링크글의 저자에게는 아무런 억하심정도 없다.. 이건 정말 확실하다. –_-;;)

저글을 딱.. 읽다가. 이런생각을 했다.

가르쳐 줬잖아.. 젠장..

 

this place is Blog, that’s mean , you don’t care about my note because this place is just my territory

if you don’t want this style note then go out~~ / not public place just my domain

maybe i say this Way.. but oh.. i didn’t..

 

그러나 말이다. 어이쿠 안가르쳐준거였다.

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNo=8&no=1559&ref=1559

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNo=8&no=1560&ref=1560

이 강좌를 적으면서 다 가르쳐 준줄 알았는데..

이거보다가 데브이자식을 내 강좌를 삭제했나 하고 울분을 부르짓다가 잘 생각해보니.. 그때 적어만 두고 올리진 않았나 보더라.

에이띠발..!!! 이런젠장..!!!

 

물론 나도 해본적이 없다.

 

저런건 말하자면 애들 놀이터에 모래날리기 수준이 아닌가. 그냥 놀이터까지 가기가 귀찮을뿐이지.. 모래야.. 발로 한번 툭하고 차면 되는것인데 뭐가 문제인가

젠장할 말이다. 그래서 지금부터 저걸 해보도록 하자.

그런데 정말 놀이터까지 가야된다는 사실은 짜증이 만땅이다.

 

long times ago i worte a little article, maybe DevPia Site delete my article?.. oh so bad guy

but i miss about how to include combobox in datagrid

and then i think about the man who is so stupid, don’t to this?.. this is very easy

ha.. ha.. but me too , i never do that but i can,,,,

the reason why i think that so….easy that do it

just say . It’s a piece of cake

but making cake need a lot of time…

ok.. now.. i will show you~!!!!

 

-------------------------------------------------------

 

헉 나름.. 답변용 클래스를 만들고 있는데

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=17&MAEULNO=8&no=100243&ref=100243&page=1

 

답이올라왔다. 흐흐..

 

열시 발이 빨라야 해..

 

ps) 그런데 왜 데브는 트랙백 기능이 없냐.. 꾸지네

'C# > DB를 이용한 Grid 셋팅' 카테고리의 다른 글

Spread Setting 2  (0) 2008.11.14
Spread Setting 1  (0) 2008.11.14
posted by 삶의여유로움
:
C#/DB를 이용한 Grid 셋팅 2008. 11. 14. 14:30

    뭔말인지도 모르는 두번째 이야기를 적어보자.

    개발론에서 항상이야기 하듯이

    1.은 사용자의 요구분석이 아니겠는가..

    자 그럼.. 2의. 설계단계로 들어가 보자.

    결국 1의 요구에 따라서 DB를 접근하지 않을수 없게 되었는데

    여기서 또 하나의 문제는 Spread를 잘 사용하지 못하는 중간 관리자에게 있다.

    이 관리자들이 뭔가 수정을 해줘야 하는데 잘 못한다는것이고.

    살다보면.. 이리 저리 꽉 맞추어진 형태의 코딩에서 조금만 수정을 가하면 오류가 우루루 떨어지는게 대부분이니

    누구 말처럼 코딩자체를 루~~~~~즈하게.. 연결해줘야 하는것들이 많아진다.

    뭐.. 이건 코딩강좌란이 아니고 낙서장에 가까워 질려고 한다.

    일단.. 대충.. DB컬럼을.. 적어보자.

    생각없이 적는거니.. 읽는이의 능력에 따라서 알아서 처리하기 바란다.

    /// 이 클래스는 귀찮게 스프레드를 셋팅하는 단점을 극복하기 위해서 제작한다.

    /// 기본적으로 DB에 값을 넣는 입력폼이 필요하게 되고(CRUD형태)

    /// 그것을 불러오는 로직이 정의되어 있을때 올바르게 작동할것이다.

    ///

    /// DB의 필드는

    /// UserID //사용자 아이디 기본적으로 Default형태로 넣어야한다.

    /// SpdID //스프레드 아이디 사용하고자 하는 폼의 명칭이나 고유명칭을 넣어줘야 한다. 예를 들어서 KSM_1

    /// HeadName //실제적으로 표현될 한글명칭을 의미한다.

    /// ColName //DB와 매핑될 이름을 의미한다. 공란이라면 Nothing+숫자로 처리하게 될것이다.

    /// ColSize // Size

    /// CellType Button, Text,Combo,Mask등등 잘 정의해야 한다.

    /// CellTypeINIT //셀타입의 초기화 처리이다.

    /// 예를 들어서 마스크라면 ###-### combo라면 "일,이,삼" 형태로 등등으로 처리한다.

    /// CellAlignH 가로정렬  Left, Right, Center

    /// CellAlignV 세로정렬  Top, Bottom, Center

                /// ColSort // 스프레드에 표현될 컬럼에 소트 속성을 줄것인가 정의함

    /// ColLock // 컬럼락을 걸어둘것인하는 속성

    /// ColBackColor 백 컬러

    /// ColForeColor 폰트의 컬러

    /// ColHidden 컬럼 숨김 속성

                /// DToutputSEQ   테이타 테이블로 정보를 빼낼때 예를 들어서 프린터를 위한경우

                ///               그 순서를 정의해 두면 순서대로 제작한다. 0 이라면 만들지 않도록 하자

    /// Sort 전체가 나오는 순서를 정의한다. 이것은 SP나 쿼리에서 이녀석을 기준으로 주는형태로 하기 위해서 이다.

                /// .

    /// .

    /// 추가적인 옵션으로 스프레드에 적용될 속성은 HeadName 의 값을 "Setting"으로 넣고 ColName에 값을 사용할것으로 넣는다.

    /// Cell순서 변경가능여부 / OperationMode사용 형태 / Merge 가로 / Merge 세로 /

    ///

    자... 대충.. 몇가지는 자삭(?)을 처리하면서.. 올려둔다.

    강호에서 살아남자고 하자면.. 서푼의 실력은 숨겨야 된다고 무협지가 말씀을 하셔서..

    뭐.. 드러난 실력이 없다보니 숨길것도 없긴 하지만..

    하여간.. 몇가지 필드가 더 필요하긴 하다만.. OP1이라든지.. 등등.. 이 글에서는 적당히 하도록 하자.

    더욱이 위에 적은것들은.. 대부분.. 프로젝트에서 굳이 신경쓰지 않아도 되는것까지 있어서

    알아서 만들기 바란다.

    자.. 하여간.. 저렇게 뭔가 테이블을 생성했다면.

    그 테이블에서 이제 정보를 select해오고 예를 들어서 SP의 TAG속성에 적어주거나 이름으로 해서 DB에서 값을 가져온다고

    보자.

    이것참.. 이렇게 딱딱하게 적어주면.. 아마도 이해가 안될테니..

    그렇다고  DB 에 연결하는것 까지 이 강좌에 적을수도 없고말이다.

    그래서 대부분의  DB연결후 우리가 얻는 DataTABLE이나 DataSET을 가지니.. 이걸 임의로 만들어서 설명을 해보자.

    -----------------------------------------------------------

    DataTable DT = new DataTable();

    int cnt = 0;

    DT.Columns.Add("HeadName", typeof(string));

                DT.Columns.Add("ColName", typeof(string));

    DT.Columns.Add("Size", typeof(string));

    DT.Columns.Add("CellType", typeof(string));

    DT.Columns.Add("CellTypeINIT", typeof(string));

    DT.Columns.Add("CellAlignH", typeof(string));

    DT.Columns.Add("CellAlignV", typeof(string));

    DT.Rows.Add(DT.NewRow());

    DT.Rows[cnt]["HeadName"] = "우리나라";

    DT.Rows[cnt]["ColName"] = "AAAAAAAAAA";

                DT.Rows[cnt]["Size"] = "80";

    DT.Rows[cnt]["CellType"] = "MASK";

    DT.Rows[cnt]["CellTypeINIT"] = "###-###";

                DT.Rows[cnt]["CellAlignH"] = "Left";

    DT.Rows[cnt]["CellAlignV"] = "TOP";

    cnt++;

    DT.Rows.Add(DT.NewRow());

                DT.Rows[cnt]["HeadName"] = "대한민국";

    DT.Rows[cnt]["ColName"] = "BBBBBBBBB";

    DT.Rows[cnt]["Size"] = "100";

                DT.Rows[cnt]["CellType"] = "MASK";

    DT.Rows[cnt]["CellTypeINIT"] = "###-###";

    DT.Rows[cnt]["CellAlignH"] = "Left";

                DT.Rows[cnt]["CellAlignV"] = "TOP";

    ---------------------------------------------------

    DB  접근했다고 머리속에서 상상을 한뒤에 상단의 코드를 실행하면.. DT가 나오게 될것이다.

    (너무한가?)

    뭐 예제까지 깔끔하게 코딩을 작성해 주기에는 너무 힘들다.

    자..얼렁 끝내야지 안되겠는가?

    일단 코드는.. 뭐 볼게 없다.

    생성자로.. 받던지.. 프로퍼티로 받던지 맴버로 하던지 맘대로 하고

    class SpreadSetting

    {

    #region 생성자

    FpSpread _spd = null;

    DataTable _DT = null;

    int _num = 0;

    int _SheetNum = 0; //스프레드의 쉬트 번호를 의미한다. 일반적으로.. 첫 쉬트이니 0이다.

    public Dictionary<string, int> ColName = new Dictionary<string, int>();

    public SpreadSetting(FpSpread spd, DataTable DT) : this(DT, spd) //생성자

    {

    }

    public SpreadSetting(DataTable DT , FpSpread spd)

            {

    _spd = spd; //스프레드 셋팅

    _DT = DT;

                _spd.Sheets[_SheetNum].AutoGenerateColumns = false; //자동 컬럼맵핑 off

    }

    }

    일단은.. 생성자로 받도록 코딩을 했다.

    자 그럼 호출하는쪽에서 보자.

    호출이 뭐 별거 있겠나.

    SpreadSetting test = new SpreadSetting(DT, this.fpSpread1);

    이정도면 될것이다.

    자 그럼 우리가 만든 클래스에 위에서 설정한 DT또는 DB에서 읽어온 DT가 셋팅이 되는것이고 그것을 가지고

    스프레스드가 셋팅이 되어야 한다.

    셋팅만 하고 말아야 하겠는가? 뭐.. 생성자에 실행을 둬도 되겠지만

    가끔은 전역변수로 상단의 클래스를 선언하고 쓸일이 있으므로 실행과 지정을 따로 해주도록 하자.

    그래서 실행하는 매서드를 하나 만들어야겠는데.. 그럼? 뭐로 할까.. RUN 정도로 하자.

    private void Run()

    {

    foreach (DataRow DR in _DT.Rows)

    {

    if (DR["HeadName"].ToString() == string.Empty) DR["HeadName"] = "이름없음" + _num.ToString().PadLeft(2, '0');

    if (DR["ColName"].ToString() == string.Empty) DR["ColName"] = "ColName" + _num.ToString().PadLeft(2,'0');

                    //외부에서 이름단위로 찾을때 사용하기 위해서 이다.대문자로 변환시킨다.

                    ColName[DR["HeadName"].ToString().ToUpper()] = _num;

                    ColName[DR["ColName"].ToString().ToUpper()] = _num;

    //-----------------------

    _spd.Sheets[_SheetNum].ColumnHeader.Cells[0, _num].Text = DR["HeadName"].ToString();

                    _spd.Sheets[_SheetNum].Columns[_num].DataField = DR["ColName"].ToString();

                    _spd.Sheets[_SheetNum].Columns[_num].Width = Convert.ToInt32( DR["size"].ToString() );

    switch (DR["CellAlignH"].ToString().ToUpper())

                    {

    case "LEFT":

                            _spd.Sheets[_SheetNum].Columns[_num].HorizontalAlignment = CellHorizontalAlignment.Left;

                            break;

    case "RIGHT":

                            _spd.Sheets[_SheetNum].Columns[_num].HorizontalAlignment = CellHorizontalAlignment.Right;

                            break;

    case "CENTER":

                            _spd.Sheets[_SheetNum].Columns[_num].HorizontalAlignment = CellHorizontalAlignment.Center;

                            break;

    }

    switch (DR["CellAlignV"].ToString().ToUpper())

                    {

    case "TOP":

                            _spd.Sheets[_SheetNum].Columns[_num].VerticalAlignment  = CellVerticalAlignment.Top;

                            break;

    case "BOTTOM":

                            _spd.Sheets[_SheetNum].Columns[_num].VerticalAlignment = CellVerticalAlignment.Bottom;

                            break;

    case "CENTER":

                            _spd.Sheets[_SheetNum].Columns[_num].VerticalAlignment = CellVerticalAlignment.Center;

                            break;

    }

    _num++;

    }

    }

    대충 이정도면 안되겠는가?

    조금 지저분 하긴하다만..

    자.. 얼렁 결과부터 볼까?

    clip_image001

    이런 것에 대충 위의 소스를 실행하자.

    clip_image002

    오 대충 된것 같다.

    그런데 왠지 셀 타입은 변경이 안된듯 하네.. 이런.. 작성을 안해줬나보다.

    지금.. 얼렁.. 작성을 해보자.

    private BaseCellType getCellType(string CellType, string INIT)

            {

    switch (CellType.ToUpper())

    {

                    case "MASK":

    MaskCellType MaskC = new MaskCellType();

    MaskC.Mask = INIT; //예를 들어서 ##:## 같은것들

    MaskC.MaskChar = Convert.ToChar(" ");

    return MaskC;

                        break;

    case "COMBO":

    break;

    case "TEXT":

    break;

    case "BUTTON":

    break;

    case "CURRENCY":

    case "MONEY":

    CurrencyCellType Money = new CurrencyCellType();

    Money.Separator = ",";

    Money.ShowCurrencySymbol = false;

    Money.ShowSeparator = true;

                        return Money;

    case "CHECKBOX":

                        break;

    case "PERCENTAGE":

                        PercentCellType Percentage = new PercentCellType();

                        return Percentage;

    break;

    }

    return null;

    }

    셀 타입은.. 이런식이 될것이다.

    대충...

    그럼.. 불러서 사용하는곳에는

    _spd.Sheets[_SheetNum].Columns[_num].CellType = getCellType(DR["CellType"].ToString(), DR["CellTypeINIT"].ToString());

    뭐 이정도 되겠지.

    그럼.. 다시금.. 결과를 보자.

    clip_image003

    뭐 이쁘지는 않지만.. 하여간.. 뭔가 되는듯 보여지기는 하다.

    원본 위치 <http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNO=8&no=1560&page=3>

'C# > DB를 이용한 Grid 셋팅' 카테고리의 다른 글

가르쳐 줬잖아.  (0) 2008.11.14
Spread Setting 1  (0) 2008.11.14
posted by 삶의여유로움
:
C#/DB를 이용한 Grid 셋팅 2008. 11. 14. 14:27

    지금 적는글은 일단 미완성이다.

    두어시간 지루함을 떨구기 위해서 그냥 심심풀이로 만들다가 적어둔다.

    게다가.. 내가 생각해도.. 참.. 한심한 수준의 이야기들이라서 그리 좋은지는 모르겠다만.. 여하튼.. 간만에 글을 적어보자.

    기본적으로 프로젝트를 하다보면 크리스털 리포트와 Spread를 빼놓을수가 없는데

    그 Spread에 컬럼의 속성이나 크기등등을 일일이 서술한다는것 자체는 여러모로 귀찮다.

    물론 아래의 방법은 더욱 더 귀찮은 방법에 속한다.

    이렇게 만드는 첫번째 이유는

    최종적인 사용자가 결과테이블을 볼때 그 결과 테이블의 정보를 쉽게 이동하게 하기 위해서 이고

    이것을 다시금 DB에 저장하고 또한 동시에 이 결과를 가지고 출력에 쉽게 사용하기 위한 몇가지를 다 함께 아우르게 된다.

    만약... 충실(?)하게도.. 시간이 남아돈다면.. 10개짜리 강좌를 적을만 하기도 하겠지만..

    눈치가 있는지라 아마도 그렇게 까지는 힘들것 같고..

    중간 중간 생략을 해 가면서 어찌되었든 글을 적어보자.

    clip_image001

    자.. 기본적으로 이런형태고 보자..

    여기서.. 클라이언트가.. CustomerID를..

    CompanyName 뒤에 보이도록 해달라고 요청을 했다.

    그럼.. 전산실에서 이걸 바꿔서 다시금 배포하는 수고를 해야된다 말인가?

    당연히 그렇치 않다. 불행히도.. 현재 어떤 프로젝트들은.. 이것들의 대부분 고정되어 있으며

    사용하기에도 그리 유연하지 않도록 설정이 되어 있다.

    물론 잘 설계를 해 놓은 소프트 웨어들은 기본적으로 되는 기능일것이다.

    clip_image002

    이런씩으로 옮겨서

    clip_image003

    사용자가 이렇게 보도록 하는것을 의미한다.

    혹자는 이럴것이다. 장난치냐고?.

    그렇다 위의 속성은 그냥 스프레드의 속성중에 컬럼이동에 대한것 한줄만 적어도 가능한것으로 알고 있다.

    예를 들어서

    fpSpread1.AllowColumnMove = true;

    이정도 수준이다.

    뭐.. 한마디로 장난을 치는것 같아 보인다.

    일단은 옮겨는 지는데.. 문제는.. 스프레드의 내용을 가지고 여러군데에서 사용할때이다.

    예를 들어서

    이런.. 설명을 위해서 몸소.. 예제를 작성하다니 ㅠ.ㅠ

    textBox1.Text = this.fpSpread1.ActiveSheet.Cells[3, 0].Text;

    textBox2.Text = this.fpSpread1.ActiveSheet.Cells[3, 1].Text;

    의 코드를 보자.

    clip_image004

    clip_image005

    이 같은 형태를 컬럼을 움직이고 나서.. 위의 두줄을 실행한다면..

    clip_image006

    clip_image007

    매우 당연히도.. 이렇게 바뀌어져 있을것이다.

    textBox1.Text = this.fpSpread1.ActiveSheet.Cells[3, 0].Text;

    textBox2.Text = this.fpSpread1.ActiveSheet.Cells[3, 1].Text;

    그렇다.. 장난치는듯 아무것도 아닌걸 가지고 정말..

    그냥.. 컬럼의 인덱스를 항상 동적으로 찾도록 하면 되는거 아닌가 말이다.

    textBox1.Text = this.fpSpread1.ActiveSheet.Cells[3, 컬럼인덱스["우리나라"]].Text;

    이정도 수준 아닌가..

    그러게 말이다. 별것도 아닌데.. 참 글을 적자니 민망하다.

    2.

    또 문제는.. 사용자가 자기가 바꾼걸 기억했다가 다음에 프로그램을 실행할때 그것의 형태로 나오게 해달라는것이다.

    으아~~~ 그렇다 이게 문제였다.

    위의 두가지 문제는 그냥.. 대충.. 두어줄로 땜방을 하면 되는건데

    젠장맞게도.. 이건 로컬의 MDB를 사용하던지 TEXT를 사용하던지 아님 서버의 DB를 사용하던지 어찌되었든

    어딘가에 적어야 되는문제가 생긴것이다.

    1. 은.. 당연히.. 순서를 저장해야 되고

    2. 는 컬럼의 크기를 저장해야 된다는 문제가 생긴다.

    내가? 이걸 어떻게 해.. 몰라~~~~~

    ㅠ.ㅠ... 이거 질문란에 적어야 되는글이 아닌가 가끔 나도 스스로를 의심해 본다.

    3.

    일단은.. 1,2번의 문제를.. 우찌 우찌 했다고 보자.

    또 하나의 문제는.. 출력이다.

    뭔 사용자는 그리도 요구사항이 많은지 말이다. 볼때마다 말이 틀려지는게 정말.. 여심과 비슷한 면이 많다.

    그럼.. 스프레드에 뿌려지는것과 출력할때는 또 DB를 한판 왔다 갔다고 하자.

    어라.. 그 사이에 DB 내용이 틀려졌네 !!

    이걸 좋아라 해야하는지 모르겠다만.. 이런것도 불만이고

    가끔가다 스프레드에 직접적으로 수정해서 적는 내용이 출력물에 반영을 시켜 달라는것도 있고

    이문제도 하여간 해결을 해줘야 하는 문제에 당면한다.

    4,5,6,7, 로~~~~~~~~ 쭉 달려가다 보면..

    너무 많으니 대충 생략을 하고

    여차여차 해서 저차저차 하다고 하자.

    다음글에서 계속 연결을 ..............

    원본 위치 <http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNO=8&no=1559&page=3>

'C# > DB를 이용한 Grid 셋팅' 카테고리의 다른 글

가르쳐 줬잖아.  (0) 2008.11.14
Spread Setting 2  (0) 2008.11.14
posted by 삶의여유로움
: