How to: Sort ListView Items

How to: Sort ListView Items
http://msdn.microsoft.com/en-us/library/ms229643(VS.80).aspx

class ListViewItemComparer : IComparer
{
private int column;
public ListViewItemComparer() : this(0) {}
public ListViewItemComparer(int column)
{
this.column = column;
}

public int Compare(object x, object y) // string compare
{
return String.Compare(((ListViewItem)x).SubItems[column].Text,
((ListViewItem)y).SubItems[column].Text);
}
}

/////
public partial class Form1 : Form
{
[…]
private void listView1_ColumnClick(object sender, ColumnClickEventArgs e)
{

// Set the column number that is to be sorted; default to ascending.
this.listView1.ListViewItemSorter = new ListViewItemComparer(e.Column);

// Perform the sort with these new sort options.
this.listView1.Sort();
}
}

Generic List Class Sort Method

public void Sort(Comparison<T> comparison)
http://msdn.microsoft.com/en-us/library/w56d4y5z.aspx

List<Person> pList = new List<Person>();
pList.Sort(ComparePersonByID); // pList를 ID로 정렬하기

[…]
public class Person : IComparable<Person>
{
public static Comparison<Person> ComparePersonByID =
delegate(Person p1, Person p2)
{
return p1.ID.CompareTo(p2.ID);
};

[…]
}

pList.Sort(ComparePersonByID); // pList를 ID로 정렬하기 (Comparison delegate)

public class Person : IComparable<Person>
{
public static Comparison<Person> ComparePersonByID =
delegate(Person p1, Person p2)
{
return p1.ID.CompareTo(p2.ID);
};

[…]
}

pList.Sort(new PersonIDComparer()); // pList를 ID로 정렬하기 (IComparer)

public class PersonIDComparer : IComparer<Person>
{
public int Compare(Person p1, Person p2)
{
return p1.ID.CompareTo(p2.ID);
}
}

pList.Sort((p, q) => p.ID.CompareTo(q.ID)); // pList를 ID로 정렬하기 (lambda)

HW3

HW3

단국대학교 멀티미디어공학과 HCI프로그래밍2 (2016년 가을학기) 실습
과목코드 : 300890
강사 : 박경신
——————————————————————
날짜: 2016년 10월 31일
– 실습번호 : HW3 (Due by 11/21)
– 실습제목 : collections, FileIO, GUI
– 실습요약 : 입체 도형의 겉넓이(surface area)와 부피(volume) 구하기 GUI 작성
– 준비자료 : HW1 http://www.mathsisfun.com/area-calculation-tool.html
http://math.about.com/od/formulas/ss/surfaceareavol.htm

