C#2011. 2. 9. 11:45


#. panel에서 AutoScroll을 true로 설정할 경우 스크롤 표현이 가능합니다. 하지만 이 스크롤은 마우스 휠로 컨트롤이 안되는데요. 다음 클래스를 추가하면 마우스 휠로 컨트롤할 수 있습니다.

#. 추가할 클래스 - ScrollPanelMessageFilter 클래스를 프로젝트에 추가합니다.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MouseWheel
{
    /// <summary>
    /// panel에 표시된 스크롤을 마우스 휠로 움직일 수 있도록 하는 클래스
    /// </summary>
    public class ScrollPanelMessageFilter : IMessageFilter
    {
        int WM_MOUSEWHEEL = 0x20A;
        Panel panel;
        bool panelHasFocus = false;
        [DllImport("user32.dll")]
        static extern bool GetCursorPos(ref Point lpPoint);
        [DllImport("User32.dll")]
        static extern Int32 SendMessage(int hWnd, int Msg, int wParam, int lParam);

        public ScrollPanelMessageFilter(Panel panel)
        {
            this.panel = panel;
            //Go through each control on the panel and add an event handler.
            //We need to know if a control on the panel has focus to prevent sending
            //the scroll message a second time
            AddFocusEvent(panel);
        }

        private void AddFocusEvent(Control parentControl)
        {
            foreach (Control control in parentControl.Controls)
            {
                if (control.Controls.Count == 0)
                {
                    control.GotFocus += new EventHandler(control_GotFocus);
                    control.LostFocus += new EventHandler(control_LostFocus);
                }
                else
                {
                    AddFocusEvent(control);
                }
            }
        }

        void control_LostFocus(object sender, EventArgs e)
        {
            panelHasFocus = false;
        }

        void control_GotFocus(object sender, EventArgs e)
        {
            panelHasFocus = true;
        }


        #region IMessageFilter Members
        public bool PreFilterMessage(ref Message m)
        {
            //filter out all other messages except than mousewheel
            //also only proceed with processing if the panel is focusable,
            //no controls on the panel have focus
            //and the vertical scroll bar is visible

            if (m.Msg == WM_MOUSEWHEEL && panel.CanFocus && !panelHasFocus && panel.VerticalScroll.Visible)
            {
                //is mouse cordinates over the panel display rectangle?
                Rectangle rect = panel.RectangleToScreen(panel.ClientRectangle);
                Point cursorPoint = new Point();
                GetCursorPos(ref cursorPoint);

                if ((cursorPoint.X > rect.X && cursorPoint.X < rect.X + rect.Width) &&
                    (cursorPoint.Y > rect.Y && cursorPoint.Y < rect.Y + rect.Height))
                {
                    //send the mouse wheel message to the panel.
                    SendMessage((int)panel.Handle, m.Msg, (Int32)m.WParam, (Int32)m.LParam);
                    return true;
                }
            }

            return false;
        }
        #endregion

    }
}

#. 사용법.
 - Form 의 Activated, Deactivate 이벤트에서 아래와 같이 구현 하여 줍니다.

    public partial class Form1 : Form
    {
        private ScrollPanelMessageFilter filter;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Activated(object sender, EventArgs e)
        {
            filter = new ScrollPanelMessageFilter(panel);
            Application.AddMessageFilter(filter);
        }

        private void Form1_Deactivate(object sender, EventArgs e)
        {
            Application.AddMessageFilter(filter);
        }
    }


네이년 블로그를 뒤져서 찾았습니다.

Posted by 쿵캉켕
C#2011. 1. 26. 16:00

#. 중복실행을 방지하기 위한 Mutex 클래스의 사용법 입니다.



using System.Threading;    // Mutex 클래스를 사용하기 위한 네임 스페이스

[STAThread]
        static void Main(string[] args)
        {
            bool bnew;

            // 프로그램명은 WinForm.Text 명을 말합니다.
            Mutex mutex = new Mutex(true, "실행하는 프로그램명", out bnew);

            try
            {
                if (bnew)
                {
                    Application app = new Application();
                    app.Run(new "실행할 프로그램");

                    //mutex 해제
                    mutex.ReleaseMutex();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "MAIN");
            }
            finally
            {
                mutex.Close();
            }

Posted by 쿵캉켕
C#2010. 11. 10. 12:33
#. 콤보박스에 텍스트를 보여주고 뒤에 Tag처럼 히든으로 값을 숨겨서 ComboBox의 Item을 선택한 경우 해당 Item의 히든 값을 같이 가져오도록 하는 방법 입니다.

1. DataTable을 만든다.
ex)
text | value
----------
001 | abc
002 | def
.
.
.

대충 요런 구성으로 만드시면 됩니다. DataTable 만드는 법을 모르신다면 제 블로그에 있으니 찾아보세요~


2. DataTable을 ComboBox에 넣는다.
 - comboBox.DataSource = dataTable;

3. ComboBox에 표시할 부분을 설정한다.
 - comboBox.DisplayMember = "text" //컬럼 명

4. comboBox에 숨길 값을 설정한다.
 - comboBox.ValueMember = "value";

이러면 다 끝난 것입니다. 만약 ComboBox에서 선택한 item의 히든 값을 보고 싶으시다면
 - string aaa = (string)comboBox.SelectedValue; //히든 값이 string인 경우
요렇게 사용 하시면 되겠습니다. SelectValue가 object 객체 이기 때문에 가져 오실 때에는 형변환을 꼭 해주셔야 합니다.^^
Posted by 쿵캉켕
C#2010. 11. 10. 12:00
#. DataTable은 메모리에 있는 데이터로 구성된 테이블을 생성하는 것입니다. 데이터를 주고 받기 위한 용도로 자주 사용됩니다.아래 예시는 간단하게 DataTable을 만드는 방법 입니다.

