How to C# Component - tip

FpSpreadSheet4.0 Sheet의 데이터 및 스키마를 Save 및 Open 하기

 

1. 개요

[그림 1.Sheet의 데이터]

프로젝트를 진행 하다보면 Sheet의 데이터를 저장하였다가 프로그램 재 구동시 불러와야 할 경우가 있습니다.

제가 생각하는 방법은 2가지 입니다.

1. Sheet에 바인딩 되어있는 DataTable을 Serialize하여 txt나 xml로 저장 하였다가 Deserialize하여 가져온다.

2. FpSpreadSheet의 Save 메소드와 Open 메소드를 이용하여 xml로 관리한다.

두 번째 방법을 이용하면 Sheet의 스키마도 Save 및 Open 할 수 있으니 두 번째 방법으로 설명하겠습니다.

 

 

2. 얻을 수 있는 기술

    - FpSpreadSheet의 Save, Open

 

3. 사용할 Method 소개하기

    Save : Sheet의 데이터를 인코딩하여 파일로 저장합니다. (Sheet의 스키마도 저장가능)

    Open : Sheet의 데이터를 디코딩하여 Sheet에 불러옵니다. (Sheet의 스키마도 로드가능)

 

 

4. 프로그래밍 UI 디자인

단계1. 프로젝트 생성

[그림 2. 프로젝트 생성]

    

    단계2. Form UI 디자인하기

 

 

            [그림 3. Form UI 디자인하기-FormMain.cs]

 

 

 

 

 

        [그림 4. Form UI 디자인하기-FormTest1.cs]

 

 

 

 

5. 프로그래밍하기

     5.1 프로그래밍에 앞서 고민하기

         프로그램 규모가 작으면 당장엔 상관 없겠지만 점점 커지고 방대해 지다 보면 Sheet를 보여주는 Form이 1000개가 될 수 있습니다.

         메인 폼에서 다른 자식들의 폼을 1000개를 가지고 있는 List<Form> foms 필드가 있습니다.

        1000개의 폼에 존재하는 Sheet를 저장 및 로드를 해야 합니다. 1000개의 메소드를 일일이 호출 할 수는 없으니 Interface를 사용하였습니다.

 

 

     5.2 본격적으로 프로그래밍하기

          노하우를 효과적으로 전달하기 위하여 설계와 OOP 철학에 대한 부분은 생략하도록 하겠습니다.

         IExportAndImport Interface에 대해 먼저 설명하겠습니다. controlFileName은 Export, Import할 파일 이름입니다.

        Directory는 사용자에게 입력 받을 수 있기 때문에 파일 이름만 필드에 넣었습니다. Export는 Save, Import는 Open기능 입니다.

 

 

namespace AboutFarPointExportAndImport

{

/// <summary>

/// Export와 Import Interface

/// </summary>

interface IExportAndImport

{

/// <summary>

/// Export, Import 할 파일 이름

/// </summary>

string controlFileName { get; set; }

 

/// <summary>

/// Save

/// </summary>

/// <param name="filePath"></param>

void Export(string folderPath);

 

/// <summary>

/// Open

/// </summary>

/// <param name="filePath"></param>

void Import(string folderPath);

}

}

 

 

 

 

     각 폼은 IExportAndImport Interface를 상속 받아 구현합니다.

    Save 메소드의 2번째 인자는 데이터만 저장 할 것인지 Sheet의 스키마도 xml형식으로 저장 할 것인지 지정합니다.

    true일 경우 데이터만 false일경우 데이터+스키마 모두 저장합니다.

public partial class FormTest1 : Form, IExportAndImport

{

public FormTest1()

{

InitializeComponent();

InitTable();

}

 

#region IExportAndImport 멤버

 

public string controlFileName { get; set; }

 

public void Export(string filePath)

{

System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create, System.IO.FileAccess.Write);

this.sheet.Save(fs, true);

fs.Close();

}

 

public void Import(string filePath)

{

System.IO.FileStream fs = System.IO.File.Open(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);

this.sheet.Open(fs);

fs.Close();

}

 

 

#endregion

 

}

 

.........

 

     FormMain의 동작을 설명하겠습니다.

     메인 폼은 List<Form> forms 라는 필드 하나를 가지고 있습니다. Load 할 때, Form 개체를 생성하고

        IExportAndImport의 필드인 controlFileName에 Save 및 Open할 파일 이름을 지정해줍니다.

 

public partial class FormMain : Form

