어셈블리 정보를 확인해보자

 

                try
                {
                    System.Reflection.AssemblyName testAssembly =
                    System.Reflection.AssemblyName.GetAssemblyName(@"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll");
                }
                catch (Exception ex)
                {

                    Console.WriteLine(ex.Message);
                }

image

 

일단 Create an AppID 만들기

http://www.bing.com/developers/createapp.aspx

우선 지역선택에서 미쿡으로 지정

image

 

image

 

image

 

Bing API SDK 다운로드 및 소개

http://kojaedoo.tistory.com/444

 

Bing API안에 있는

Microsoft Translator  API의 간단한  설명

http://msdn.microsoft.com/en-us/library/ff512423(v=MSDN.10).aspx

image

나중에 실버라이트에도 적용하기 위해 HTTP Service 를 이용 ㅋ

 

 

아래는 구동되는 코드

image

번역 눌렀을때

image

 

소스코드

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.Net;
using System.IO;
using System.Xml;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        const string AppId = "위에보고 키 발급받아요!~ ㅋ";

        public Form1()
        {
            InitializeComponent();                     
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.comboBox1.SelectedIndex = 0;
            this.comboBox2.SelectedIndex = 1;

        }

        public static HttpWebRequest BuildRequest(string str, string SourceLanguage, string TargetLanguage)
        {
            string requestString = "http://api.bing.net/xml.aspx?"

                // Common request fields (required)
                + "AppId=" + AppId
                + "&Query=" + str
                + "&Sources=Translation"

                // Common request fields (optional)
                + "&Version=2.2"

                // SourceType-specific request fields (required)
                + "&Translation.SourceLanguage=" + SourceLanguage
                + "&Translation.TargetLanguage=" + TargetLanguage;

            // Create and initialize the request.
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(
                requestString);

            return request;
        }

    static string DisplayResponse(HttpWebResponse response)
    {
        // Load the response into an XmlDocument.
        XmlDocument document = new XmlDocument();
        document.Load(response.GetResponseStream());

        // Add the default namespace to the namespace manager.
        XmlNamespaceManager nsmgr = new XmlNamespaceManager(
            document.NameTable);
        nsmgr.AddNamespace(
            "api",
            "http://schemas.microsoft.com/LiveSearch/2008/04/XML/element");

        XmlNodeList errors = document.DocumentElement.SelectNodes(
            "./api:Errors/api:Error",
            nsmgr);
        string result = string.Empty;
        if (errors.Count > 0)
        {
            // There are errors in the response. Display error details.
            DisplayErrors(errors);
        }
        else
        {
            // There were no errors in the response. Display the
            // Translation results.
            result =   DisplayResults(document.DocumentElement, nsmgr);
        }
        return result;
    }


    static string DisplayResults(XmlNode root, XmlNamespaceManager nsmgr)
    {
        string version = root.SelectSingleNode("./@Version", nsmgr).InnerText;
        string searchTerms = root.SelectSingleNode(
            "./api:Query/api:SearchTerms",
            nsmgr).InnerText;

        // Display the results header.
        Console.WriteLine("Bing API Version " + version);
        Console.WriteLine("Translation results for " + searchTerms);
        Console.WriteLine();

        // Add the Translation SourceType namespace to the namespace manager.
        nsmgr.AddNamespace(
            "tra",
            "http://schemas.microsoft.com/LiveSearch/2008/04/XML/translation");

        XmlNodeList results = root.SelectNodes(
            "./tra:Translation/tra:Results/tra:TranslationResult",
            nsmgr);

        // Display the Translation results.
        string MsgResult = string.Empty;
        foreach (XmlNode result in results)
         {

             MsgResult= result.SelectSingleNode("./tra:TranslatedTerm", nsmgr).InnerText;
         }
        return MsgResult;
    }
    static void DisplayErrors(XmlNodeList errors)
    {
        // Iterate over the list of errors and display error details.
        Console.WriteLine("Errors:");
        Console.WriteLine();
        foreach (XmlNode error in errors)
        {
            foreach (XmlNode detail in error.ChildNodes)
            {
                Console.WriteLine(detail.Name + ": " + detail.InnerText);
            }

            Console.WriteLine();
        }
    }

    private void button1_Click_1(object sender, EventArgs e)
    {

        HttpWebRequest request = BuildRequest(this.textBox1.Text , this.comboBox1.SelectedItem.ToString() , this.comboBox2.SelectedItem.ToString());
        try
        {
            // Send the request; display the response.
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            this.textBox2.Text =  DisplayResponse(response);
        }
        catch (WebException ex)
        {
            // An exception occurred while accessing the network.
            Console.WriteLine(ex.Message);
        }
    }

    }
}

 