11/21까지 online.dankook.ac.kr 이러닝으로 실행파일(bin\*.exe)과 소스코드(*.cs)와 보고서(*.doc/*.hwp)를 전부 “학번_이름_HW3.zip”으로 묶어서 제출한다. 또한, 비주얼 스튜디오에서 만든 프로젝트 전체 파일(*.sln, *.csproj)을 폴더에 같이 넣어준다. 보고서는 출력해서 수업시간에 제출한다.

– 실습문제

1. Geometry 추상클래스를 정의한다.

2. Geometry 추상클래스를 상속받은 Sphere, Cone, Cylinder, … 는 겉넓이(Surface Area), 부피(Volume)를 계산한다.

3. GeometryForm 를 구현하고 입체도형의 겉넓이와 부피 계산을 구현한다.
-ComboBox, Label, TextBox, Button, Panel을 사용하여 GUI를 정의한다.
-Geometry 객체를 생성해서 텍스트필드에서 입력받은 값으로 SurfaceArea와 Volume을 계산하여 화면에 출력한다.

4. MainForm은 List<Geometry>를 관리한다.
-Listview을 사용하여 Geometry 리스트를 출력한다.
-File I/O을 사용하여 Geometry 리스트를 관리한다.

5. 사용자의 잘못된 입력에 따른 처리를 반드시 포함해야 하며, 그 외에 본인이 더 테스트해보고 싶은 method나 routine을 추가하라. 실행 화면과 코드를 첨부하시오.

GeometryForm

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GeometryForm
{
public abstract class Geometry
{
public abstract GeometryType Type { get; }
public abstract double SurfaceArea { get; }
public abstract double Volume { get; }
public void Print()
{
System.Diagnostics.Trace.WriteLine
(ToString() + ” S.A.=” + SurfaceArea + ” Vol=” + Volume);
}
// needed for ListView
#region ListViewItem
public ListViewItem ToListViewItem()
{
ListViewItem item = new ListViewItem(this.ToString());
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, string.Format(“{0:0.###}”, this.SurfaceArea)));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, string.Format(“{0:0.###}”, this.Volume)));
return item;
}
#endregion
}
}

TRACE macro

TRACE macro
-윈도우 응용프로그램 개발시 Visual Studio IDE의 Output Window (출력창)에 Debug하는 내용을 출력하고자 할 때System.Diagnostics.Trace.WriteLine(…..)을 사용
-기존의 C# Console 응용프로그램에서 System.Console.WriteLine(….)와 동일
-기존의 MFC 윈도우 프로그래밍에서 TRACE 매크로와 비슷 (C의 printf와 동일한 형식 지원)
-기존의 WIN32 윈도우 프로그래밍에서 OutputDebugString 함수와 같은 기능 (C의 printf와 동일한 형식 지원)

Windows Forms Application

.NET2015

  • 메뉴에서 File->New->Project->Visual C# 템플릿->Windows Forms Application를 선택한 후 “프로젝트 이름(예를 들어, WindowFormHello)”을 적고 확인버튼을 누르면 빈폼 프로젝트가 생성된다.
 form1
 form2

컨트롤 코드 추가

  • Toolbox(도구상자) 에서 컨트롤을 선택(예를 들어, Label 또는 Button)하여 Dialog기반의 Form1 안에 추가하여 편집한다.
 form3

컨트롤에 이벤트 추가하기
-컨트롤 (예를들어, 버튼을 더블클릭하면 또는 이벤트목록중 Click이벤트에 더블클릭하면)에 클릭 이벤트에 대한 이벤트핸들러에 내용(예를 들어, 레이블의 Text를 “Button Clicked”)을 작성한다.
private void button1_Click(object sender, EventArgs e)
{

// button1을 클릭하면 label1 텍스트 변경

label1.text = “Button Clicked”;
// button1을 클릭하면 Form2 팝업

Form2 f = new Form2();

f.ShowDialog();
}

form8

폼 코드 추가

  • Project 에서 폼을 추가(Add New Item)하여 Form2 를 추가한다.

form5

form6

  • Toolbox(도구상자) 에서 컨트롤을 선택(예를 들어, Label 또는 Textbox)하여 Dialog기반의 Form2 안에 추가하여 편집한다.

form7

  • Form2 안에 코드를 추가한다.

form9

빌드(F7) 후 실행(F5)하기

Getting Started with Windows Forms

http://msdn.microsoft.com/en-us/library/ms229601(VS.80).aspx

  • Creating a New Windows Form
  • Creating Event Handlers in Windows Forms
  • Adjusting the Size and Scale of Windows Forms
  • Changing the Appearance of Windows Forms
  • Windows Forms Controls
  • User Input in Windows Forms
  • Dialog Boxes in Windows Forms
  • Windows Forms Data Binding
  • Windows Forms Security
  • ClickOnce Deployment for Windows Forms
  • How to: Access Keyed Collections in Windows Forms

LINQ

class Category
    {
        public string Name { get; set; }
        public int ID { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // The Three Parts of a LINQ Query:
            //  1. Data source.
            int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

            // 2. Query creation.
            // numQuery is an IEnumerable<int>
            var numQuery =
                from num in numbers
                where (num % 2) == 0
                select num;

            // 3. Query execution.
            foreach (int num in numQuery)
            {
                Console.Write(“{0,1} “, num);
            }
            Console.WriteLine();

            // LIST
            List<Person> pList = new List<Person>();
            pList.Add(new Person(“둘리”, 1, “123-4568-9012”, “대한민국”));
            pList.Add(new Person(“희동이”, 3, “000-0000-0000”, “서울”));
            pList.Add(new Person(“고길동”, 2, “000-0000-0000”, “서울”));
            pList.Add(new Person(“도우너”, 5, “000-0000-0000”, “온따빠야별”));
            pList.Add(new Person(“또치”, 4, “000-0000-0000”, “미국”));
            pList.Insert(2, new Person(“마이콜”, 6, “000-0000-0000”, “서울”));

            // query syntax

            IEnumerable<Person> seoulQuery =
                from per in pList
                where per.Address == “서울”
                select per;

            foreach (var per in seoulQuery)
            {
                Console.WriteLine(per.Name + “, ” + per.ID);
            }
            Console.WriteLine();

            // query syntax
            IEnumerable<Person> personQuery =
                from p in pList
                where (p.ID < 2) || (p.Address == “서울”)
                orderby p.Name ascending
                select p;

            foreach (var p in personQuery)
            {
                Console.WriteLine(p.Name + “, ” + p.ID);
            }
            Console.WriteLine();

            // method syntax
            IEnumerable<Person> personQuery2 = pList.Where(p => (p.ID < 2) || (p.Address == “서울”)).OrderBy(p => p);
            foreach (var p in personQuery2)
            {
                Console.WriteLine(p.Name + “, ” + p.ID);
            }
            Console.WriteLine();

            // JOIN
            List<Category> categories = new List<Category>()
            {
                new Category() { Name=”서울”, ID=1 },
                new Category() { Name=”대한민국”, ID=2 },
                new Category() { Name=”미국”, ID=3 },
                new Category() { Name=”온따빠야별”, ID=4 },
            };

            var query = from p in pList
                        join cat in categories on p.Address equals cat.Name
                        select new
                        {
                            p.Name,
                            p.Address,
                            cat.ID
                        };
            Console.WriteLine(“Join Query”);
            foreach (var q in query)
            {
                Console.WriteLine(q.Name + “, ” + q.Address + “, ” + q.ID);
            }
            Console.WriteLine();
        }
    }

 

 

// 결과

0 2 4 6
희동이, 3
마이콜, 6
고길동, 2

고길동, 2
둘리, 1
마이콜, 6
희동이, 3

고길동, 2
둘리, 1
마이콜, 6
희동이, 3

Join Query
둘리, 대한민국, 2
희동이, 서울, 1
마이콜, 서울, 1
고길동, 서울, 1
도우너, 온따빠야별, 4
또치, 미국, 3

Array.ConvertAll

https://msdn.microsoft.com/ko-kr/library/kt456a2y(v=vs.110).aspx

public delegate TOutput Converter<in TInput, out TOutput>(
TInput input
)

 static System.Drawing.Point Point2DrawingPoint(Point p)
{
     return (System.Drawing.Point)p;
}

static void Main(string[] args)
{

List<Point> Vertices = new List<Point>()
{
new Point() { X = 400, Y = 10 },
new Point() { X = 300, Y = 210 },
new Point() { X = 500, Y = 210 }
};

// 1. Lambda expression
System.Drawing.Point[] points1 = Array.ConvertAll(Vertices.ToArray(), x => (System.Drawing.Point)x); // Use with Point.cs type conversion operator overload

// 2. Anonymous method
System.Drawing.Point[] points2 = Array.ConvertAll(Vertices.ToArray(), delegate(Point x) { return (System.Drawing.Point)x; });

// 3. Delegate (Converter<TInput, TOutput>)
System.Drawing.Point[] points3 = Array.ConvertAll(Vertices.ToArray(), new Converter<Point, System.Drawing.Point>(Point2DrawingPoint));

foreach (var v in Vertices)
Console.WriteLine(v);
foreach (var p in points1)
Console.WriteLine(p);
foreach (var p in points2)
Console.WriteLine(p);
foreach (var p in points3)
Console.WriteLine(p);

}

COLLECTION, INTERFACE, DELEGATE

1. Collection 
서로 밀접하게 관련된 데이터를 그룹화하여 좀 더 효율적으로 처리할 수 있게 한 특수한 클래스 혹은 구조체이다.

 

2. Collection과 Interface
모든 닷넷 컬렉션은 ICollection<T> 인터페이스는 구현한다. 
IList<T> 인터페이스는 인덱스를 사용하여 요소에 개별적으로 접근할 수 있는 컬렉션을 정의한다.
-T this [int index] { get; set; } //지정한 인덱스에 있는 요소를 가져오거나 설정
-int IndexOf(T item) //IList에서 특정 항목의 인덱스를 확인
-void Insert(int index, T item) //항목을 IList의 지정한 인덱스에 삽입
-void RemoveAt(int index) //지정한 인덱스에서 IList 항목을 제거

 

3. Collection과 Method와 Delegate
// Person 클래스
public class Person
{
private readonly string _name;

 

public string Name
{
get { return _name; }
}

 

private readonly int _age;

 

public int Age
{
get { return _age; }
}

 

public Person(string name, int age)
{
_name = name;
_age = age;
}

 

public override string ToString()
{
return string.Format(“이름 : {0}\t나이 : {1}”, _name, _age);
}
}

 

// List<T> 컬렉션에 Person 객체를 담는다
private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));
}

 

// aList에 포함된 세 사람이 모두 10세 이상인지를 확인한다 => 둘리와 고길동만 만족함
private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));

 

bool result = true;
foreach (Person p in aList)
{
if (p.Age < 10)
{
result = false;
break;
}
}
}

 

// aList에 포함된 세 사람이 모두 이름이 두 글자인지를 확인한다 => 둘리만 만족함
private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));

 

bool result = true;
foreach (Person p in aList)
{
if (p.Name.Length != 2)
{
result = false;
break;
}
}
}

 

// 위의 두 코드가 나이가 10세이상인지 또는 이름이 두 글자인지 조건을 만족하는지를 확인하는 부분이 반복
// List<T> 컬렉션의 TrueForAll 메소드는 조건을 만족하는 메소드가 존재한다면 true반환
public delegate bool Predicate<T>(T item);

 

public class List<T> : …
{

 

public bool TrueForAll(Predicate<T> match)
{
bool result = true;
foreach (T item in this)
{
if (match(item) == false)
{
result = false;
break;
}
}
}
}

 

private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));

 

// 10살 이상인지를 검사
bool result1 = aList.TrueForAll(IsGreaterThanTen);

 

// 무명 대리자를 사용하여 이름이 두 글자인지 검사
bool result2 = aList.TrueForAll(delegate(Person p)
{ return p.Name.Length == 2; });
}

 

private static bool IsGreaterThanTen(Person p)
{
return p.Age >= 10;
}

4. List<T> 컬랙션 클래스의 메소드와 헬퍼 대리자

 

public List<TOutput> ConvertAll<TOutput> (Converter<T, TOutput> converter)
-리스트 객체의 각 원소를 TOutput 형으로 변환하여 리스트로 반환

 

public bool Exists(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 원소가 있는지 여부를 반환

 

public T Find(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 첫번째 원소를 반환

 

public List<T> FindAll(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 모든 원소를 리스트로 반환

 

public int FindIndex(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 첫번째 원소의 인덱스를 반환

 

public int FindLastIndex(Predicate<T> match)
-리스트에 있는 모든 원소 중 match 조건을 만족하는 마지막 원소의 인덱스를 반환

 

public void ForEach(Action<T> action)
-리스트에 있는 모든 원소에 대해 action을 수행

 

public bool TrueForAll(Predicate<T> match)
-리스트에 있는 모든 원소가 match 조건을 만족하는 지 여부를 반환

 

<<대리자(Delegate)>>

 

public delegate void Action<T>(T object)
-T 형의 매개변수를 하나 받고 반환값이 없는 메소드

 

public delegate TOutput Converter<TInput, TOutput>(TInput input)
-TInput 형의 매개변수를 받고 이를 TOutput 형으로 변환하여 반환하는 메소드

 

public delegate bool Predicate<T>(T object)
-T 형의 매개변수를 받아 그것이 특정 조건을 만족하는지를 반환하는 메소드

 

public delegate int Comparison<T>(T x, T y)
-x, y 두 객체를 비교하는 메소드로 x가 y보다 작으면 음수, 같으면 0, 크면 양수를 반환하는 메소드

 

5. List<T>의 Sort 메소드
public void Sort()
public void Sort(Comparison<T> comparison)
public void Sort(IComparer<T> comparer)
public void Sort(int index, int count, IComparer<T> comparer)

 

-public void Sort()
즉, 매개변수가 없는 Sort 메서드(void Sort())는 List<T>의 원소인 객체와 계약을 맺었는데, 
그 계약의 내용은 List<T>의 원소인 객체는 int CompareTo(T other)와 같은 메서드를 가지고 있다는 것입니다. 
따라서 실제 List<T>의 원소의 객체가 무엇이든지 간에 Sort 메서드는 그 객체의 CompareTo 메서드를 호출하면 정렬을 수행할 수 있다.
List<T>의 원소인 객체는 int CompareTo(T other)를 구현하여야 한다. 
즉, Person이 int CompareTo(Person other) 메소드에 이름 순으로 구현하여야 계약이 성립한다.

 

public class Person : IComparable<Person>
{
….

// Sort
public int CompareTo(Person other)
{
return this.Name.CompareTo(other.Name);
}
}

 

private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));

 

// 이름순으로 정렬
aList.Sort();
}

-public void Sort(Comparison<T> comparison)
이번에는 이름이 아니라 나이 순으로 정렬을 하는 경우, 
int CompareTo(Person other) 내부 구현을 이름이 아니라 나이를 기준으로 정렬하도록 수정한다.
이 경우 동적으로 Sort를 다르게 할수없는 문제가 있으므로, 
List<T>의 원소를 비교 가능한 객체라고 전제 하는 것이 아니라, 
Sort 메서드의 매개 변수로 아예 List<T>의 원소들을 비교하는 메서드를 전달하는 것입니다.

public delegate int Comparison<T>(T x, T y)
Comparison 대리자의 의미는 x가 y보다 작으면 음수, 같으면 0, 크면 양수를 반환한다는 것이다.

public static int ComparePersonByName(Person x, Person y)
{
return x.Name.CompareTo(y.Name);
}

public static int ComparePersonByAge(Person x, Person y)
{
return x.Age.CompareTo(y.Age);
}

 

private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));

 

// 이름순으로 정렬
aList.Sort(ComparePersonByName);
// 나이순으로 정렬
aList.Sort(ComparePersonByAge);
}

-public void Sort(IComparer<T> comparer)
Sort가 IComparer<T> 인터페이스를 매개변수로 받아 처리할 수 있다.
int Compare(T x, T y)

public class PersonNameComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Name.CompareTo(y.Name);
}
}

 

public class PersonAgeComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Age.CompareTo(y.Age);
}
}

 

private static void Main(string[] args)
{
List<Person> aList = new List<Person>();
aList.Add(new Person(“둘리”, 1000));
aList.Add(new Person(“희동이”, 3));
aList.Add(new Person(“고길동”, 40));

 

// 이름순으로 정렬
aList.Sort(new PersonNameComparer());
// 나이순으로 정렬
aList.Sort(new PersonAgeComparer());

 

foreach(Person p in aList)
Console.WriteLine(p); // Person의 ToString 호출
}

C# Collection Interface Delegate

CollectionInterfaceDelegateFileIOTest

http://msdn.microsoft.com/en-us/library/system.collections.generic(v=VS.80).aspx

Collections (예로, List, ArrayList, Hashtable등)은 ICollection<T> 인터페이스를 구현한다.
List 클래스의 경우는 IList<T> 인터페이스를 또한 구현한다.

List<T> 컬랙션 클래스의 메소드 (예를 들어, Exists, Find, TrueForAll 등)는 특정 헬퍼대리자 (예를 들어, delegate void Action<T>, delegate bool Predicate<T> 등과 같은)를 사용하여, 중복되는 코드를 간결하게 만들수있다.