사용자 도구

사이트 도구


kb:csharpsnippets


C# Snippets

.NET Tip이라고 불러야 하나?

ShellExecute

using System;
using System.Diagnostics;
...
ProcessStartInfo psi = new ProcessStartInfo();
psi.Verb = "open";
psi.FileName = @"c:\windows";
psi.UseShellExecute = true;
Process.Start(psi);

텍스트 파일 인코딩 알아내기

public System.Text.Encoding DetectEncoding(string fileName)
{
    System.Text.Encoding result = System.Text.Encoding.Default;
 
    using (System.IO.FileStream stream = System.IO.File.OpenRead(fileName))
    {
        if (stream != null && stream.CanRead && stream.CanSeek)
        {
            byte[] bom = new byte[stream.Length > 4 ? 4 : stream.Length];
            stream.Read(bom, 0, bom.Length);
            result = DetectEncoding(bom);
        }
    }
 
    return result;
}
 
public System.Text.Encoding DetectEncoding(byte[] bom)
{
    System.Text.Encoding result = System.Text.Encoding.Default;
 
    do
    {
        if (bom == null)
            break;
 
        if (bom.Length < 2)
            break;
 
        if (bom[0] == 0xFF && bom[1] == 0xFE && (bom.Length < 4 || bom[2] != 0 || bom[3] != 0))
        {
            result = System.Text.Encoding.Unicode;
            break;
        }
 
        if (bom[0] == 0xFE && bom[1] == 0xFF)
        {
            result = System.Text.Encoding.BigEndianUnicode;
            break;
        }
 
        if (bom.Length < 3)
            break;
 
        if (bom[0] == 0xEF && bom[1] == 0xBB && bom[2] == 0xBF)
        {
            result = System.Text.Encoding.UTF8;
            break;
        }
 
        if (bom[0] == 0x2B && bom[1] == 0x2F && bom[2] == 0x76)
        {
            result = System.Text.Encoding.UTF7;
            break;
        }
 
        if (bom.Length < 4)
            break;
 
        if (bom[0] == 0xFF && bom[1] == 0xFE && bom[2] == 0 && bom[3] == 0)
        {
            result = System.Text.Encoding.UTF32;
            break;
        }
 
        if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xFE && bom[3] == 0xFF)
        {
            result = System.Text.Encoding.GetEncoding(12001);
            break;
        }
 
    } while (false);
 
    return result;
}

간단한 TCP & UDP 통신

public static string TcpSendReceive(string ipStr, int port, string sendMsg, int timeout)
{
    Socket tcpSocket = new Socket(
            AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp
            );
    tcpSocket.ReceiveTimeout = timeout;
 
    StringBuilder result = new StringBuilder();
 
    tcpSocket.Connect(ipStr, port);
    if (tcpSocket.Connected)
    {
        try
        {
            Byte[] sendBuffer = Encoding.ASCII.GetBytes(sendMsg);
            tcpSocket.Send(sendBuffer, sendBuffer.Length, 0);
 
            Byte[] recvBuffer = new Byte[1024];
            Int32 bytes = tcpSocket.Receive(recvBuffer, recvBuffer.Length, 0);
            result.Append(Encoding.ASCII.GetString(recvBuffer, 0, bytes));
            while (bytes > 0)
            {
                bytes = tcpSocket.Receive(recvBuffer, recvBuffer.Length, 0);
                result.Append(Encoding.ASCII.GetString(recvBuffer, 0, bytes));
            }
        }
        catch (System.Net.Sockets.SocketException)
        {
            result.Append("Error");
        }
 
        tcpSocket.Close();
    }
    else
    {
        result.Append("Error");
    }
 
    return result.ToString();
}
 