수정/삭제/업데이트를 동시에 하기 위해 만든 클래스입니다.

한번에 수정/삭제/업데이트를

bool IsNew { set; get; }
bool IsDeleted { get; set; }
bool IsEdited { get; set; }

가지고 확인 가능합니다.

 

환경설정

데이터 클래스는 아래의 두개 인터페이스를 구현해야 가능

INotifyPropertyChanged(using System.ComponentModel). , IDataContextState (걍 제가만든..)

 

가 구현되어져 있어야 프로퍼티가 수정되었을때 IsEdit 변경가능

아래인터페이스는 수정/추가/삭제 상태변경을 확인하기 위해 만든 인터페이스 입니다.

    /// <summary>
    /// 데이터베이스의 상태관리를 합니다.
    /// </summary>
    public interface IDataContextState
    {
        bool IsNew { set; get; }
        bool IsDeleted { get; set; }
        bool IsEdited { get; set; }
    }
DataGridView에서 프로퍼티가 수정되면 INotifyPropertyChanged 이벤트가 발생합니다.
IsEdit를 변경시키고 있습니다.
 

INotifyPropertyChanged 구현

        protected virtual void SendPropertyChanged(String propertyName)
        {
            if ((this.PropertyChanged != null))
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                this.IsEdited = true; //상태변경
            }
        }

IDataContextState 구현

 #region IDataContextState Members
        private bool _IsNew = false;
        private bool _IsDeleted = false;
        private bool _IsEdited = false;

        public bool IsNew
        {
            set
            {
                this._IsNew = value;
            }
            get
            {
				//고유증감 번호라든지 생성날짜가 없으면 신규로 본다
                return this._CreateTimesamp == null && !this.IsDeleted;
            }
        }
        
        public bool IsDeleted            
        {
            set
            {
                this._IsDeleted = value;
            }
            get
            {
                return this._IsDeleted;
            }
        }

        public bool IsEdited
        {
            set
            {
                this._IsEdited = value;
            }
            get
            {
                return this._IsEdited;
            }
        }

        #endregion

RepositoryManager.cs 구현

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace PersonnelManagement.Data
{
    /// <summary>
    /// TODO  RepositoryManager 데이터를 관리하는 클래스
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class RepositoryManager<T> : BindingList<T>
    {
        BindingList<T> DeleteBindingList = new BindingList<T>();
        
        /// <summary>
        /// 신규추가
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public void IsNew(T t)
        {
            if (t != null)
            {
                Type type = t.GetType().GetInterface("IDataContextState");
                if (type != null)
                {
                    ((Contract.Data.IDataContextState)t).IsNew = true;
                    this.Add(t);
                }
            }
        }

        /// <summary>
        /// (사용안함 ) INotifyPropertyChanged 로 자동 수정 상태변경
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public void IsUpdate(T t)
        {
            if (t != null)
            {
                Type type = t.GetType().GetInterface("IDataContextState");
                if (type != null)
                {
                    ((Contract.Data.IDataContextState)t).IsEdited = true;
                }
            }
        }
        

        /// <summary>
        /// 실제로 삭제하지 않고 상태만 변경
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public void IsDelete(T t)
        {
            if (t != null)
            {
                Type type = t.GetType().GetInterface("IDataContextState");
                if (type != null)
                {
                    ((Contract.Data.IDataContextState)t).IsDeleted = true;
                    foreach (var item in this.ToList() )
	                {
                        bool result =      Object.Equals(item , t );
                        if (result) {
                            ((Contract.Data.IDataContextState)item).IsDeleted = true;
                            DeleteBindingList.Add(t); //삭제된건 DeleteBindingList 담아둔다. 
                            this.Remove(t);
                            break;
                        }
	                } //end for
                }
            }
        }
        

        public void AddRange(List<T> list)
        {
            foreach (var item in list)
            {
                this.Add(item);
            }
        }

        /// <summary>
        /// 삭제 아이템을 포함 전체 리스트 반환
        /// </summary>
        /// <returns></returns>
        public List<T> GetBindingList() 
        {
            //삭제된 내용 담기
            foreach (var item in this.DeleteBindingList)
            {
                this.Add(item);
            }
            return this.ToList();
        }
    }
}

 

 

사용방법

바인딩

			//리스트 형식의 데이터를 받아옴
           List<Contract.Data.Doc.DocCategory> list = docManager.GetDocCategory(string.Empty);
			//담기
           DocCategoryRepositoryManager.AddRange(list);
			//그리드 뷰의 바인딩하기
           docCategoryBindingSource.DataSource = DocCategoryRepositoryManager;

 

