TextBox에 PlaceHolder 기능을 추가해야 해서 이것 저것 해보다가

 

OnPaint로 그릴 생각까지 했는데 분면 OnPaint를 오버라이드 했는데도 이벤트가 발생하지 않았습니다.

그럴때는 서브클래싱한 컨트롤에서 SetStyle을 설정('SetStyle(ControlStyles.userPaint, true)')해줘야 합니다.

 

SetStyle : http://msdn.microsoft.com/ko-kr/library/system.windows.forms.control.setstyle.aspx

 

그런데 구글링으로 찾은 소스중 보다 Win32 API를 이용해서 텍스트박스에 PlaceHolder 기능을 구현한게 있네요.

 

public class CueTextBox : TextBox

{  

    private static class NativeMethods

    {

        private  const uint ECM_FIRST       = 0x1500;

        internal const uint EM_SETCUEBANNER = ECM_FIRST + 1;

        [DllImport("user32.dll", EntryPoint = "SendMessageW")]

        public static extern IntPtr SendMessageW(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);

    }

    private string _cue;

    [

        Description("PlaceHolder로 사용될 텍스트"),

        Category("Appearance"),

        Browsable(true),

    ]        

    public string Cue

    {

        get

        {

            return _cue;

        }

        set

        {

            _cue = value;

            UpdateCue();

        }

    }

    public CueTextBox()

    {

        this.SetStyle(ControlStyles.UserPaint, false);

        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

    }

    protected override void OnPaint(PaintEventArgs e)

    {

        base.OnPaint(e);

    }

    private void UpdateCue()

    {

        if (IsHandleCreated && _cue != null)

        {

            NativeMethods.SendMessageW(Handle, NativeMethods.EM_SETCUEBANNER, (IntPtr)1, _cue);

        }

    }

    protected override void OnHandleCreated(EventArgs e)

    {

        base.OnHandleCreated(e);

        UpdateCue();

    }

}


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

[.Net] FolderbrowserDialog Custom Action  (0) 2014.02.08
[WinForm] OpenFileDialog  (0) 2013.03.13
posted by 뚱2