public static string UdpSendReceive(string ipStr, int port, string sendMsg, int timeout)
{
    IPEndPoint ip = new IPEndPoint(IPAddress.Parse(ipStr), port);
 
    Socket udpSocket = new Socket(
            AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp
            );
    udpSocket.ReceiveTimeout = timeout;
 
    string result = "";
 
    Byte[] sendBuffer = Encoding.ASCII.GetBytes(sendMsg);
    udpSocket.SendTo(sendBuffer, sendBuffer.Length, SocketFlags.None, ip);
 
    IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
    EndPoint remote = (EndPoint)sender;
 
    Byte[] recvBuffer =  new byte[1024];
    try
    {
        int bytes = udpSocket.ReceiveFrom(recvBuffer, ref remote);
        if (bytes > 0)
            result = Encoding.ASCII.GetString(recvBuffer, 0, bytes);
    }
    catch (System.Net.Sockets.SocketException)
    {
        result = "Error";
    }
 
    udpSocket.Close();
 
    return result;
}

블록킹 소켓 만세~

파일 이름, 확장자 등 분리하기

System.IO.Path 모듈 이용

OS 종류 알아내기

OperatingSystem os = Environment.OSVersion;
MessageBox.Show(os.Version.ToString());
MessageBox.Show(os.Platform.ToString());

시스템 폴더 경로 알아내기

Environment.GetFolderPath( Environment.SpecialFolder.Personal )

실행 파일 경로 알아내기

Application.ExecutablePath

or

Application.StartupPath

아니면 이렇게도…

System.Reflection.Assembly.GetExecutingAssembly.GetModules()(0).FullyQualifiedName
System.Reflection.Assembly.GetExecutingAssembly.Location

ListView 성능 개선

정렬자(sorter)가 설정되어 있는 리스트뷰에 대량의 아이템을 집어넣는 경우, 아이템을 집어넣을 때마다 정렬이 이루어지므로 뒤로 갈수록 매우 느려진다. 이를 해결하기 위해서는 2가지 방법이 있다.

첫번째는 아이템을 집어넣기 전에 정렬자를 null로 만든 다음, 다 집어넣은 후 정렬자를 새로 세팅하고, Sort()를 호출하는 방법이다. 아이템을 집어넣을 때

AddRange()

함수를 이용하면 좀 더 나은 성능을 얻을 수 있다.

System.Collections.IComparer<ListViewItem> oldSorter = MyListView.ListViewItemSorter;
MyListView.ListViewItemSorter = null;
...
아이템 추가
...
MyListView.ListViewItemSorter = oldSorter;
MyListView.Sort();

두번째는 리스트뷰의 가상 모드(virtual mode)를 이용하는 방법이다. 가상 모드에서는 아이템의 컬렉션이 리스트뷰 내부에 존재하는 것이 아니라, 외부에 존재하게 된다. 리스트뷰가 이벤트 핸들러를 통해 아이템을 요청하면 유저가 이를 제공해줘야 한다.

...
TListViewItem[] MyItems;
MyListView.OnRetrieveVirtualItem += MyListView_RetrieveVirtualItem;
...
 
private void SomeButton_Click(object sender, EventArgs e)
{
    Array.Sort(MyItems, MySorter);
    MyListView.VirtualMode = true;
    MyListView.VirtualListSize = MyItems.Length;
}
 
private void MyListView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
    e.Item = MyItems[e.ItemIndex];
}

정렬자 안에서 하는 일이 매우 많다면, 즉 리스트 아이템 비교에 들어가는 비용이 크다면 가상 모드보다는 그냥 정렬자 껐다 켯다 하는 것이 낫다.

ListView 각 컬럼 헤더 클릭시 해당 컬럼을 기준으로 아이템 정렬하기

대충 아래와 같은 클래스를 만들고…

/// <summary>
/// 리스트뷰 아이템 소팅을 위한 비교 클래스. 
/// 리스트뷰에 있는 아이템을 문자열로서가 아니라, 숫자로 비교하고자 하는 
/// 경우 Numeric = true로 설정한다.
/// </summary>
class ListViewItemComparer : System.Collections.IComparer<ListViewItem>
{
    private int ColumnIndex = 0;
    private bool NumericComparison = false;
    private bool AscendingOrder = true;
 