가져오기

 List<DocCategory> resultList = this.DocCategoryRepositoryManager.GetBindingList();

이걸 사용하기 위해서는 아래의 인터페이스가 구현되어져 있어야함

추가

            //추가
            Contract.Data.Doc.DocCategory dc = new Contract.Data.Doc.DocCategory();
            DocCategoryRepositoryManager.IsNew(dc);

삭제

            foreach (DataGridViewRow row in this.dgvDocCategory.SelectedRows)
            {
                DocCategory dc = row.DataBoundItem as Contract.Data.Doc.DocCategory;
                if (dc != null)
                {
                    DocCategoryRepositoryManager.IsDelete(dc);
                }
            }

image

위의 서식을 반영하면됩니다.

 

<td style='mso-number-format:"\@";'>0103099</td>

실제  출력 모습

image

enum 의 항목과 같은 이름으로 된 이미지 파일을 가져오는 예제입니다.

		//enum 리스트
        public enum EnumImage
        {
            OK,M_OK, CANCEL,M_CANCEL, DELETE,M_DELETE, UPDATE, LOCK, 
			LOCK_OPEN, USER, USERS, SAVE, M_SAVE , SEARCH, FORDER_OPEN,
            PROPERTIES, PRINT, QUESTION, CALC, SETTING, 
			M_SETTING, CAHRT, DOC_CHART, DOC_TEXT, DOC_EXCEL
        }

		//리소스에 OK,M_OK등등의 이름으로된 이미지가 있다
		//enum 이름으로 이미지를 가져옵니다.
		string imagekey = Enum.GetName(typeof(EnumImage), "M_OK");

		//리소스 이미지 가져오기
	 	this.Image = (Image)Properties.Resources.ResourceManager.GetObject(imagekey, System.Globalization.CultureInfo.CurrentUICulture);

다른클래스 또는 다른위치의 이벤트를 받아오고 싶을때

다음 코드 예제에서는 이벤트 데이터와 이 이벤트 데이터를 사용하는 일반 EventHandler<(Of <(TEventArgs>)>) 대리자를 선언하며, 이벤트가 발생하는 방법을 보여 줍니다.

// This example demonstrates the EventHandler<T> delegate.

using System;
using System.Collections.Generic;

//---------------------------------------------------------
public class MyEventArgs : EventArgs
{
    private string msg;

    public MyEventArgs( string messageData ) {
        msg = messageData;
    }
    public string Message { 
        get { return msg; } 
        set { msg = value; }
    }
}
//---------------------------------------------------------
public class HasEvent
{
// Declare an event of delegate type EventHandler of 
// MyEventArgs.

    public event EventHandler<MyEventArgs> SampleEvent;

    public void DemoEvent(string val)
    {
    // Copy to a temporary variable to be thread-safe.
        EventHandler<MyEventArgs> temp = SampleEvent;
        if (temp != null)
            temp(this, new MyEventArgs(val));
    }
}
//---------------------------------------------------------
public class Sample
{
    public static void Main()
    {
        HasEvent he = new HasEvent();
        he.SampleEvent += 
                   new EventHandler<MyEventArgs>(SampleEventHandler);
        he.DemoEvent("Hey there, Bruce!");
        he.DemoEvent("How are you today?");
        he.DemoEvent("I'm pretty good.");
        he.DemoEvent("Thanks for asking!");
    }
    private static void SampleEventHandler(object src, MyEventArgs mea)
    {
        Console.WriteLine(mea.Message);
    }
}
//---------------------------------------------------------
/*
This example produces the following results:

Hey there, Bruce!
How are you today?
I'm pretty good.
Thanks for asking!

*/


 

Namespace: System.Net 추가

           string strHostName = Dns.GetHostName();

           IPHostEntry ipEntry = Dns.GetHostByName(strHostName);
           IPAddress[] addr = ipEntry.AddressList;

           for (int i = 0; i < addr.Length; i++)
           {
               Console.WriteLine("IP Address {0}: {1} ", i, addr[i].ToString());
           }

 

아래는 MSDN