{

/// <summary>

/// 생성한 Form

/// </summary>

List<Form> forms = null;

 

public FormMain()

{

InitializeComponent();

}

 

/// <summary>

/// Form Load할때

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void FormMain_Load(object sender, EventArgs e)

{

FormTest1 form1 = new FormTest1();

FormTest1 form2 = new FormTest1();

form1.controlFileName = "form1.xml";

form2.controlFileName = "form2.xml";

 

forms = new List<Form>();

forms.Add(form1);

forms.Add(form2);

}

......

 

      

 

 

     프로그램 구동 중에 Save를 하려고 Save 버튼을 눌렀을 시와 Load를 하려고 Load 버튼을 눌렀을 시입니다.

    자식 폼들이 또 자식 폼을 가지고 있다면, 해당 자식 Form의 Export 메소드를 구현 할 때,

    아래와 같은 구조로 작성하신다면 문제가 없을 것입니다.

 

/// <summary>

/// Export

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btn_save_Click(object sender, EventArgs e)

{

FolderBrowserDialog fb = new FolderBrowserDialog();

if (fb.ShowDialog() == DialogResult.OK)

{

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

{

IExportAndImport exportAndImportMember = this.forms[i] as IExportAndImport;

if (exportAndImportMember != null)

{

exportAndImportMember.Export(string.Format("{0}\\{1}", fb.SelectedPath, exportAndImportMember.controlFileName));

}

}

}

}

 

/// <summary>

/// Import

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void btn_load_Click(object sender, EventArgs e)

{

FolderBrowserDialog fb = new FolderBrowserDialog();

if (fb.ShowDialog() == DialogResult.OK)

{

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

{

IExportAndImport exportAndImportMember = this.forms[i] as IExportAndImport;

if (exportAndImportMember != null)

{

exportAndImportMember.Export(string.Format("{0}\\{1}", fb.SelectedPath, exportAndImportMember.controlFileName));

}

}

}

}

 

 

 

 

How_to_-_FarPoint Sheet 저장 및 불러오기.docx

 

AboutFarPointExportAndImport.zip

 

디자인 창에서 FpSpread 작업 할 때, SheetView 추가하여 Column Header 조작하기를 설명하겠습니다.

FpSpread를 하나 생성 하신 후, 속성 중 Sheets를 클릭하여 SheetView를 하나 생성합니다.

이 때, Column의 개수 및 Row 개수를 조절 하실 수 있습니다. (물론 Spread Designer에서도 변경 가능합니다.)

 

 

 

 

 

 

 

 

 

 

 

 

 

오른쪽 마우스 버튼을 눌러 Spread Designer를 클릭합니다.

 

 

 

 

 

 1번 지점을 클릭하시면 전체 선택이됩니다. 2번의 ColumnHeaderRowCount 속성을 조절하시면 3번과 같이
Header의 Row 개수가 3개로 증가한걸 확인 하실 수 있습니다.

 

 

 

 

 

 

 

 

 

 

 

 

1번 처럼 드래그 하여 선택을 한 후 오른쪽 마우스 버튼을 눌러 맨아래의 "Headers.."를 클릭하면 Header Editor창이
뜨게 됩니다. 2번은 1번의 상태와 동일합니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

1번의 위치의 Cell을 클릭한 후, ColumnSpan을 2로 변경하면 Column 방향으로 2개가 합쳐지게 됩니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

그 상태에서 RowSpan을 3으로 주면 Column 2개와 Row 3개가 합쳐진 모습을 미리 보여줍니다. Ok를 눌러줍니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

1번과 같은 상태가 됩니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

이처럼 Column 헤더를 조작하면 위와 같은 복잡한 헤더도 간단히 구현 가능합니다.

 

 

