'.NET > WPF' 카테고리의 다른 글
동적으로 컨트롤 생성하기 (0) | 2010.07.21 |
---|---|
WPF에서 사용자정의컨트롤 쓰기 (0) | 2010.04.26 |
미디어플레이어 (동기화해결) (0) | 2010.04.22 |
WPF에서 미디어 플레이어 만들기 (1) | 2010.04.19 |
의존속성 (0) | 2010.04.16 |
동적으로 컨트롤 생성하기 (0) | 2010.07.21 |
---|---|
WPF에서 사용자정의컨트롤 쓰기 (0) | 2010.04.26 |
미디어플레이어 (동기화해결) (0) | 2010.04.22 |
WPF에서 미디어 플레이어 만들기 (1) | 2010.04.19 |
의존속성 (0) | 2010.04.16 |
동적으로 컨트롤 생성하기 (0) | 2010.07.21 |
---|---|
WPF에서 사용자정의컨트롤 쓰기 (0) | 2010.04.26 |
미디어플레이어 (동기화해결) (0) | 2010.04.22 |
WPF에서 미디어 플레이어 만들기 (1) | 2010.04.19 |
사용자지정과 사용자정의 컨트롤 차이 (0) | 2010.04.18 |
Page - 웹 응용 프로그램을 위한 프로그래밍 가능한 사용자 인터페이스
- 브라우저 또는 클라이언트 장치를 통해 사용자에게 정보를 표시하며 서버 측 코드를 사용하여 응용 프로그램 논리를 구현
- 스타일, 레이아웃 등의 기능에 해당 브라우저 호환 HTML을 자동으로 렌더링함.
- 웹 페이지의 구성요소는 시각적 구성 요소와 논리라는 두 부분으로 나뉨
Cookie, View State, Hidden Field, IsPostBack 란? (0) | 2010.04.08 |
---|
서버에 게시할 때 유지되어야 하는 값을 저장하는 데 사용됩니다. 이 컨트롤은 <input type= "hidden"/> 요소로 렌더링됩니다. (렌더링 - 사용자가 직접 눈으로 볼 수 있게 이미지화 하는거)
대개 뷰 상태, 세션 상태 및 쿠키가 Web Forms 페이지의 상태를 유지하는 데 사용됩니다. 그러나 이러한 방법을 사용하지 않도록 설정했거나 사용할 수 없는 경우에는 HiddenField 컨트롤을 사용하여 상태 값을 저장할 수 있습니다.
HiddenField 컨트롤의 값을 지정하려면 Value 속성을 사용합니다. ValueChanged 이벤트에 대한 이벤트 처리기를 만들어 서버에 대한 게시 사이에 HiddenField 컨트롤의 값이 변경될 때마다 호출되는 루틴을 제공할 수 있습니다.
ViewState
웹에서는 상태를 유지하기위한 여러가지 방법들을 사용합니다.
그 예로는 Application, Session, Cookie, ViewState 등등.. 이외에도 여러가지 방법들이 있습니다.
(김영욱님의 상태관리하기1, 상태관리하기2 를 참고하시기 바랍니다.)
이중에서 ViewState만 다루어보도록 하겠습니다. 이후 다른 상태유지에 대해서는 직접 알아보는 재미를 느껴보시기 바랍니다.^^
ViewState에 대해 언급하는 이유는 VisualStudio(이하 VS)에서 사용하는 서버 컨트롤 들은 기본적으로 상태유지를 위해 ViewState를 사용합니다.
사용자가 따로 설정하지 않아도 자체적으로 ViewState에 상태값을 저장해두었다가 불러 사용합니다. 이내용은 지난 시간의 페이지 실행주기의 내용에 언급되어 있으니 참고하시면 좋을 듯 합니다.
컨트롤 속성에는 ViewSate를 사용하지 않는 옵션(EnableViewState)도 있으니 참고하시기 바랍니다.
상태유지란 의미를 모르시는 분들을 위해 간단하게 설명해드리겠습니다.
웹페이지는 기본적으로 HTML형식의 문서입니다.
입력을 위한 input태그 빼고는 대부분의 태그들은 표현을 위한 태그들이 대다수 입니다.
Input 태그 또한 새로고침등의 자기 자신을 다시 호출하는 경우에는 input 태그의 text타입에 있던 내용들도 사라지게 됩니다.
예제 1 )
<input id="Text1" type="text" /> <input id="Button1" type="button" value="button" /> |
input 태그를 이용한 textbox에 “dnc”를 입력
그러나 서버 컨트롤은 앞에서 언급한 바와 같이 ViewState를 이용한 상태유지를 합니다.
서버컨트롤을 이용해서 예제 1과 같은 예제를 만들어 보겠습니다.
예제 2 )
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> <asp:Button ID="Button1" runat="server" Text="Button" /> |
이게 어떻게 된 일일까요? 분명 앞에서는 서버컨트롤은 자체적으로 ViewState를 이용해서 상태유지를 한다고 말했었는데 거짓말을 한 것 일까요?
상태유지를 하지 못한 이유는 이전 포스팅의 페이지 실행 주기를 참고하시기 바랍니다.
페이지 실행 주기를 보게 되면 ViewState 복구와 저장을 하는 시점이 있습니다.
즉 ViewState에 저장을 하기위해서는 실행주기를 거쳐야 한다는 말이 되겠죠?
그말은 서버에 갔다와야 한다. PostBack이 발생해야 한다는 말이 되겠습니다.
이번에는 예제 2 와 같지만 버튼을 한번눌러 PostBack을 일으켜 서버에 갔다온이후 새로고침을 해보겠습니다.
예제 3 )
그럼 html 컨트롤들은 Server 컨트롤들처럼 자체적으로 상태유지를 할 수 없는 것인가??
꼭 그렇진 않습니다. Html 컨트롤에 runat="server" 속성을 넣어주면 서버컨트롤처럼 사용할 수 있습니다.
지금까지는 컨트롤에서 ViewState를 사용하는 부분에 대해 이야기를 해보았습니다.
이번에는 사용자가 직접 ViewState를 사용하는 이야기를 해보도록 하죠^^
사용은 아주 간단합니다.
예제 4 )
// ViewState에 상태값 설정 ViewState["상태유지"] = "상태값"; // ViewState에서 상태값을 가져옴 string str상태유지 = (string)ViewState["상태유지"]; |
예제 4와 같은 형태로 ViewState에 데이터를 설정 및 가져올 수 있습니다.
하지만 보시는 것처럼 Boxing, UnBoxing이 발생하는걸 볼 수 있습니다.
Boxing, UnBoxing이 발생한다는 말은 부하가 심해진다는 말이죠
즉 많이 사용하면 좋지 않다는 말입니다.
그리고 ViewState같은 경우 페이지에 input태그의 hidden 형태로 존재하기 때문에 서버와의 통신시 많은량의 데이터 전송이 발생하게 됩니다.
예제 5 )
페이지의 소스보기를 하면 다음과 같은 소스를 볼 수 있습니다.
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJMjY4MTkwNDYwZGQINdZC2Y34uVAOpUIXzxBu3ijnGA==" /> |
즉 ViewState의 값들이 Base64()을 통해 인코딩을 해서 hidden형태로 관리하는걸 볼 수 있습니다.
페이지에 노출이 되기 때문에 보안에 아주 취약합니다. Base64로 인코딩을 하였어도 얼마든지 디코딩을 할 수 있기 때문입니다. 그리고 Base64로 인코딩을 하면서 기존의 값들보다 많은 문자열이 발생하는걸 볼 수 있습니다. 즉 ViewState를 많이 사용하면 할수록 서버와의 통신시 많은 데이터를 주고 받아야하는 부하를 가지게 됩니다.
protected void Button1_Click(object sender, EventArgs e)
{
if (ViewState["LOAD_TIME"] != null)
{
this.Label1.Text = "로드시간:"
+ Convert.ToDateTime(ViewState["LOAD_TIME"]).ToShortTimeString();
}
}
실행 후 리스트박스의 항목을 선택 후 새로 고침을 해도 그 상태 그대로 유지 된다! 그 이유는
VIEWSTATE 항목은 웹 페이지에 대한 현재 상태 정보를 저장하는 곳이다. 페이지를 다시 읽어오는 경우에도 정상적으로 리스트 컨트롤의 선택 정보를 표시 할 수 있도록 VIEWSTATE 항목에 저장했다가 보여 주는 것이다.
Cookie - 일반적으로 쿠키는 웹 응용 프로그램에서 연속성을 유지 관리하는 방법, 즉 상태 관리를 수행 하는 방법 중 하나이다. 사용자가 여러 사이트를 방문할 경우 각 사이트에서는 사용자의 브라우저에 쿠키를 보내고 브라우저에서는 모든 쿠키를 개별적으로 저장한다.
장점
- 단순성
쿠키는 단순한 키 값으로 구성된 간단한 텍스트 기반 구조다.
- 데이터 지속성
클라이언트의 쿠키 만료 프로세스 및 사용자 개입에 따라 클라이언트 컴퓨터의 쿠키 보존 기간이 결정되지만 일반적으로 쿠키는 클라이언트에 보관되는 데이터 중 가장 오래 보관된다.
단점
대부분의 브라우저에서는 쿠키 크기를 4096바이트로 제한하고 있다.
- 사용자에 의한 쿠키 거부
일부 사용자는 브라우저나 클라이언트 장치에서 쿠키 수신 기능을 사용하지 않으므로 이 기능이 제한됩니다.
- 잠재적 보안 위험
쿠키는 손상될 가능성이 높습니다. 사용자가 컴퓨터에서 쿠키를 조작할 수 있기 때문에 잠재적으로 보안 위험을 일으키거나 쿠키를 사용하는 응용 프로그램에 오류가 발생할 수 있습니다.
예제
protected void Page_Load(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
HttpCookie cookie = Request.Cookies.Get("DateCookie"); //이러한 쿠키가 있나 확인 없으면 null
//자동 로그인 = 쿠키
if (cookie == null)
{
sb.Append("클라이언트에서 쿠키를받지않음");
sb.Append("생성한 쿠키를 response에 추가");
cookie = new HttpCookie("DateCookie");
cookie.Value = DateTime.Now.ToString();
cookie.Expires = DateTime.Now.AddMinutes(10); //해당 파일이 언제까지 유효한지 설정
//유효 시간이 지나면 파괴
Response.Cookies.Add(cookie);
}
else
{
sb.Append("클라이언트에서 쿠키를 검색<br/>");
sb.Append("Cookie Name: " +cookie.Name + "<br/>" );
sb.Append("Cookie Value: " + cookie.Value + "<br/>");
sb.Append("Cookie 만료날짜" + cookie.Expires.ToString() + "<br/>");
}
Label1.Text = sb.ToString();
}
ViewState 출처 - http://dncblog.tistory.com/47
Page (Request, Response) (0) | 2010.04.08 |
---|
XML 개론 - http://msdn.microsoft.com/ko-kr/library/hf9hbf87.aspx
XML 노드 형식 - http://msdn.microsoft.com/ko-kr/library/3k5w5zc3.aspx
XML 데이터에 개체 계층 구조 매핑 - http://msdn.microsoft.com/ko-kr/library/a3bszkbd.aspx
DOM에서 새 노드 만들기 - http://msdn.microsoft.com/ko-kr/library/k44daxya.aspx
간단한 예제
member.xml
<?xml version="1.0" encoding = "UTF-8"?>
<members>
<id> sjy </id>
<id> aaa </id>
</members>
ConvertMember.cs
static void Main(string[] args)
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load("member.xml");
XmlElement xe = xdoc.DocumentElement;
XmlNode xn;
while ((xn = xe.SelectSingleNode("id")) != null)
{
if (xn.Name == "id")
{
XmlElement xne = xdoc.CreateElement("아이디");
xne.InnerText = xn.InnerText;
xe.RemoveChild(xn);
xe.AppendChild(xne);
}
Console.WriteLine(xe.InnerXml);
}
}
윈폼-리스트뷰에서 간단히 사용하기 (0) | 2010.04.25 |
---|---|
ReadLine, Read, ReadKey (0) | 2010.04.03 |
어셈블리 동적 로딩 (0) | 2010.03.31 |
Const Vs Readonly (0) | 2010.03.29 |
Sealed (0) | 2010.03.29 |
예외 | 상황 |
---|---|
IOException |
I/O 오류가 발생하는 경우 |
OutOfMemoryException |
반환된 문자열을 위한 버퍼를 할당할 메모리가 부족한 경우 |
ArgumentOutOfRangeException |
다음 줄의 문자 수가 Int32..::.MaxValue보다 큰 경우 |
이 메서드에서 OutOfMemoryException을 throw하는 경우 내부 Stream의 reader 위치가 메서드에서 읽지 못한 문자 수만큼 올라가지만, 이미 읽은 내부 ReadLine 버퍼의 문자는 삭제됩니다. 스트림의 reader 위치는 변경할 수 없으므로 이미 읽은 문자는 복구할 수 없고 TextReader를 다시 초기화하는 경우에만 액세스할 수 있습니다. 스트림 내부의 처음 위치를 알 수 없거나 해당 스트림이 검색을 지원하지 않는 경우에도 내부 Stream을 다시 초기화해야 합니다.
스트림을 다시 초기화하지 않고 견고한 코드를 생성하려면 Read 메서드를 사용하여 읽은 문자를 미리 할당된 버퍼에 저장해야 합니다.
윈폼-리스트뷰에서 간단히 사용하기 (0) | 2010.04.25 |
---|---|
윈도우 서비스 만들기 (0) | 2010.04.04 |
어셈블리 동적 로딩 (0) | 2010.03.31 |
Const Vs Readonly (0) | 2010.03.29 |
Sealed (0) | 2010.03.29 |
DataAdapter의 기능
- 데이터베이스의 Connection으로부터 DataSet을 생성하는 중간 역할 담당
- DataSet을 채우고 데이터 소스를 업데이트하는 데 사용되는 SQL 명령 집합 및 데이터베이스 연결을 지원하는 클래스
- DataTable와 같은 비연결 지향적 클래스들이 데이터베이스와 연결
- Command로 작업할 때에는 데이터베이스와 연결된 상태에서 작업
- DataAdapter로 작업을 할 경우에는 DataSet이라는 결과를 얻은 후에 데이터베이스와의 연결을 끊고, DataSet 자체만으로도 작업을 수행한다.
- 작업이 끝난 후에는 DatatAdapter를 통해 DataSet의 변경된 부분이 실제 데이터베이스에 반영 가능
SelectCommand 속성
- SelectCommand 속성을 이용하여 원본 DB의 데이터 소스에서 레코드를 검색하는데 사용하는 SQL문이나 Proc를 설정할 수 있다.
- SelectCommand 에 설정된 SQL문을 실행했을때 검색결과가 없어서 SelectCommamd가 행을 반환하지 않으면 데이터 셋에 테이블이 추가되지 않는다.
- SelectCommand 문을 실행해서 나온 결과에 대해서 SqlDataAdapter클래스의 Fill메소드가 데이터 셋에 테이블을 추가하게 된다.
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand();
adapter.SelectCommand.Connection = sConnection;
adapter.SelectCommand.CommandText = Query;
InsertCommand 속성
- InsertCommand 속성을 이용하면 새로운 레코드를 데이터 소스에 삽입할 SQL 문이나 Proc를 설정할 수 있다.
- InsertCommand를 이용해서 데이터 셋에 자료를 추가하는 등의 처리를 할 수 있다
adapter.InsertCommand = new SqlCommand();
adapter.InsertCommand.Connection = sConnection;
adapter.InsertCommand.CommandText = Query;
adapter.InsertCommand.Parameters.Add("@name",SqlDbType.VarChar,10,"name");
adapter.Update(ds, "tb_insert");
DeleteCommad 속성
- DeleteCommand는 행을 삭제할때 사용되는 속성이다.
- DeleteCommand 속성을 이용해서 행(레코드)를 데이터 집합으로부터 삭제할 SQL 문이나 Proc를 가져오거나 설정할 수 있다.
adapter.DeleteCommand = new SqlCommand();
adapter.DeleteCommand.Connection=(SqlConnection)adapter.SelectCommand.Connection;
adapter.DeleteCommand = new SqlCommand();
adapter.DeleteCommand.CommandText = strUpdateQurey;
adapter.DeleteCommand.CommandType = CommandType.Text;
- 작업을 하다보면 여러가지 이유로 입력된 데이터를 수정해야 할 때가 있다.
- UpdateCommand 속성을 이용하면 데이터 소스에서 레코드를 업데이트 하는데 사용하는 SQL 문이나 Proc를 가져오거나 설정할 수 있다
adapter.UpdateCommand = new SqlCommand();
adapter.UpdateCommand.Connection=(SqlConnection)adapter.SelectCommand.Connection;
adapter.UpdateCommand.CommandText = strUpdateQuery;
adapter.UpdateCommand.CommandType = CommandType.Text;
adapter.UpdateCommand.Parameters.Add(myParam);
메소드 |
설명 |
Fill |
데이터 셋의 행을 데이터 소스와 일치하도록 한다. |
FillSchema |
데이터 셋에 DataTable을 추가하고 데이터 소스의 스키마와 일치하도록 스키마를 구성한다. |
Update |
데이터 셋과 동일하게 데이터 소스를 업데이트한다. |
string connString = "server = 504-24\\SQL2005;database=tempdb;";
connString = connString + "uid=Hello;password=dhtlak;";
SqlConnection sConnection = new SqlConnection(connString);
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand();
adapter.SelectCommand.Connection = sConnection;
String Query = "select * from titile";
adapter.SelectCommand.CommandText = Query;
DataSet ds = new DataSet("Mytable");
adapter.FillSchema(ds, SchemaType.Source, "titile");
adapter.Fill(ds, "titile");
DataRow[] r3 = ds.Tables["titile"].Select();
foreach (DataRow ro in r3)
{
Console.WriteLine(ro["titile_id"].ToString() + ro["type"].ToString());
}
DB에 이미지 저장 / 로드 하기 (0) | 2010.06.18 |
---|---|
DB모델링 (0) | 2010.05.28 |
DataSet (0) | 2010.04.02 |
DataView (0) | 2010.04.02 |
SqlDataReader (1) | 2010.04.02 |
DataSet - 여러개의 테이블로 구성되있다.
DataTable의 구성요소
DataRelation(관계)
- DataColumn 개체를 통해 두 개의 DataTable 개체를 서로 연결하는데 사용
- 부모 및 자식 테이블의 일치하는 열 간에 관계가 만들어짐
- DataSet 내의 한 DataTable에서 다른 DataTable로 이동을 허용
table.Columns.Add("이름", typeof(string)); //컬럼 추가
table.Columns.Add("나이", typeof(int));
table.Columns.Add("학번", typeof(string));
//레코드 추가
row = table.NewRow();
row["이름"] = "천정민";
row["나이"] = 26;
row["학번"] = "123456789";
table.Rows.Add(row);
row = table.NewRow();
row["이름"] = "조아라";
row["나이"] = 23;
row["학번"] = "123456789";
table.Rows.Add(row);
row = table.NewRow();
row["이름"] = "안용준";
row["나이"] = 26;
row["학번"] = "987654321";
table.Rows.Add(row);
dataSet.Tables.Add(table); //DataSet에 테이블 추가
//table 테이블 레코드 변경전
Console.WriteLine("table 테이블 레코드 변경전");
DataRow[] r = dataSet.Tables["MyTable"].Select();
foreach (DataRow ro in r)
{
Console.WriteLine("이름 : " + ro["이름"].ToString() + " 나이 : " + ro["나이"].ToString() + " 학번 : " + ro["학번"].ToString());
}
Console.WriteLine();
//table 테이블 레코드변경
dataSet.Tables["MyTable"].Rows[0].Delete(); //테이블 삭제
dataSet.Tables["MyTable"].Rows[0].BeginEdit(); //수정시작
dataSet.Tables["MyTable"].Rows[0]["이름"] = "송창은"; //레코드 값 변경
dataSet.Tables["MyTable"].Rows[0].EndEdit(); //수정끝
dataSet.Tables["MyTable"].Rows[0].AcceptChanges(); //변경된 내용 실행
//table 레코드 값 얻어오기
Console.WriteLine("table 레코드 값 변경 후");
DataRow[] r2 = dataSet.Tables["MyTable"].Select();
foreach (DataRow ro in r2)
{
Console.WriteLine("이름 : " + ro["이름"].ToString() + " 나이 : " +
ro["나이"].ToString() + " 학번 : " + ro["학번"].ToString());
}
Console.WriteLine();
//다른 테이블 생성 및 레코드 생성
DataTable OtherTable = new DataTable("OtherTable");
OtherTable.Columns.Add("학번", typeof(string));
OtherTable.Columns.Add("학년", typeof(int));
row = OtherTable.NewRow();
row["학번"] = "123456789";
row["학년"] = 4;
OtherTable.Rows.Add(row);
row = OtherTable.NewRow();
row["학번"] = "123456789";
row["학년"] = 3;
OtherTable.Rows.Add(row);
dataSet.Tables.Add(OtherTable); //DataSet 추가
//OtherTable 레코드 값 얻어오기
Console.WriteLine("OtherTable 레코드 값 출력");
DataRow[] or = dataSet.Tables["OtherTable"].Select();
foreach (DataRow dr in or)
{
Console.WriteLine("학번 : " + dr[0].ToString() + " 학년 : " + dr[1].ToString());
}
Console.WriteLine();
//pk설정
dataSet.Tables["Mytable"].PrimaryKey = new DataColumn[] { dataSet.Tables["Mytable"].Columns["학번"] };
//Relation 설정
DataRelation rel = new DataRelation("Stu", dataSet.Tables["Mytable"].Columns["학번"], dataSet.Tables["OtherTable"].Columns["학번"]);
dataSet.Relations.Add(rel);
//Relation 관계에서 부모에 해당하는 Row값으로 자식의 Row값을 출력
Console.WriteLine("Relation 관계에서 부모에 해당하는 Row값으로 자식의 Row값을 검색");
DataRow[] childrow = dataSet.Tables["MyTable"].Rows[0].GetChildRows("Stu");
//부모테이블의 0번째 row를 관계맺은 컬럼을 자식테이블에서 찾아라
foreach (DataRow cr in childrow) //childrow에 있는 값을 DataRow형식으로 가지고 오겠다
{
Console.WriteLine("학번 : " + cr[0].ToString() + " 학년 : " + cr[1].ToString());
}
Console.WriteLine();
//테이블 갯수 출력
Console.WriteLine("테이블 수 : " + dataSet.Tables.Count);
//테이블 명 출력
foreach (DataTable t in dataSet.Tables)
{
Console.WriteLine("테이블 명 : " + t.ToString());
}
//Console.WriteLine("테이블 명 : " + dataSet.Tables[0]);
//Console.WriteLine("테이블 명 : " + dataSet.Tables[1]);
//컬럼 명 출력
Console.WriteLine("컬럼 명");
foreach (DataColumn dc in dataSet.Tables[0].Columns)
{
Console.Write(dc.ColumnName + " ");
}
Console.WriteLine();
}
DB모델링 (0) | 2010.05.28 |
---|---|
SqlDataAdapter (0) | 2010.04.02 |
DataView (0) | 2010.04.02 |
SqlDataReader (1) | 2010.04.02 |
SqlParameter 클래스 (0) | 2010.03.31 |