The following example uses the GetHostByName method to get the DNS information for the specified DNS host name.

      try 
      {
         IPHostEntry hostInfo = Dns.GetHostByName(hostName);
         // Get the IP address list that resolves to the host names contained in the 
         // Alias property.
         IPAddress[] address = hostInfo.AddressList;
         // Get the alias names of the addresses in the IP address list.
         String[] alias = hostInfo.Aliases;

         Console.WriteLine("Host name : " + hostInfo.HostName);
         Console.WriteLine("\nAliases : ");
         for(int index=0; index < alias.Length; index++) {
           Console.WriteLine(alias[index]);
         } 
         Console.WriteLine("\nIP address list : ");
         for(int index=0; index < address.Length; index++) {
            Console.WriteLine(address[index]);
         }
      }
      catch(SocketException e) 
      {
         Console.WriteLine("SocketException caught!!!");
         Console.WriteLine("Source : " + e.Source);
         Console.WriteLine("Message : " + e.Message);
      }
      catch(ArgumentNullException e)
      {
     Console.WriteLine("ArgumentNullException caught!!!");
         Console.WriteLine("Source : " + e.Source);
         Console.WriteLine("Message : " + e.Message);
      }
      catch(Exception e)
      {
          Console.WriteLine("Exception caught!!!");
          Console.WriteLine("Source : " + e.Source);
          Console.WriteLine("Message : " + e.Message);
      }

.NET Framework 2.0의 Windows Forms 데이터 바인드 개선점 ( 제 2 부)

Cheryl Simmons
Microsoft Corporation

August 2006

적용 대상:
Microsoft Visual Studio 2005
Microsoft .NET Framework 2.0
Microsoft Windows Forms

요약: 일반 BindingList 에 대해 설명하고, 일반 컬렉션 형식을 확장해 정렬 기능 및 검색 기능의 추가 방법을 설명합니다.

Microsoft 다운로드 센터 (영어) 에서 C# 및 Visual Basic 로 작성된 코드 샘플 (29 KB)을 다운로드해 주세요.

목차

소개
일반 BindingList(generic BindingList)에 대해
코드 샘플 개요
일반 BindingList 검색
일반 BindingList 정렬
다음 단계
요약

소개

Windows Forms 데이터 바인드에서 화제가 되는 새로운 기능의 하나인 BindingSource 구성요소는 통화 관리 기능, 변경통지 기능 및 바인드 된 목록내의 멤버에 간단히 접근하는 기능을 제공하여 개발 작업을 크게 간략화합니다. 데이터 소스에 IBindingList 인터페이스가 구현되어 한층 더 검색 및 정렬 기능이 구현되며, BindingSource 를 사용해 데이터 소스의 검색 및 정렬을 실행할 수 있습니다. IBindingList 인터페이스를 구현하는 형식의 일례로서는 DataView 클래스가 있습니다. 그러나, IBindingList 인터페이스를 구현하는 클래스를 사용하지 않는 경우도 있을 수 있습니다. 이러한 경우에는 IBindingList 인터페이스를 독자적으로 구현하여 사용자 지정 비즈니스 개체 목록을 작성하여 바인드해야 합니다. 이 문서에서는 데이터 바인드 응용 프로그램으로 일반 BindingList를 사용하여 검색 및 정렬 가능한 사용자 지정 비즈니스 개체 목록의 생성 방법을 설명합니다.

일반 BindingList 에 대해

일반 BindingList는 IBindingList 인터페이스의 일반 구현입니다. IBindingList 인터페이스는 Windows Forms 데이터 바인드의 기본 인터페이스인 IList 인터페이스를 확장한 것입니다. IBindingList를 구현하는 클래스는 IList 인터페이스에서 상속된 기능 뿐만이 아니라, 정렬 기능, 검색 기능 및 변경통지 기능도 지원가능합니다. IBindingList 인터페이스는 매우 복잡한 인터페이스입니다. 일반 BindingList 형식의 일반 구현을 제공하여, Windows Forms 데이터 바인드엔진에 의해 이용되는 바인드 가능한 사용자 지정 비즈니스 개체 목록의 작성이 아주 간단해집니다. 일반 BindingList를 사용하여 비즈니스 개체를 데이터 바인드의 시나리오에 보관하면, 목록 삽입이나 목록 삭제를 간단하게 실행할 수 있으며, 목록을 변경했을 경우 변경 통지가 자동적으로 생성됩니다. 필요에 따라 몇가지의 속성 및 메서드를 오버라이드(override) 하여, 일반 BindingList 에 대한 검색 및 정렬 기능을 구현 할 수 있습니다.

코드 샘플 개요

검색 기능 및 정렬 기능을 데이터 소스에 추가하는 방법을 보여주기 위해 간단한 코드 샘플을 작성했습니다. 예를 들어, 복수의 Employee 개체가 포함된 목록이 있습니다. 우선, 이름, 급여 또는 입사일에 의해 특정 직원을 목록에서 검색하는 기능을 응용 프로그램에 구현해야 합니다. 또, 응용 프로그램의 사용자는 목록을 검색할 뿐만 아니라, 이름, 급여, 입사일등 직원 목록도 정렬해야 합니다. 다음의 코드 샘플과 같이, DataGridView 컨트롤에서 바인드되는 일반 BindingList 정렬 기능을 구현하여, 추가 코드를 기술하지 않아도 DataGridView 로 정렬 기능을 구현할 수 있습니다.