 #region 필드
        /// <summary>
        /// 다음 단어를 찾을 때 Index 위치
        /// </summary>
        int seekIndex = 0;
        #endregion

#region public method
        /// <summary>
        /// 해당 키워드들을 원하는 Color로 지정해줍니다.
        /// </summary>
        /// <param name="words"></param>
        /// <param name="color"></param>
        public void SetColorWords(string []words, System.Drawing.Color color)
        {
            for (int i = 0; i < words.Length; i++)
            {
                string word = words[i];
                while (true)
                {
                    int findIndex = 0;

                    findIndex = NextFind(word);

                    //검색된 것이 없다면
                    if (findIndex == -1)
                        break;

                    int result = this.Find(word, findIndex, findIndex + word.Length, RichTextBoxFinds.MatchCase);
                    if (result == -1)
                        break;

                    this.SelectionColor = color;
                    this.DeselectAll();
                    this.SelectionColor = System.Drawing.Color.Black;
                }
                this.seekIndex = 0;
            }
            this.SelectionLength = 0;
        }
        #endregion
        /// <summary>
        /// seekIndex부터 word에 해당하는 시작되는 Index 반환
        /// </summary>
        /// <param name="word"></param>
        /// <returns></returns>
        private int NextFind(string word)
        {
            int i = 0;
            for (i = seekIndex; i < this.Text.Length; i++)
            {
                int wordIndex = 0;
                while (true)
                {
                    if (this.Text[i] == word[wordIndex])
                    {
                        i++;
                        wordIndex++;
                        if (wordIndex == word.Length)
                        {
                            this.seekIndex = i;
                            return i - word.Length;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }
            this.seekIndex = i;
            return -1;
        }

 

 

결과 화면

 

 

 

 

 

TestRichTextBox.zip

 

 

'.Net > Winform' 카테고리의 다른 글

C# Keyboard, Mouse Hooking  (0) 2012.06.28
C# 지정한 폴더 감시하기  (0) 2012.06.27
RichTextBox Keyword 비쥬얼 스튜디오 효과내기  (0) 2012.05.10
C# WndProc이용, USB인식 및 해제 감시  (0) 2011.12.07
C# FileSystemWatcher  (3) 2011.12.07

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace WebSolus.Windows.Controls
{
    class KeyWordRichTextBox:RichTextBox
    {
        #region 속성
        /// <summary>
        /// 검색할 KeyWord를 가져오거나 설정합니다.
        /// </summary>
        public List<string> KeyWords {get;set; }
        #endregion

        #region 생성자
        /// <summary>
        /// 생성자
        /// </summary>
        public KeyWordRichTextBox()
        {
            InitializeComponent();
        }
        #endregion

        #region InitializeComponent
        /// <summary>
        /// InitializeComponent
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            this.ResumeLayout(false);
            this.KeyWords = new List<string>();
            this.KeyUp += new KeyEventHandler(KeyWordRichTextBox_KeyUp);
        }
        #endregion

        #region Api Function
        /// <summary>
        /// Caret의 위치를 가져옵니다.
        /// </summary>
        /// <param name="pt">Point 개체</param>
        /// <returns>true 성공,false 실패</returns>
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern bool GetCaretPos(out System.Drawing.Point pt);
        #endregion

        #region Event
        /// <summary>
        /// 키를 놓을 때 발생합니다.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void KeyWordRichTextBox_KeyUp(object sender, KeyEventArgs e)
        {
            for (int i = 0; i < this.KeyWords.Count; i++)
            {
                string word = this.KeyWords[i];
                if (this.SelectionStart >= word.Length)
                {
                    int result = this.Find(word, this.SelectionStart - word.Length, this.SelectionStart, RichTextBoxFinds.MatchCase);
                    if (result != -1)
                    {
                        System.Drawing.Point nearPoint = new System.Drawing.Point();
                        GetCaretPos(out nearPoint);
                        int index = this.GetCharIndexFromPosition(nearPoint);
                        this.SelectionColor = System.Drawing.Color.Blue;
                        if (index + 1 == this.TextLength)
                        {
                            this.SelectionStart = index + 1;
                        }
                        else
                        {
                            this.SelectionStart = index;
                        }
                        this.SelectionColor = System.Drawing.Color.Black;
                        this.DeselectAll();

                    }

                }
            }
        }
        #endregion
    }
}

 

 

 

결과 이미지

 

 

 

 

 

프레임워크 버젼 : 닷넷 프레임워크 2.0

 

 

TestRichTextBox.zip

'.Net > Winform' 카테고리의 다른 글

C# Keyboard, Mouse Hooking  (0) 2012.06.28
C# 지정한 폴더 감시하기  (0) 2012.06.27
RichTextBox 원하는 단어들 원하는 색으로 변경  (0) 2012.05.11
C# WndProc이용, USB인식 및 해제 감시  (0) 2011.12.07
C# FileSystemWatcher  (3) 2011.12.07
  1. 개요

    한 개의 서버에서 다수의 클라이언트들을 관리해주기 위한 프로그램

  • 기능

    1:N 다중 파일 전송

    1:1 원격제어 (키보드 이벤트, 마우스 Left, Right 클릭)

    WOL(원격으로 컴퓨터 키기)

    원격 컴퓨터 제어(원격으로 컴퓨터 종료 및 재시작)

     

     

  1. 동작 환경

    닷넷 프레임워크 3.5

     

     

     

  2. 프로그램 사용 전 구성 사항

     

    WOL 기능을 이용하려면 장치관리자->네트워크 어댑터->자신의 랜 카드 등록 정보->

    고급으로 이동 후 Wake on Magic Packet, Wake on pattern match, 웨이크 온 랜 종료을

    모두 사용으로 변경합니다.

     

     

     

    BIOS에서도 설정을 해야 하는데, 부팅 후 BIOS 설정 화면으로 진입하여 PME Event Wake up의

    사항을 Enabled로 지정하여 줍니다.

     

     

  3. 사용 설명서

     

-클라이언트

클라이언트 실행시 화면입니다.

설정 버튼을 클릭하시게 되면 아래와 같은 창이 뜨게 됩니다.

위의 창은 윈도우 부팅 시 자동 실행 여부와 다운로드 경로 설정을 할 수 있습니다.

 

 

또한 다운로드 경로는 setupinfo.xml을 메모장으로 열어

<?xml version="1.0"?>

<DownloadPath>D:\MyProjects\원격제어\파일및원격제어\Client\Client\bin\Debug\Download</DownloadPath>

</Global>

<DownloadPath>경로</DownloadPath> 경로 부분을 변경 하실 수 있습니다.

프로그램 동작 화면입니다. 로그를 보여줍니다.

 

 

 

 

 

 

 

-서버

프로그램 동작 화면입니다. 클라이언트의 IP 주소, Mac 주소, 비고를 추가 하실 수

있습니다. Mac주소는 cmd창을 여신 후, ipconfig –all 을 입력하시면 물리적 주소

(Mac주소)가 나옵니다. 로그인 상태는 클라이언트가 프로그램을 켰을 때 "O" 프로그램을

종료 하였을 때 "X"로 표시됩니다.

 

편집 메뉴의 리스트입니다.

 

 

추가 버튼을 눌렀을 때의 화면입니다. 원격 컴퓨터의 IP와 Mac주소와 비고는 해당

컴퓨터의 이름이나 특이사항을 적으시면 되겠습니다.

 

기능 메뉴의 리스트입니다.

파일 전송은 서버에서 클라이언트들에게 다중으로 파일을 전송 가능 합니다.

원격제어는 1:1만 지원합니다. 파일전송, WOL, 컴퓨터 제어는 여러 개의 클라이언트

에게 동시에 수행 할 수 있습니다.

 

원격제어 화면입니다. 마우스 Left, Right클릭, 키보드 사용 가능합니다.

 

 

 

파일 전송 화면입니다. 닫기 버튼을 누르셔도 전송 취소가 되지 않으며 닫기 버튼을 눌러

창이 닫혀도 기능->파일전송상태를 클릭하시면 전송상태를 확인 하실 수 있으십니다.

 

 

 

 

메뉴의 리스트입니다. 저장하기 버튼을 누르시면 IP주소, Mac주소,비고가 XML형식으로

computerinfo.xml에 저장이 됩니다.

<?xml version="1.0"?>

<Global xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="computerinfo">

<RemoteStart>false</RemoteStart>

<ctis>

<ComputerInfo>

<Ip>192.168.25.8</Ip>

<Mac_address>D0:00:00:00:00:00</Mac_address>

<Etc>백업</Etc>

</ComputerInfo>

</ctis>

</Global>

 

Client.exe

 

Server.exe

 

'프로그램' 카테고리의 다른 글

C# 작업관리자 구현 중  (0) 2012.08.19

USB 복사 프로그램입니다~
 닷넷프레임워크2.0 기반입니다~~
실행 오류 나시는분은 닷넷프레임워크2.0 설치해주세요~



filter.dat 파일을 메모장 형식으로 열어 형식을 정해줍니다~~ ex) *.exe/*.jpg


 

 


AutoUSBCopy 프로그램을 실행 시키시면 메모장에 정해진 형식들이
체크 리스트박스 목록에 뜨게 됩니다.

 



USB가 인식 되었을때 자동으로 복사하실 파일의 형식 1~n개 선택해주시고~

 

 

 

 

 

복사가 완료된 후 log 파일을 통해 복사한 파일을 확인하실 수 있습니다.

복사 경로는 복사하실 원하시는 폴더 지정해주시면 되겠습니다~
시작 버튼을 누르시면 USB 인식을 감시하고

USB를 인식하게되면 자동으로 복사합니다~

 

F12키 누르시면 프로그램이 숨겨지고 보여집니다~^^

체크되는것들이 적을 수록 복사 속도는 뛰어나겠죠?^^

 

 

USB 백업하실 때, 유용하게 사용 할 것 같아 만들었습니다~^^
폴더만 복사할때도 유용하겠네요....ㅎㅎ
폴더만 복사 할일이 있을려나..흠...ㅡ.ㅡ;;

 

protected override void WndProc(ref Message m)

{

      UInt32 WM_DEVICECHANGE = 0x0219;

      UInt32 DBT_DEVTUP_VOLUME = 0x02;

      UInt32 DBT_DEVICEARRIVAL = 0x8000;

      UInt32 DBT_DEVICEREMOVECOMPLETE = 0x8004;

if ((m.Msg == WM_DEVICECHANGE) && (m.WParam.ToInt32() == DBT_DEVICEARRIVAL)) //디바이스 연결

{

      int devType = Marshal.ReadInt32(m.LParam, 4);

      if (devType == DBT_DEVTUP_VOLUME)

      {

            RefreshDevice();

      }

}

if ((m.Msg == WM_DEVICECHANGE) && (m.WParam.ToInt32() == DBT_DEVICEREMOVECOMPLETE)) //디바이스 연결 해제

{

      int devType = Marshal.ReadInt32(m.LParam, 4);

      if (devType == DBT_DEVTUP_VOLUME)

      {

            RefreshDevice();

      }

}

 

base.WndProc(ref m);

}

 

 

 

public void RefreshDevice()

{

            listBox1.Items.Clear();

            string[] ls_drivers = System.IO.Directory.GetLogicalDrives(); //연결 되어있는 디바이스 얻어오기

            foreach (string device in ls_drivers)

            {

            System.IO.DriveInfo dr = new System.IO.DriveInfo(device);

            if (dr.DriveType == System.IO.DriveType.Removable) //제거 가능한 타입이라면

            {

                  listBox1.Items.Add(device);

            }

      }

}

 

FileSystemWatcher

작성자 : 김동영

작성일 : 2011. 12. 7

제목 : C# 폴더 감시

 

FileSystemWatcher 클래스는 파일 시스템 변경 알림을 수신하면서 디렉토리 또는

디렉토리의 파일이 변경되면 이벤트를 발생시킵니다.

 

FileSystemWatcher fs = new FileSystemWatcher();//개체 생성

fs.Path = "Test"; //Test 폴더 감시

fs.NotifyFilter = NotifyFilters.FileName|NotifyFilters.DirectoryName; //파일 이름과 폴더 이름 감시

fs.Filter = ""; //특정 파일 감시 ex)*.exe,(모두 감시"", *.*)

fs.Created += new FileSystemEventHandler(fs_Created); //조건에 해당하는 파일 및 폴더의 생성 이벤트 등록

fs.Deleted+=new FileSystemEventHandler(fs_Deleted); //조건에 해당하는 파일 및 폴더의 삭제 이벤트 등록

fs.EnableRaisingEvents = true; //이벤트 활성화

 

testeventhandler += new mydele(Form1_testeventhandler);

 

 

속성

설명

Path

조사할폴더의경로를가져오거나설정

NotifyFilter

조사할변경내용형식을가져오거나설정

Filter

폴더에서 모니터닝할 파일을 결정하는데 사용되는 필터 문자열을 가져오거나 설정

EnableRaisingEvents

구성 요소가 활성화 되는지 여부를 나타내는 값을 가져오거나 설정

 

 

public partial class Form1 : Form

{

delegate void mydele(string path);

event mydele testeventhandler;

 

public Form1()

{

InitializeComponent();

InitWatcher();

}

 

private void InitWatcher()

{

FileSystemWatcher fs = new FileSystemWatcher();

fs.Path = "Test";//

fs.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName;

fs.Filter = "";

fs.Created += new FileSystemEventHandler(fs_Created);

fs.Deleted += new FileSystemEventHandler(fs_Deleted);

fs.EnableRaisingEvents = true;

 

testeventhandler += new mydele(Form1_testeventhandler);

}

 

void fs_Deleted(object sender, FileSystemEventArgs e)

{

MakeMessage(e.FullPath, "삭íe제|");

}

 

void Form1_testeventhandler(string path)

{

listBox1.Items.Add(path);

}

 

 

 

void fs_Created(object sender, FileSystemEventArgs e)

{

MakeMessage(e.FullPath,"생성");

}

 

private void MakeMessage(string FullPath, string msg)

{

string path = string.Format("{0}\\{1}", Application.StartupPath, FullPath);

string extension = Path.GetExtension(path); //확장자 검사 폴더면 Null 반환

if (extension == string.Empty)

{

path = string.Format("{0} 폴더가 {1}되었습니다", path, msg);

}

else

{

path = string.Format("{0} 파일이 {1}되었습니다", path, msg);

}

listBox1.Invoke(testeventhandler, new object[] { path });

}

}

 

    

결과:

 

 

 

 

자세한 내용: MSDN 링크

+ Recent posts