[C#] .Net Control.Invoke

.Net/.Net 2012. 3. 18. 20:17
MFC로만 응용프로그램을 만들어오다 이번에 프로젝트로 C# WinForm으로 응용프로그램을 만들게 되었다.
다른걸 떠나서 생산성 하나는 끝내준다.

각설하고 기본적으로 UI컨트롤은 메세지 루프로 이벤트를 받기때문에 메인 윈도우에서 생성해줘야 한다.
물론 별도 스레드를 만들고 메세지 루프도 만들어주면 가능하기는 한데 이건 된다 이거지 이렇게 사용해본적도
없고 본적도 없다.

백그라운드 작업을 할때 별도의 스레드에서 작업을 하고 메인 스레드에서 프로그레스 바를 이용해서 상태값을
변경해주는 방법을 종종 사용하는데 이게 네이티브 응용프로그램에서는 메세지로 컨트롤 했는데 
.Net쪽에서는 Controls.Invoke를 사용해서 해결한다는걸 삽질끝에 알았다.

Invoke 설명 : http://msdn.microsoft.com/ko-kr/library/system.windows.forms.control.invoke.aspx



위 이미지 같이 각 파일의 복사 나 이동의 상태를 알려주고 아래 프로그래스 바는 전체 파일 단위의 상태를 알려준다.

form code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Security.AccessControl;
using System.Threading;

namespace TestExplorer
{
    public partial class FileProgressForm : Form
    {
        public enum ACTION_TYPE {COPY, MOVE}
        delegate void SetProgressValueDelegate(int value);
        delegate void SetLabelTextDelegate(string text);
        delegate void DoEndDelegate();

        private string sourcePath = "";
        private string targetPath = "";
        private byte[] buffer = new byte[1024*100];// 100Kb
        private Thread thread = null;
        private ACTION_TYPE action = ACTION_TYPE.COPY;
        private bool isThreadEnd = false;

        public string SourcePath
        {
            get { return sourcePath;  }
            set { sourcePath = value; }
        }

        public string TargetPath
        {
            get { return targetPath; }
            set { targetPath = value; }
        }

        public ACTION_TYPE Action
        {
            get { return (action); }
            set { action = value;  }
        }

        public FileProgressForm()
        {
            InitializeComponent();
        }

        private void FileProgressForm_Load(object sender, EventArgs e)
        {
        }

        private void DoEnd()
        {
            this.isThreadEnd = true;
            this.DialogResult = DialogResult.OK;
        }

        private void FileProgressForm_Shown(object sender, EventArgs e)
        {
            // 파일 읽기 작업을 시작한다.
            if (File.Exists(this.sourcePath) == false
                && Directory.Exists(this.targetPath) == false)
            {
                MessageBox.Show("원본 폴더나, 파일을 선택해 주세요.");
                this.DialogResult = DialogResult.Cancel;
                return;
            }

            if (Directory.Exists(this.targetPath) == false)
            {
                MessageBox.Show("대상 폴더를 선택해 주세요.");
                this.DialogResult = DialogResult.Cancel;
                return;
            }

            if (this.sourcePath.Equals(this.targetPath) == true)
            {
                MessageBox.Show("원본과 대상이 일치합니다.");
                this.DialogResult = DialogResult.Cancel;
                return;
            }

            thread = new Thread(new ThreadStart(WorkThread));
            thread.Start();
        }

        // 복사 작업을 한다.
        private void WorkThread()
        {
            FileInfo[] arrfileInfo = null;

            if (File.Exists(sourcePath) == true)
            {
                arrfileInfo = new FileInfo[] { new FileInfo(sourcePath) };
            }
            else if (Directory.Exists(sourcePath) == true)
            {
                DirectoryInfo dirInfo = new DirectoryInfo(sourcePath);
                arrfileInfo = dirInfo.GetFiles();
            }

            if (arrfileInfo != null)
            {
                int count = arrfileInfo.Length;
                long total_current = 0;
                long total_total = 0;

                // 총 파일 용량을 가져온다.
                foreach (FileInfo i in arrfileInfo)
                {
                    if ((i.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden)
                    {
                        total_total += i.Length;
                    }
                }

                // 복사할 파일을 순회한다.
                foreach (FileInfo i in arrfileInfo)
                {
                    if ((i.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
                    {
                        continue;
                    }

                    FileStream rs = null, ws = null;
                    try
                    {
                        rs = new FileStream(i.FullName, FileMode.Open);
                        ws = new FileStream(targetPath + "\\" + i.Name, FileMode.Create);

                        // 익명 메서드
                        this.Invoke((SetLabelTextDelegate)delegate(string text)
                        {
                            this.label_filename.Text = text;
                        },
                        new object[] {i.Name});


                        int readSize = 0;
                        long current_current = 0;
                        long current_total = i.Length;

                        while ((readSize = rs.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            current_current += readSize;
                            total_current += readSize;
                            // 현재 프로그래스 바
                            int percent = (int)((double)current_current / (double)current_total * 100);

                            Console.WriteLine("cur={0}, total={1}, percent={2}", current_current, current_total, percent);

                            //익명 메서드
                            this.Invoke((SetProgressValueDelegate)delegate(int value)
                            {
                                this.progressCur.Value = value;
                                this.lableCurPercent.Text = String.Format("{0}%", value);
                            },
                            new object[] {percent});

                            // 토탈 프로그래스 바
                            percent = (int)((double)total_current / (double)total_total * 100);
                            
                            //익명 메서드
                            this.Invoke((SetProgressValueDelegate)delegate(int value)
                            {
                                this.progressTotal.Value = value;
                                this.labelTotalPercent.Text = String.Format("{0}%", value);
                            },
                            new object[] { percent });


                            ws.Write(buffer, 0, readSize);
                        }//while ((readSize = rs.Read(buffer, 0, buffer.Length)) != 0)

                        //익명 메서드
                        this.Invoke((SetProgressValueDelegate)delegate(int value)
                        {
                            this.progressCur.Value = value;
                            this.lableCurPercent.Text = String.Format("{0}%", value);
                        },
                        new object[] { 100 });
                    }
                    catch (Exception ex)
                    {
                    }
                    finally
                    {
                        try { rs.Close(); }
                        catch (Exception ex) { }
                        try { ws.Close(); }
                        catch (Exception ex) { }
                    }

                    if (this.action == ACTION_TYPE.MOVE)
                    {
                        File.Delete(i.FullName);
                    }
                }//foreach (FileInfo i in arrfileInfo)

                //익명 메서드
                this.Invoke((SetProgressValueDelegate)delegate(int value)
                {
                    this.progressTotal.Value = value;
                    this.labelTotalPercent.Text = String.Format("{0}%", value);
                },
                new object[] { 100 });

                //TODO: 500 밀리세컨 슬립한다.
                Thread.Sleep(500);
            }//if (arrfileInfo != null)
            this.Invoke((DoEndDelegate)delegate()
            {
                this.DoEnd();
            });
        }//private void WorkThread(object arg)

        private void FileProgressForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (thread != null && thread.IsAlive == true && isThreadEnd == false )
            {
                MessageBox.Show("작업 중입니다.");
                e.Cancel = true;
            }
        }
    }
}


designer code
namespace TestExplorer
{
    partial class FileProgressForm
    {
        /// 
        /// Required designer variable.
        /// 
        private System.ComponentModel.IContainer components = null;

        /// 
        /// Clean up any resources being used.
        /// 
        /// true if managed resources should be disposed; otherwise, false.
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// 
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// 
        private void InitializeComponent()
        {
            this.progressCur = new System.Windows.Forms.ProgressBar();
            this.progressTotal = new System.Windows.Forms.ProgressBar();
            this.label1 = new System.Windows.Forms.Label();
            this.label2 = new System.Windows.Forms.Label();
            this.labelTotalPercent = new System.Windows.Forms.Label();
            this.lableCurPercent = new System.Windows.Forms.Label();
            this.label_filename = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // progressCur
            // 
            this.progressCur.Location = new System.Drawing.Point(13, 49);
            this.progressCur.Name = "progressCur";
            this.progressCur.Size = new System.Drawing.Size(366, 32);
            this.progressCur.Step = 1;
            this.progressCur.TabIndex = 0;
            // 
            // progressTotal
            // 
            this.progressTotal.Location = new System.Drawing.Point(12, 107);
            this.progressTotal.Name = "progressTotal";
            this.progressTotal.Size = new System.Drawing.Size(366, 32);
            this.progressTotal.Step = 1;
            this.progressTotal.TabIndex = 1;
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(13, 32);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(65, 12);
            this.label1.TabIndex = 2;
            this.label1.Text = "현재 파일 :";
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(13, 91);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(65, 12);
            this.label2.TabIndex = 3;
            this.label2.Text = "전체 파일 :";
            // 
            // labelTotalPercent
            // 
            this.labelTotalPercent.AutoSize = true;
            this.labelTotalPercent.Location = new System.Drawing.Point(87, 91);
            this.labelTotalPercent.Name = "labelTotalPercent";
            this.labelTotalPercent.Size = new System.Drawing.Size(21, 12);
            this.labelTotalPercent.TabIndex = 4;
            this.labelTotalPercent.Text = "0%";
            // 
            // lableCurPercent
            // 
            this.lableCurPercent.AutoSize = true;
            this.lableCurPercent.Location = new System.Drawing.Point(87, 32);
            this.lableCurPercent.Name = "lableCurPercent";
            this.lableCurPercent.Size = new System.Drawing.Size(21, 12);
            this.lableCurPercent.TabIndex = 5;
            this.lableCurPercent.Text = "0%";
            // 
            // label_filename
            // 
            this.label_filename.AutoSize = true;
            this.label_filename.Location = new System.Drawing.Point(13, 9);
            this.label_filename.Name = "label_filename";
            this.label_filename.Size = new System.Drawing.Size(75, 12);
            this.label_filename.TabIndex = 7;
            this.label_filename.Text = "(현재파일명)";
            // 
            // FileProgressForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(391, 151);
            this.Controls.Add(this.label_filename);
            this.Controls.Add(this.lableCurPercent);
            this.Controls.Add(this.labelTotalPercent);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.progressTotal);
            this.Controls.Add(this.progressCur);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "FileProgressForm";
            this.Text = "파일전송";
            this.Load += new System.EventHandler(this.FileProgressForm_Load);
            this.Shown += new System.EventHandler(this.FileProgressForm_Shown);
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FileProgressForm_FormClosing);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.ProgressBar progressCur;
        private System.Windows.Forms.ProgressBar progressTotal;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.Label labelTotalPercent;
        private System.Windows.Forms.Label lableCurPercent;
        private System.Windows.Forms.Label label_filename;
    }
}

 
posted by 뚱2