Employee 비즈니스 개체 개요

다음의 코드 샘플에서는 단순한 Employee 비즈니스 개체를 사용합니다. Employee 형식 구현은 다음과 같습니다.

public class Employee
{
    private string lastNameValue;
    private string firstNameValue;
    private int salaryValue;
    private DateTime startDateValue;

    public Employee() 
    {
        lastNameValue = "Last Name";
        firstNameValue = "First Name";
        salaryValue = 0;
        startDateValue = DateTime.Today;
    }

    public Employee(string lastName, string firstName, 
        int salary, DateTime startDate)
    {
        LastName = lastName;
        FirstName = firstName;
        Salary = salary;
        StartDate = startDate;
    }

    public string LastName
    {
        get { return lastNameValue; }
        set { lastNameValue = value; }
    }

    public string FirstName
    {
        get { return firstNameValue; }
        set { firstNameValue = value; }
    }

    public int Salary
    {
        get { return salaryValue; }
        set { salaryValue = value; }
    }

    public DateTime StartDate
    {
        get { return startDateValue; }
        set { startDateValue = value; }
    }

    public override string ToString()
    {
        return LastName + ", " + FirstName + "\n" +
        "Salary:" + salaryValue + "\n" +
        "Start date:" + startDateValue;
    }
}
일반 BindingList 확장

이 코드 샘플에서는 Employee 개체의 목록에 대한 검색 기능 및 정렬 기능을 구현하기 위해서 BindingList 에 근거해 SortableSearchableList 라는 이름의 형식을 작성했습니다. 검색 기능 및 정렬 기능을 구현하기위해 오버라이드(override) 할 필요가 있는 메서드 및 속성은 보호되고, 일반 BindingList를 확장해야 합니다. 또, SortableSearchableList 형식을 일반 목록으로 하여, <T> 구문을 클래스 정의로 사용합니다. 확장한 목록을 일반화함으로 다양한 상황에서 목록을 재사용 할 수 있습니다.

public class SortableSearchableList<T> : BindingList<T>

일반 BindingList 검색

일반 BindingList 에 대한 검색 기능을 구현하려면, 몇가지 과정을 거쳐야 합니다. 우선 SupportsSearchingCore 속성을 오버라이드(override) 하여 검색 기능이 지원되는 것을 보여줘야 합니다. 그 다음은 검색을 실행하는 FindCore 메서드를 오버라이드(override) 해야 합니다. 마지막으로 검색 기능을 공개합니다.

검색 지원 표시

SupportsSearchingCore 속성은 오버라이드(override) 해야하는 보호된 읽기 전용 속성입니다. SupportsSearchingCore 속성은 목록 검색이 지원되는지를 보여줍니다. 기본값에서는 이 속성이 false 로 설정되어 있습니다. 검색 기능이 목록에 구현되는 것을 보여주려면, 이 속성을 true 로 설정해야 합니다.

protected override bool SupportsSearchingCore
{
    get
    {
        return true;
    }
}
검색 기능 구현

다음에, FindCore 메서드를 오버라이드(override) 해, 목록을 검색하기 위한 구현을 제공해야 합니다. FindCore 메서드는 목록을 검색하여, 발견된 아이템의 인덱스를 돌려줍니다. FindCore 메서드는 검색하는 데이터 소스 종류의 속성 또는 열을 나타내는 PropertyDescriptor 개체와 검색 값을 나타내는 주요 개체를 받습니다. 다음의 코드는 대문자와 소문자를 구별하는 검색 기능의 간단한 구현을 보여줍니다.

protected override int FindCore(PropertyDescriptor prop, object key)
{
    // Get the property info for the specified property.
    PropertyInfo propInfo = typeof(T).GetProperty(prop.Name);
    T item;

    if (key != null)
    {
        // Loop through the items to see if the key
        // value matches the property value.
        for (int i = 0; i < Count; ++i)
        {
            item = (T)Items[i];
            if (propInfo.GetValue(item, null).Equals(key))
                return i;
        }
    }
    return -1;
}
검색 기능 공개

마지막으로, 퍼블릭 메서드를 사용해 검색 기능을 공개할 수 있습니다. 또는 Find 메서드를 사용하여 기본이 되는 IBindingList 가 검색 기능을 호출할 수도 있습니다. 다음의 코드에서는 검색 기능의 호출을 간략히 하기위해 퍼블릭에 공개된 Find 메서드가 문자열과 검색대상 키를 받습니다. 다음은 속성 문자열이 PropertyDescriptor 개체에 변환됩니다. 정상적으로 변환되면, PropertyDescriptor 및 키가 FindCore 메서드에게 전달됩니다.