#. 생성코드
  1. DataTable dt = new DataTable("TableName");  
 - 생성자의 인자는 테이블 이름입니다. 인자를 주지 않을 수도 있습니다.

#. 필드 정의 코드
  1. DataColumn col1 = new DataColumn();  
  2. col1.DataType = System.Type.GetType("System.Int32");  
  3. col1.ColumnName = "ID";  
  4. col1.AutoIncrement = true;  
  5. dt.Columns.Add(col1);  
  6.   
  7. DataColumn col2 = new DataColumn();  
  8. col2.DataType = System.Type.GetType("System.String");  
  9. col2.ColumnName = "Name";  
  10. col2.DefaultValue = "No Name";  
  11. dt.Columns.Add(col2);  
  12.   
  13. DataColumn col3 = new DataColumn();  
  14. col3.DataType = System.Type.GetType("System.Int32");  
  15. col3.ColumnName = "Age";  
  16. col3.DefaultValue = 0;  
  17. dt.Columns.Add(col3);
 - 각 필드에 대한 데이터 타입은 .NET의 Type을 그대로 사용할 수 있습니다.


#. 필드에 대한 레코두 추가 코드
  1. DataRow dr1 = dt.NewRow();  
  2. dr1["Name"] = "개똥이";  
  3. dr1["Age"] = 10;  
  4. dt.Rows.Add(dr1);  
  5.   
  6. DataRow dr2 = dt.NewRow();  
  7. dr2["Name"] = "소똥이";  
  8. dr2["Age"] = 13;  
  9. dt.Rows.Add(dr2);  
  10.   
  11. DataRow dr3 = dt.NewRow();  
  12. dr3["Name"] = "말똥이";  
  13. dr3["Age"] = 15;  
  14. dt.Rows.Add(dr3); 
 - 레코드에 해당되는 DataRow는 DataTable의 NewRow 매소드를 통해 생성해야 합니다.

#. Primary Key 지정 코드
  1. DataColumn[] key = new DataColumn[1];  
  2. key[0] = col1;  
  3. dt.PrimaryKey = key; 


Posted by 쿵캉켕
C#2010. 6. 15. 14:39

#. 내용.
 - C#에서 포인터를 사용하면 불안전한 코드가 됩니다. C#은 CLR이 메모리를 자동으로 관리해 주는데 포인터는 사용자가 직접 메모리를 건들이기 때문에 불안전코드가 되는 것입니다. 이 상태에서 실행하면 컴파일 오류가 발생합니다. 이때 unsafe키워드를 사용하면 포인터를 사용할 수 있습니다.

#. 방법.
1. unsafe 키워드를 함수 앞에 명시.
 - 함수의 매게변수와 함수의 끝부분까지 포인터를 사용할 수 있습니다.
 ex)
   unsafe static void PointerMethod(int* x)
   {
          *x = 1000;
    }
2. unsafe 블록을 설정.
 - 블록 내에서 포인터를 사용할 수 있습니다.
 ex)
   public static void Start()
   {
       int x1 = 10;
       unsafe
       {
           PointerMethod(&x1);
       }
       MessageBox.Show(x1.ToString());
  }

Posted by 쿵캉켕
C#2010. 4. 23. 19:55

#. 내용.
  닷넷 UI를 사용하는 프로그램을 제작하다가 이런 메시지를 보았습니다.
 - "크로스 스레드 작업이 잘못되었습니다. 'm_listBoxMessages' 컨트롤이 자신이 만들어진 스레드가 아닌 스레드에서 액세스되었습니다."

  FTP Server를 제작하는 도중에 윈도우 폼에서 listBox컨트롤을 사용하였는데, TcpListener를 사용하는 Thread 안에서 Handler 클래스를 호출하면 Handler 클래스 내에 등록한 이벤트가 발생하여 윈도우 폼에 있는 listBox에 메시지를 출력하는 경우였습니다. 컴파일을 한 경우 정상적으로 실행되지만 디버깅모드에 들어가면 저 메시지가 출력 되더군요.

  네이년을 뒤져보니 다음 해결방법을 찾았습니다. 그 해결방법에 따라 소스를 아래와 같이 변경하였더니 정상적으로 디버깅 됩니다. 방법은 delegate를 선언하여 다르 스레드에서 Control을 호출하는경우 Invoke로 그 함수를 다시 호출하는 거죠. 아래 방법을 보시면 도움이 되실겁니다.

#. 방법.
public partial class FTPServerForm : Form
{
        //System.InvalidOperationException처리를 위한 delegate 선언.
        delegate void SetMessageHandler(int nID, string strMessage);
        .
        .
        .
        .

       //delegate를 사용하여 Control의 InvokeRequired속성이 true일 경우
     //Form에서 Invoke 함수로 해당 함수를 다시 호출.

        void FtpServerMessageHandler_Message(int nID, string strMessage)
        {
            if (this.m_listBoxMessages.InvokeRequired)
          {
                SetMessageHandler message = new SetMessageHandler(FtpServerMessageHandler_Message);
                this.Invoke(message, new object[] { nID, strMessage });
            }
            else
            {
                //실제 listBox에서 출력되는 부분.
                .
                .
                .
                .
             }
        }
}


※. 꼭 같은 경우는 아니지만 크로스 스레드 작업 시 해당 윈폼의 생성자에다가 CheckForIllegalCrossThreadCalls = false;를 넣어 줘도 되는 경우가 있습니다.

Posted by 쿵캉켕