    public int Column 
    { 
        get { return ColumnIndex; } 
        set { ColumnIndex = value; } 
    }
    public bool Numeric 
    { 
        get { return NumericComparison; } 
        set { NumericComparison = value; } 
    }
    public bool Ascending 
    { 
        get { return AscendingOrder; } 
        set { AscendingOrder = value; } 
    }
 
    public ListViewItemComparer(int col)
    {
        ColumnIndex = col;
    }
 
    public int Compare(object l, object r)
    {
        ListViewItem lhs = (ListViewItem)l;
        ListViewItem rhs = (ListViewItem)r;
 
        if (AscendingOrder)
        {
            if (lhs == null && rhs == null) return 0;
            else if (lhs == null) return -1;
            else if (rhs == null) return 1;
 
            if (lhs == rhs) return 0;
 
            if (NumericComparison)
            {
                decimal lhsValue, rhsValue;
 
                if (!Decimal.TryParse(lhs.SubItems[ColumnIndex].Text, out lhsValue))
                    lhsValue = 0;
 
                if (!Decimal.TryParse(rhs.SubItems[ColumnIndex].Text, out rhsValue))
                    rhsValue = 0;
 
                return Decimal.Compare(lhsValue, rhsValue);
            }
            else
            {
                string lhsText = lhs.SubItems[ColumnIndex].Text;
                string rhsText = rhs.SubItems[ColumnIndex].Text;
                return String.Compare(lhsText, rhsText);
            }
        }
        else
        {
            if (lhs == null && rhs == null) return 0;
            else if (lhs == null) return 1;
            else if (rhs == null) return -1;
 
            if (lhs == rhs) return 0;
 
            if (NumericComparison)
            {
                decimal lhsValue, rhsValue;
 
                if (!Decimal.TryParse(lhs.SubItems[ColumnIndex].Text, out lhsValue))
                    lhsValue = 0;
 
                if (!Decimal.TryParse(rhs.SubItems[ColumnIndex].Text, out rhsValue))
                    rhsValue = 0;
 
                return -(Decimal.Compare(lhsValue, rhsValue));
            }
            else
            {
                string lhsText = lhs.SubItems[ColumnIndex].Text;
                string rhsText = rhs.SubItems[ColumnIndex].Text;
                return -(String.Compare(lhsText, rhsText));
            }
        }
    }
};
// 어딘가에서 이벤트 핸들러 추가해주고...
...
ListView1.ColumnClick += ListView1_ColumnClick;
...
 
private void ListView1_ColumnClick(object sender, ColumnClickEventArgs e)
{
    ListViewItemComparer sorter =
        ListView1.ListViewItemSorter as ListViewItemComparer;
 
    if (sorter == null)
        sorter = new ListViewItemComparer(e.Column);
    else
        sorter.Column = e.Column;
 
    ListView1.Sort();
}

TextBox 마지막 라인까지 스크롤 하기

로그 출력 같은 걸 텍스트박스에다 하는 경우, 텍스트가 추가될 때마다 마지막 라인까지 스크롤해주는 것이 보기가 좋다. 이를 위해서는 TextBox.ScrollToCaret 함수를 이용하면 된다. 단 포커스를 텍스트박스에다 줘야한다.

TextBox1.Focus();
TextBox1.SelectionStart = TextBox1.TextLength;
TextBox1.ScrollToCaret();

Mnemonic Focus Control

Label과 Textbox가 있을 때 라벨에 있는 mnemonic을 눌렀을 때, Textbox에 포커스가 가게 하려면, 탭순서를 잘 맞춰주면 된다.

사용자가 ALT+S를 누르면 일단 해당하는 라벨에 포커스를 주려고 시도한다. 그런데 라벨은 기본적으로 포커스를 가질 수 없으므로 그 다음 컨트롤에 포커스가 가게 된다. 그래서 원하는 컨트롤에 포커스가 가게 되는 것이다. 만약 그 다음 컨트롤이 포커스를 가질 수 없는 컨트롤이라면 계속해서 다음 컨트롤을 시도하게 된다.


  • see also C#
kb/csharpsnippets.txt · 마지막으로 수정됨: 2014/11/10 16:23 (바깥 편집)