public int Find(string property, object key)
{
    // Check the properties for a property with the specified name.
    PropertyDescriptorCollection properties = 
        TypeDescriptor.GetProperties(typeof(T));
    PropertyDescriptor prop = properties.Find(property, true);

    // If there is not a match, return -1 otherwise pass search to
    // FindCore method.
    if (prop == null)
        return -1;
    else
       return FindCore(prop, key);
}

그림 1 에, 실행중인 검색 기능을 보여줍니다. 성을 입력해 [Search] 버튼을 클릭하면, 검색 기능으로 성이 표시된 그리드 안의 첫번째 행이 표시됩니다 (발견되었을 경우).

그림 1. 일반 BindingList 를 사용해 구현 된 검색 기능

일반 BindingList 정렬

응용 프로그램의 사용자는 목록을 검색할 뿐만 아니라, 이름, 급여, 입사일 등의 직원관련 목록을 정렬해야 합니다. SupportsSortingCore 속성과 ApplySortCore 및 RemoveSortCore 메서드를 오버라이드(override) 해서 일반 BindingList 에 정렬 기능을 구현 할 수 있습니다. 또는 SortDirectionCore 및 SortPropertyCore 속성을 오버라이드(override) 하고, 정렬의 방향 및 속성을 각각 가져올수 있습니다. 또, 목록에 추가한 새로운 아이템을 정렬할 경우는 EndNew 메서드를 오버라이드(override) 해야 합니다.

정렬 지원 표시

SupportsSortingCore 속성은 오버라이드(override) 해야 하는 보호된 읽기 전용 속성입니다. SupportsSortingCore 속성은 목록이 정렬을 지원하는지 보여줍니다. 정렬 기능이 목록에 구현되는 것을 보여주려면, 이 속성을 true 로 설정합니다.

protected override bool SupportsSortingCore
{
    get { return true; }
}
정렬 적용

다음은 ApplySortCore 메서드를 오버라이드(override) 하여 정렬 내용을 지정합니다. ApplySortCore 메서드는 정렬 조건으로서 사용하는 목록 아이템 속성을 지정하는 PropertyDescriptor 개체와 목록을 올림차순으로 정렬할지 내림차순으로 정렬할지 지정하는 ListSortDescription 열거형을 인자로 받습니다.

다음의 코드에서는 선택한 속성에 의해서 IComparable 인터페이스가 구현 된 경우에만, 목록을 정렬할 수 있습니다. 이 인터페이스에서는 CompareTo 메서드가 제공됩니다. 문자열, 정수, DateTime 형식 등, 단순한 대부분의 형식에서는 IComparable 인터페이스가 구현 됩니다. Employee 개체의 모든 속성이 단순한 형식이므로, 이와 같습니다.  또, 이 구현에서는 단순한 형식이 아닌 속성으로 데이터 소스를 정렬했을 경우에 통지하는 단순한 오류 처리기능이 제공됩니다.

다음의 코드에서는 정렬 전의 목록의 복사가 RemoveSortCore 메서드로 사용할 수 있도록 보존됩니다. 또한 지정한 속성의 값이 ArrayList 에 복사됩니다. ArrayList Sort 메서드의 호출을 합니다. 그 결과, 배열 멤버의 CompareTo 메서드가 호출됩니다. 또, 정렬 후의 배열내의 값을 사용하고, 일반 BindingList 값이 올림차순 또는 내림차순의 한쪽에 정리됩니다. 마지막으로, 목록이 재설정 된 것을 보여주는 ListChanged 이벤트가 발생해 바인드 된 제어로 목록 값이 업데이트됩니다. 다음 코드는 정렬 기능의 구현을 보여줍니다.

ListSortDirection sortDirectionValue;
PropertyDescriptor sortPropertyValue;

protected override void ApplySortCore(PropertyDescriptor prop, 
    ListSortDirection direction)
{
    sortedList = new ArrayList();

    // Check to see if the property type we are sorting by implements
    // the IComparable interface.
    Type interfaceType = prop.PropertyType.GetInterface("IComparable");

    if (interfaceType != null)
    {
        // If so, set the SortPropertyValue and SortDirectionValue.
        sortPropertyValue = prop;
        sortDirectionValue = direction;

        unsortedItems = new ArrayList(this.Count);

        // Loop through each item, adding it the the sortedItems ArrayList.
        foreach (Object item in this.Items) {
            sortedList.Add(prop.GetValue(item));
            unsortedItems.Add(item);
        }
        // Call Sort on the ArrayList.
        sortedList.Sort();
        T temp;

        // Check the sort direction and then copy the sorted items
        // back into the list.
        if (direction == ListSortDirection.Descending)
            sortedList.Reverse();

        for (int i = 0; i < this.Count; i++)
        {
            int position = Find(prop.Name, sortedList[i]);
            if (position != i) {
                temp = this[i];
                this[i] = this[position];
                this[position] = temp;
            }
        }

        isSortedValue = true;

        // Raise the ListChanged event so bound controls refresh their
        // values.
        OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
    }
    else
        // If the property type does not implement IComparable, let the user
        // know.
        throw new NotSupportedException("Cannot sort by " + prop.Name +
            ". This" + prop.PropertyType.ToString() + 
            " does not implement IComparable");
}
정렬 해제

