====== 컬렉션 ====== Data Collection에서 사용 가능한 컬렉션의 종류를 설명합니다. ===== 용어의 정의 ===== 여기서는 필드와 속성을 모두 합쳐서 멤버(Member)라 정의합니다. 함수를 메서드라 부르고 List, Dictionary와 같은 데이터 형식을 컬렉션으로 부르기도 합니다. ===== 계층 구조 ===== 최상위 계층인 ''TypeMapper'' 클래스를 상속받아 ''NotifyList'' 컬렉션을 구현하였고 이 컬렉션을 기반으로 ''DataList'' 와 ''VirtualList'' 컬렉션을 구현하였습니다. 이러한 관계의 Class Diagram은 다음과 같습니다. {{:product:povice:632db341f528d770bdf766c713fc971f.png}} [그림 1] DataList와 VirtualList의 Class Diagram ===== NotifyList ===== NotifyList는 컬렉션에서 항목이 추가되거나 제거가 되었을 때 혹은, 항목의 값이 변경되었을 때 알림을 받을 수 있는 컬렉션입니다. ==== 멤버(Member) ==== * **this[int] : T** * 지정한 인덱스에 있는 요소를 가져오거나 설정합니다. * **Count : int** * NotifyList에 실제로 포함된 요소의 수를 가져옵니다. * **InitInProgress : bool** * ISupportInitialize 인터페이스에 의해 BeginInit() 메서드가 호출되었는지 여부를 가져옵니다. * **ItemType : Type** * 항목의 형식을 가져옵니다. * **Members : MemberCollection** * 정의한 형식 멤버들에 대한 컬렉션을 가져옵니다. * **ReadOnly : bool** * NotifyList가 읽기 전용인지 여부를 나타내는 값을 가져오거나 설정합니다. 기본값은 false입니다. ==== 메서드(Method) ==== * **Add(T) : void** * 개체를 NotifyList의 끝 부분에 추가합니다. * **AddRange(IEnumerable) : void** * 지정된 컬렉션의 항목을 NotifyList의 끝에 추가합니다. * **ApplyRange(IEnumerable) : void** * 다시 적용하기위해 기존 항목들을 지우고 지정된 컬렉션의 항목을 NotifyList에 추가합니다. * **BeginInit() : void** * 초기화가 시작됨을 개체에 알립니다. * **Clear() : void** * NotifyList에서 요소를 모두 제거합니다. * **Contains(T) : bool** * NotifyList에 요소가 있는지 여부를 확인합니다. * **CreateItem(params object[]) : object** * ItemType 속성값에 해당하는 형식을 생성합니다. * **CopyTo(T[], int) : void** * 현재 1차원 배열의 모든 요소를 지정된 1차원 배열에 복사합니다. * **EndInit() : void** * 초기화가 완료됨을 개체에 알립니다. * **GenerateCode() : string** * 형식 정보를 사용하여 클래스 구현 코드를 생성합니다. * **GetRange(int, int) : IList** * 소스 NotifyList에 있는 일련의 항목에 대한 단순 복사본을 만듭니다. * **IndexOf(T) : int** * NotifyList에서 특정 항목의 인덱스를 결정합니다. * **Insert(int, T) : void** * 항목을 NotifyList의 지정된 인덱스에 삽입합니다. * **Remove(T) : bool** * NotifyList에서 맨 처음 발견되는 특정 개체를 제거합니다. * **RemoveAt(int) : void** * NotifyList에서 지정한 인덱스의 항목을 제거합니다. * **RemoveRange(int, int) : void** * NotifyList에서 항목의 범위를 제거합니다. ==== 이벤트(Event) ==== * **AsyncCollectionChanged : NotifyCollectionChangedEventHandler** * 비동기로 컬렉션이 변경될 때 발생합니다. * **CollectionChanged : NotifyCollectionChangedEventHandler** * 컬렉션이 변경될 때 발생합니다. * **ValueChanged : EventHandler** * 멤버의 값이 변경되면 발생합니다. === 이벤트 발생 조건 === 기본적으로는 ''CollectionChanged'' 이벤트와 ''ValueChanged'' 이벤트가 발생합니다. 그리고, 값이 변경될 때 알림을 받을 수 있는 조건은 몇가지가 존재하며 그 조건이 만족되면 ValueChanged 이벤트가 발생합니다. 아래는 해당조건입니다. * NotifyList 사용 * NotifyList.Members[i].SetValue() 메서드를 사용 할 것 * 클래스 선언 시 INotifyValueChanged 인터페이스를 상속 받아 구현 할 것 **NotifyList** NotifyList 컬렉션은 Member를 직접 추가하거나 삭제할 수 있습니다. Member에 해당하는 값을 수정하면 ValueChanged 이벤트가 발생합니다. GenerateCode() 메서드를 호출하면 NotifyList 컬렉션에서 생성된 Member 정보를 사용하여 아래와 유사한 클래스 구조의 코드를 생성합니다. #region ClassName /// /// 클래스를 정의합니다. /// public class ClassName { /// RegionID 입니다. public long RegionID; /// RegionDescription 입니다. public string RegionDescription; } #endregion **NotifyList.Members[i].SetValue() 메서드** T 타입에 상관없이 SetValue() 메서드를 사용하면 ValueChanged 이벤트가 항상 발생합니다. **INotifyValueChanged 인터페이스 상속** 클래스를 선언할 때 INotifyValueChanged 인터페이스를 상속받고 속성 값이 변경될 때 ValueChanged 이벤트를 호출해주는 패턴을 구현합니다. 아래는 구현 방법입니다. /// /// INotifyValueChanged 인터페이스를 사용하는 예제입니다. /// public class TestClass : INotifyValueChanged { /// /// 멤버의 값이 변경될 때 발생합니다. /// public event EventHandler ValueChanged; /// /// ID 값입니다. /// string id; /// /// ID 값을 가져오거나 설정합니다. /// public string Id { get => this.id; set { var oldValue = this.id; this.id = value; // 변경 후 이벤트를 호출합니다. this.ValueChanged?.Invoke(this, new ValueChangedEventArgs(this, nameof(Id), value, oldValue)); } } } ==== LINQ 지원 ==== 다음과 같이 LINQ 구문이 사용 가능합니다. var enumerable = from item in notifyList where item.Category == "Category1" select item; ===== DataList ===== ''NotifyList'' 컬렉션을 상속받아 구현되었고 UI 컨트롤에 바인딩이 가능하도록 설계되었습니다. NotifyList 컬렉션에서 데이터를 필터링하는 기능과 정렬하는 기능이 포함되었습니다. ==== 멤버(Member) ==== * **this[int] : T** * 지정한 인덱스에 있는 요소를 가져오거나 설정합니다. * **Count : int** * DataList에 실제로 포함된 요소의 수를 가져옵니다. * **Filters : FilterCollection** * 필터의 컬렉션을 가져옵니다. 설정되지 않았을 경우 Count가 0입니다. * **InitInProgress : bool** * ISupportInitialize 인터페이스에 의해 BeginInit() 메서드가 호출되었는지 여부를 가져옵니다. * **ItemType : Type** * 항목의 형식을 가져옵니다. * **Members : MemberCollection** * 정의한 형식 멤버들에 대한 컬렉션을 가져옵니다. * **ReadOnly : bool** * DataList가 읽기 전용인지 여부를 나타내는 값을 가져오거나 설정합니다. 기본값은 false입니다. * **Sorts : SortCollection** * 정렬의 컬렉션을 가져옵니다. 설정되지 않았을 경우 Count가 0입니다. ==== 메서드(Method) ==== * **Add(T) : void** * 개체를 DataList의 끝 부분에 추가합니다. * **AddRange(IEnumerable) : void** * 지정된 컬렉션의 항목을 DataList의 끝에 추가합니다. * **ApplyRange(IEnumerable) : void** * 다시 적용하기위해 기존 항목들을 지우고 지정된 컬렉션의 항목을 DataList에 추가합니다. * **BeginInit() : void** * 초기화가 시작됨을 개체에 알립니다. * **Clear() : void** * DataList에서 요소를 모두 제거합니다. * **Contains(T) : bool** * DataList에 요소가 있는지 여부를 확인합니다. * **CreateItem(params object[]) : object** * ItemType 속성값에 해당하는 형식을 생성합니다. * **CopyTo(T[], int) : void** * 현재 1차원 배열의 모든 요소를 지정된 1차원 배열에 복사합니다. * **EndInit() : void** * 초기화가 완료됨을 개체에 알립니다. * **Find(string, object) : int** * 컬렉션에서 멤버 이름과 값이 일치하는 항목의 인덱스를 반환합니다. * **GenerateCode() : string** * 형식 정보를 사용하여 클래스 구현 코드를 생성합니다. * **GetRange(int, int) : IList** * 소스 DataList에 있는 일련의 항목에 대한 단순 복사본을 만듭니다. * **IndexOf(T) : int** * DataList에서 특정 항목의 인덱스를 결정합니다. * **Insert(int, T) : void** * 항목을 DataList의 지정된 인덱스에 삽입합니다. * **Remove(T) : bool** * DataList에서 맨 처음 발견되는 특정 개체를 제거합니다. * **RemoveAt(int) : void** * DataList에서 지정한 인덱스의 항목을 제거합니다. * **RemoveRange(int, int) : void** * DataList에서 항목의 범위를 제거합니다. * **SetValue(object, string, object) : void** * 항목의 값을 변경합니다. 변경된 후에 ValueChanged 이벤트가 발생합니다. ==== 이벤트(Event) ==== * **AsyncCollectionChanged : NotifyCollectionChangedEventHandler** * 비동기로 컬렉션이 변경될 때 발생합니다. * **CollectionChanged : NotifyCollectionChangedEventHandler** * 컬렉션이 변경될 때 발생합니다. * **ValueChanged : EventHandler** * 멤버의 값이 변경되면 발생합니다. ==== 필터(Filter) ==== 필터 기능을 위해 ''Filters'' 컬렉션 속성을 사용하며, 사용 방법은 아래와 같습니다. Add() 메서드를 사용하여 필터를 여러 번 추가하면, 필터 적용이 여러 번 수행되어 성능이 저하될 수 있습니다. 이럴 경우, AddRange() 메서드를 사용하여 2개 이상의 필터 조건을 한 번에 적용하는 것을 고려해야 합니다. dataList.Filters.Add("rowid", RelationalOperator.LessThanOrEqual, 1000); ==== 정렬(Sort) ==== 정렬 기능을 위해 ''Sorts'' 컬렉션 속성을 사용하며, 사용 방법은 아래와 같습니다. 필터와 동일하게 Add() 메서드를 사용하여 정렬을 여러 번 추가하면, 정렬 적용이 여러번 수행되어 성능이 저하될 수 있습니다. 이럴 경우, AddRange() 메서드를 사용하여 2개 이상의 정렬 조건을 한 번에 적용하는 것을 고려해야 합니다. dataList.Sorts.Add("rowid", ListSortDirection.Descending); ===== VirtualList ===== 데이터베이스의 테이블의 항목이 추가 또는 제거되거나 전체 목록이 새로 고쳐질 때 알림을 제공하는 동적 데이터 컬렉션을 나타냅니다. VirtualList는 다음과 같은 특징을 가지고 있습니다. * 대용량 처리를 위해 데이터는 RDB에 적재하고 사용할 때는 필요한 부분만 가져옵니다. * In-memory, Caching, Dynamic Query 최적화를 통해 기본 성능을 향상시킵니다. * 전체 데이터를 검색할 경우 성능을 위해 foreach를 사용하여야 합니다. **선언 방법** 기본적인 선언 방법은 다음과 같습니다. var virtualList = new VirtualList("TableName", "SQLite"); ==== 멤버(Member) ==== * **this[int] : T** * 지정한 인덱스에 있는 요소를 가져오거나 설정합니다. * **ConnectionName : string** * 연결 이름을 가져옵니다. * **Count : int** * VirtualList에 실제로 포함된 요소의 수를 가져옵니다. * **Filters : FilterCollection** * 필터의 컬렉션을 가져옵니다. 설정되지 않았을 경우 Count가 0입니다. * **InitInProgress : bool** * ISupportInitialize 인터페이스에 의해 BeginInit() 메서드가 호출되었는지 여부를 가져옵니다. * **ItemIdColumnName : string** * 항목 ID 값을 가지는 컬럼 이름을 가져오거나 설정합니다. * **ItemType : Type** * 항목의 형식을 가져옵니다. * **Members : MemberCollection** * 정의한 형식 멤버들에 대한 컬렉션을 가져옵니다. * **ReadOnly : bool** * VirtualList가 읽기 전용인지 여부를 나타내는 값을 가져오거나 설정합니다. 기본값은 false입니다. * **Sorts : SortCollection** * 정렬의 컬렉션을 가져옵니다. 설정되지 않았을 경우 Count가 0입니다. * **TableName : string** * 테이블 이름을 가져옵니다. ==== 메서드(Method) ==== * **Add(T) : void** * 개체를 VirtualList의 끝 부분에 추가합니다. * **AddRange(IEnumerable) : void** * 지정된 컬렉션의 항목을 VirtualList의 끝에 추가합니다. * **ApplyRange(IEnumerable) : void** * 다시 적용하기위해 기존 항목들을 지우고 지정된 컬렉션의 항목을 VirtualList에 추가합니다. * **BeginInit() : void** * 초기화가 시작됨을 개체에 알립니다. * **Clear() : void** * DataList에서 요소를 모두 제거합니다. * **Contains(T) : bool** * DataList에 요소가 있는지 여부를 확인합니다. * **CreateItem(params object[]) : object** * ItemType 속성값에 해당하는 형식을 생성합니다. * **CopyTo(T[], int) : void** * 현재 1차원 배열의 모든 요소를 지정된 1차원 배열에 복사합니다. * **EndInit() : void** * 초기화가 완료됨을 개체에 알립니다. * **Find(string, object) : int** * 컬렉션에서 멤버 이름과 값이 일치하는 항목의 인덱스를 반환합니다. * **GenerateCode() : string** * 형식 정보를 사용하여 클래스 구현 코드를 생성합니다. * **GetRange(int, int) : IList** * 소스 VirtualList에 있는 일련의 항목에 대한 단순 복사본을 만듭니다. * **IndexOf(T) : int** * VirtualList에서 특정 항목의 인덱스를 결정합니다. * **Remove(T) : bool** * VirtualList에서 맨 처음 발견되는 특정 개체를 제거합니다. * **RemoveAt(int) : void** * VirtualList에서 지정한 인덱스의 항목을 제거합니다. * **RemoveRange(int, int) : void** * VirtualList에서 항목의 범위를 제거합니다. * **SetValue(object, string, object) : void** * 항목의 값을 변경합니다. 변경된 후에 ValueChanged 이벤트가 발생합니다. ==== 이벤트(Event) ==== * **AsyncCollectionChanged : NotifyCollectionChangedEventHandler** * 비동기로 컬렉션이 변경될 때 발생합니다. * **CollectionChanged : NotifyCollectionChangedEventHandler** * 컬렉션이 변경될 때 발생합니다. * **ValueChanged : EventHandler** * 멤버의 값이 변경되면 발생합니다. ==== 필터(Filter) ==== 필터 기능을 위해 ''Filters'' 컬렉션 속성을 사용하며, 사용 방법은 아래와 같습니다. DataList 컬렉션과 다르게 Add() 메서드를 사용하여 필터 조건을** 여러 번 추가하여도 성능에 영향을 받지 않습니다**. VirtualList 컬렉션은 필터 적용 후 실제 사용 시점에 데이터를 쿼리하기 떄문입니다. virtualList.Filters.Add("rowid", RelationalOperator.LessThanOrEqual, 1000); // 필터 적용 후 아래와 같이 실제 사용 시점에 쿼리 후 데이터를 가져옵니다. var item = virtualList[2]; ==== 정렬(Sort) ==== 정렬 기능을 위해 ''Sorts'' 컬렉션 속성을 사용하며, 사용 방법은 아래와 같습니다. DataList 컬렉션과 다르게 Add() 메서드를 사용하여 정렬 조건을 **여러 번 추가하여도 성능에 영향을 받지 않습니다**. VirtualList 컬렉션은 정렬 적용 후 실제 사용 시점에 데이터를 쿼리하기 떄문입니다. virtualList.Sorts.Add("rowid", ListSortDirection.Descending); // 정렬 적용 후 아래와 같이 실제 사용 시점에 쿼리 후 데이터를 가져옵니다. var item = virtualList[2];