문자열 리스트를 그리드에 바인딩하기

[제목] 문자열 리스트를 그리드에 바인딩하기

문자열 리스트(혹은 문자열 배열)를 DataGridView 와 같은 그리드에 데이타 바인딩할 경우 흔히 다음과 같이 코딩할 수 있다.

var nameList = new List { "Tim", "Irina", "John" };
dataGridView1.DataSource = nameList;

언뜻 큰 문제가 없어 보이지만, 위의 코드는 문자열을 출력하는 대신 다음과 같이 문자열의 길이를 출력한다.

이것의 이유는 DataGridView.DataSource에 문자열 리스트가 설정될 경우, DataGridView는 DataMember를 체크하고 아무 지정이 없으면 디폴트로 첫번째 Public Property를 사용해서 데이타를 출력하기 때문이다. String 클래스의 경우, Property가 Length 라는 속성 하나만 존재하기 때문에 문자열의 길이를 출력하는 것이다.

이것을 Fix 하기 위해 다음과 같이 고쳐 쓸 수 있다.

// Read only
dataGridView1.DataSource = nameList.Select(p => new { Value = p }).ToList();

위의 코드는 원래의 문자열 리스트를 LINQ를 사용하여 변형한 것으로, 문자열 하나 하나를 받아들여 Value 라는 속성을 하나 갖는 새로운 익명 타입으로 Wrapping하여 변형하는 것이다. 이렇게 변형된 익명 타입 객체들을 다시 ToList()를 사용해 리스트로 만들어져 그리드의 DataSource에 할당된다. 이 코드는 매우 단순하게 문자열 리스트 바인딩의 문제점을 해결할 수 있다. 만약 데이타를 단순히 그리드에 표시하고 수정하지 않는다면, 쉽고 간편한 방식으로 볼 수 있다. 하지만, 만약 사용자가 그리드의 내용을 수정해야 한다면, 위의 방식을 사용할 수 없다.

그리드에서 수정이 가능하도록 만들려면, 아래와 같이 별도의 StringWrapper 클래스를 만들어 사용할 수 있다. 이 클래스는 문자열을 받아들여 Value 라는 속성에 지정하고, 그 속성에 get 과 set을 구현하고 있다.

class StringWrapper
{        
    public StringWrapper(string s)
    {
        Value = s;
    }
    public string Value { get; set; }
}

위의 클래스를 활용하여 다음과 같이 리스트를 만들고 바인딩을 할 수 있다.

nameList = new List();
nameList.Add(new StringWrapper("Tim"));
nameList.Add(new StringWrapper("Irina"));
nameList.Add(new StringWrapper("John"));            
dataGridView1.DataSource = nameList;

이렇게 바인딩을 하면 그리드의 변경 내용이 바인딩 소스 즉 nameList 컬렉션에 반영되게 된다. 이러한 바인딩은 UI에서 데이타 소스에 변경이 적용되는 One-way 바인딩이다.

만약 Two-way 바인딩을 구현해야 한다면, StringWrapper 클래스에 INotifyPropertyChanged 인터페이스를 구현하고, nameList를 List가 아닌 BindingList로 변경하면 된다.

// INotifyPropertyChanged 를 구현
class StringWrapper : INotifyPropertyChanged
{
    private string val; 
    public event PropertyChangedEventHandler PropertyChanged;

    public StringWrapper2(string s)
    {
        val = s;
    }
    public string Value
    {
        get
        {
            return val;
        }
        set 
        {
            val = value;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, null);
            }
        }
    }           
}

// 데이타소스를 BindingList 로
var nameList = new BindingList();



본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.