다음의 순서에서는 RemoveSortCore 메서드를 오버라이드(override) 합니다. RemoveSortCore 메서드는 목록에 마지막으로 적용된 정렬를 해제하고, ListChanged 이벤트를 호출하고, 목록이 재설정 된 것을 보여줍니다. RemoveSort 메서드는 정렬 해제 기능을 공개합니다.

protected override void RemoveSortCore()
{
    int position;
    object temp;
    // Ensure the list has been sorted.
    if (unsortedItems != null)
    {
        // Loop through the unsorted items and reorder the
        // list per the unsorted list.
        for (int i = 0; i < unsortedItems.Count; )
        {
            position = this.Find("LastName", 
                unsortedItems[i].GetType().
                GetProperty("LastName").GetValue(unsortedItems[i], null));
            if (position > 0 && position != i)
            {
                temp = this[i];
                this[i] = this[position];
                this[position] = (T)temp;
                i++;
            }
            else if (position == i)
                i++;
            else
                // If an item in the unsorted list no longer exists,
                // delete it.
                unsortedItems.RemoveAt(i);
        }
        isSortedValue = false;
        OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
    }
}

public void RemoveSort()
{
    RemoveSortCore();
}
정렬 방향 및 속성 공개

다음에, 보호되는 SortDirectionCore 및 SortPropertyCore 속성을 오버라이드(override) 합니다. SortDirectionCore 속성은 올림차순 또는 내림차순의 몇가지 정렬 방향을 보여줍니다. SortPropertyCore 속성은 목록이 정렬에 사용되는 속성을 설명하는 것을 보여줍니다.

ListSortDirection sortDirectionValue;
PropertyDescriptor sortPropertyValue;

protected override PropertyDescriptor SortPropertyCore
{
    get { return sortPropertyValue; }
}

protected override ListSortDirection SortDirectionCore
{
    get { return sortDirectionValue; }
}
정렬 기능 공개

이 코드 샘플에서는 Employees 의 사용자 지정 일반 BindingList (SortableSearchableList)를 DataGridView 컨트롤을 바인드 합니다. DataGridView 컨트롤은 정렬 기능이 구현되어 있는지 검색 합니다. 정렬은 구현되어 있으므로, DataGridView 열을 클릭하면, DataGridView 내용이 그 열의 내용에 의해 올림차순으로 정렬할 수 있습니다. 사용자는 열을 한번 더 클릭하고, 아이템을 내림차순으로 정렬할 수 있습니다. DataGridView는 IBindingList 인터페이스를 통해 목록의 호출을 실행합니다.

검색코드와 같이, ApplySortCore 를 호출하는 퍼블릭 메서드를 필요에 따라서 공개할 수 있습니다. 또는 DataGridView 컨트롤과 같이, 기본으로 되는 IBindingList  호출을 실행할 수도 있습니다.

((IBindingList)employees).ApplySort(somePropertyDescriptor,
    ListSortDirection.Ascending);
목록에 추가된 아이템 정렬

Employee 개체에서는 기본값의 생성자가 공개되므로, BindingList 의 AllowNew 속성은 true 를 돌려줍니다. 이것에 의해, 사용자는 새로운 직원을 목록에 추가할 수 있습니다. 새로운 아이템을 추가할 수 있도록 한 후, 목록에 추가된 아이템이 정렬할 수 있도록 (정렬이 적용되는 경우) 할 수도 있습니다. 이것을 실행하기 위해서 EndNew 메서드를 오버라이드(override) 했습니다. 이 메서드 오버라이드(override)에서는 SortPropertyValue 가 null 이외의 값인 것을 확인하여 목록을 정렬하는 것을 것을 체크합니다. 또, 목록의 마지막에 새로운 아이템이 추가되어 있는지 체크해 (목록의 재정렬이 필요한 것을 보여줌), 다음에 목록으로 ApplySortCore 를 호출합니다.

public override void EndNew(int itemIndex)
{
    // Check to see if the item is added to the end of the list,
    // and if so, re-sort the list.
    if (sortPropertyValue != null && itemIndex == this.Count - 1)
        ApplySortCore(this.sortPropertyValue, this.sortDirectionValue);

    base.EndNew(itemIndex);
}

그림 2 에서, 실행중에 정렬 기능을 보여줍니다. DataGridView 열을 클릭하면, 그 내용을 정렬할 수 있습니다. [Remove sort] 버튼을 클릭하면, 마지막에 적용된 정렬이 해제됩니다.

그림 2. 일반 BindingList 를 사용해 구현 된 정렬 기능

다음 단계

지금까지 채택해 온 코드는 일반 BindingList 에 대한 검색 기능 및 정렬 기능의 구현방법이었습니다. 이 코드 샘플에서 사용한 정렬 알고리즘은 IComparable 인터페이스를 구현하는 형식에 따라서 다릅니다. IComparable 인터페이스를 구현하지 않는 속성에 의해 정렬를 실행하려면, 예외로 처리됩니다. 속성이 주로 단순한 형식인 사용자 지정 비즈니스 개체를 정렬하는 경우는 이것으로 충분합니다. 사용자 지정 비즈니스 개체의 속성이 복잡한 형식인 경우는 이 코드 샘플로 한층 더 향상된 기능을 구현하기 위해서 IComparable 인터페이스 구현을 검토해야 합니다. 예를 들어,Employee 개체에 복잡한 형식 Address 의 Address 속성이 있는 경우는 Address 형식을 정렬하기 위한 비즈니스 규칙을 결정하여 Address 형식에 대해 IComparable 인터페이스와 CompareTo 메서드를 구현합니다.

또, 새로운 아이템이 목록의 마지막에 추가되었을 경우, 목록은 자동적으로 다시 정렬할 수 있습니다. 응용 프로그램의 기본 비즈니스 로직에 따라, 아이템이 추가된 장소에 관계없이 목록을 다시 정렬하는 것을 검토하길 바랍니다.

또, 데이터 소스에 필터 설정 기능이나 복수열 정렬 기능을 추가할 수도 있습니다. 그 경우는 데이터 소스에 IBindingListView 인터페이스를 구현하는 것을 검토하길 바랍니다.

요약

BindingSource 구성요소는 Windows Forms 데이터 바인드 시나리오로 매우 높은 효과를 발휘합니다. 그러나, 사용자 지정 비즈니스 개체의 목록을 처리하는 경우는 검색 기능 및 정렬 기능을 추가해야 할 경우도 있습니다. 새로운 일반 BindingList를 사용하면, 검색 및 정렬이 가능한 사용자 지정 비즈니스 개체의 바인드 목록을 간단하게 작성할 수 있습니다. Windows Forms의 BindingList 및 그 외의 기능의 자세한 내용은 다음을 참조해 주세요.

        private void TestForm_Load(object sender, EventArgs e)
        {
            //걍 일반적인 데이터 소스
            Client.Module.PersonnelManagement.Personnel.PersonnelManager pm 
                = new Client.Module.PersonnelManagement.Personnel.PersonnelManager();
            Contract.Data.CustomData.ParentsPersonnelData pp = pm.GetPersonnel(32);
            

            //바인딩 생성 value 속성에 CreateDate 필드값을 대입할꺼임 ㅋ
            Binding bd = new Binding("Value", pp.Personnel, "CreateDate");           
           
            bd.Format += new ConvertEventHandler(bd_Format);
            bd.Parse += new ConvertEventHandler(bd_Parse);
			//컨트롤과 바인딩 연결
            this.dtPlaceJoinDate.DataBindings.Add(bd);
            
        }

        void bd_Parse(object sender, ConvertEventArgs e)
        {
            //컨트롤에서 값 받아올때
            string s = e.Value.ToString();
        }

        void bd_Format(object sender, ConvertEventArgs e)
        {
            //바인딩에서 컨트롤로 나갈때
            string s = e.Value.ToString();
        }

클래스나 구조체, 인터페이스 또는 메서드의 정의를 둘 이상의 소스 파일로 분할할 할때 사용

대규모 프로젝트 등에서 여러명이 작업할때 사용하면 좋다

아래보면 CoOrds 라는 클래스 명이 같다 하지만 Partial 선언해서 사용할수 있다

public partial class CoOrds
{
    private int x;
    private int y;

    public CoOrds(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

public partial class CoOrds
{
    public void PrintCoOrds()
    {
        System.Console.WriteLine("CoOrds: {0},{1}", x, y);
    }

}

class TestCoOrds
{
    static void Main()
    {
        CoOrds myCoOrds = new CoOrds(10, 15);
        myCoOrds.PrintCoOrds();
    }
}

+ Recent posts