동적으로 생성된 컨트롤의 이벤트 처리시 넘기는 인자값으로 인한 문제입니다.

 

int NumSearch = 1

LOOP()

{

                        Button btnSearchUp = new Button();  // 버튼 객체 생성

                        btnSearchUp.Width = 70;

                        btnSearchUp.Text = "UpLoad";

                        btnSearchUp.ID = "btnSearchUp" + NumSearch.ToString();

                       

                        // 이 버튼의 명령인자에 파일의 경로와 파일 이름으로 설정

                        btnSearchUp.CommandArgument = temp;

 

                        // 해당 버튼에 이벤트를 걸어준다.

                        btnSearchUp.Click += new EventHandler(btnSearchUpClick);

 

                        NumSearch++;

}

 

 

이런 식으로 하여, 동적으로 컨트롤을 생성합니다.

컨트롤 아이디는 보시는 바와 같이 "btnSearchUp" + 1 ... 2 ... 3 이런식으로 컨트롤의 아이디가 붙습니다.

그리고 버튼의 CommandArgument 속성에 temp라는 string을 넣습니다. 그러면

아래쪽에 해당 버튼의 클릭 이벤트를 만들어 준 곳에서 이 CommandArgument 속성이 전달이 됩니다.

 

        void btnSearchUpClick(object sender, EventArgs e)

        {

             ((Button)FindControl("btn")).CommandArgument    

        }

 

이벤트 메서드 입니다.

이 부분은 엄준일 님께서 알려 주셨는데요. 이렇게 이벤트를 처리하는 메소드는 1개 뿐입니다.

전달 인자를 찾아 내기 위해서 위와 같은 방법을 쓴다는데, 이 부분은 버튼 컨트롤을 FindControl() 메서드로 찾아서 해당 속성을

추출하는 것 처럼 보입니다만, 저 부분의 "btn" 부분은 컨트롤의 아이디가 아닌가요?

컨트롤의 아이디로 알고 있는데, 여기서 문제가 생깁니다.

 

예를 들어, 위에서 동적으로 10개의 버튼 컨트롤을 생성했습니다.

그런데 사용자가 어떠한 버튼을 클릭할 지 알 수 없는데,

이벤트 처리 메서드에서는 어떻게 사용자가 클릭한 버튼 컨트롤의 아이디를 찾아서 해당 속성을 가져온다는 말인가요?

 

이러한 문제는 어떻게 해결해야 하나요?

 


 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>제목 없음</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

               <input type="hidden" id="hid" name="hid" />

    </div>

    </form>

</body>

</html>

----------------------------------------------------------------------------

        protected void Page_Load(object sender, EventArgs e)

        {

               for (int i = 0; i < 10; i++)

               {

                       Button btn = new Button();

                       btn.ID = "btn" + i;

                       btn.Click += new EventHandler(btn_Click);

                       btn.Attributes["onclick"]     = "form1.hid.value = '" + "btn"+i + "';";

                       btn.Text = i.ToString();

                       btn.CommandArgument = "인자값 : " + i.ToString();

 

                       form1.Controls.Add(btn);

                       form1.Controls.Add(new LiteralControl("<br/>"));

               }

        }

 

        void btn_Click(object sender, EventArgs e)

        {

               string btnString       = Request["hid"].ToString();

 

               Response.Write( "버튼 컨트롤 아이디 : " + btnString + "<br>");

               Button btn = (Button)FindControl( btnString );

               Response.Write( btn.CommandArgument );

        }

---------------------------------------------------------------------------------------------

이 소스는 10 개의 버튼을 생성한 후에 버튼을 클릭하게 되면 html 히튼 컨트롤에 버튼의 아이디 값을 넣습니다.

 

그리고 포스트백 후에 버튼 이벤트가 실행되겠지요.

 

버튼 이벤트에서 버튼의 아이디 값을 가져옵니다. 그것으로 마져 CommandArgument 값을 가져오지요..

 

ASP나 JSP 식의 코딩이지요~

 

이전에도 말씀드렸다 시피, 닷넷의 생산성이 높다는 것의 하나가 바로 바인딩 가능한 서버 컨트롤이 있기 때문이지요.

 

똑같은 소소를 DataList 로 작성해 보면..

 

<%@ Import Namespace="System.Data" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<script runat="server">

        private void Page_Load(object sender, EventArgs e)

        {

               if( IsPostBack ) return;

              

               // 가상의 데이터

               DataTable dt = new DataTable();

               dt.Columns.Add("Title", typeof(string) );

 

               for (int i = 0; i < 10; i++)

               {

                       DataRow row = dt.NewRow();

                       row["Title"] = "btn"+i;

                       dt.Rows.Add( row );

               }

              

               dlList.DataSource      = dt;

               dlList.DataBind();

        }

 

        protected void dlList_ItemCommand(object source, DataListCommandEventArgs e)

        {

               if (e.CommandName == "upload")

               {

                       Response.Write( e.CommandArgument.ToString() + "버튼이 클릭되었습니다");

               }

        }

</script>

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>제목 없음</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

               <asp:DataList ID="dlList" runat="server" OnItemCommand="dlList_ItemCommand">

                       <ItemTemplate>

                              <%# DataBinder.Eval(Container.DataItem,"Title") %> <asp:Button ID="btn" runat="server" CommandName="upload" Text='Upload' CommandArgument='<%# DataBinder.Eval(Container.DataItem,"Title") %>'></asp:Button>

                       </ItemTemplate>

               </asp:DataList>

    </div>

    </form>

</body>

</html>

 

소스량은 언듯 비슷해 보이네요~

 

하지만 작성하면서 직관성이 매우 차이가 나고, 직관적이므로 디버깅도 용이해 지겠죠~

 

또한 후자처럼 작성하시게 되면 아시겠지만, 속도면에서도 굉장히 빨라집니다.

 

VS 2003 에서 작성하시는거라 위의 녹색 부분은 Oninit 메서드에서 이벤트로 따로 연결해 주셔야 합니다.

 

DataList 의 편리함을 뒤늦게라도 아시면... "아차~ 왜 진작 안썼지~" 라고 후회하실거에영^^;

naver OpenAPI의 내PC 검색은 일반적인 검색과 리턴 값이 달랐다.
일반적인 openAPI의 리턴값은 다음과 같다. 예를들어 검색 api는 다음과 같은 XML을 리턴한다.
<?xml version="1.0" encoding="UTF-8" ?>
- <rss version="2.0">
- <channel>
  <title>Naver Open API - webkr ::'go'</title>
  <link>http://search.naver.com</link>
  <description>Naver Search Result</description>
  <lastBuildDate>Tue, 11 Apr 2006 14:36:33 +0900</lastBuildDate>
  <total>18992582</total>
  <start>1</start>
  <display>10</display>
- <item>
  <title><b>GO</b>.com</title>
  <link>http://www.go.com/</link>
  <description>... Victims, Military Personnel Sell Rations Online Government Report Finds Ready-to-Eat Meals for Sale on eBay...... trailers and the latest buzz on... Harry Potter and the Goblet of Fire , X-Men 3 , Spider-Man 3 , more... Tonight...</description>
  </item>

보면 알겠지만 <TAG>TEXT</TAG> 형식으로 구성되어 있으므로 파싱하기가 편리하다.
직접 파싱을 해도 되지만, C#에서 파서를 제공해 주는데 굳이 할 필요는 없지 않은가.
최초 XML을 접하고 파싱에 애를 먹어 각지의 도움을 얻었었다. 그리고 준일님께서 도와주셨다.

웹서비스는 XML 을 이용한 HTTP 간의 통신 방법이다.
이 기술이 현재 각광을 받는 이유는 방화벽간에 통신을 위한 포트가 아닌,
HTTP 로 어떤 플랫폼에서도 인식이 가능한 규격화된 텍스트 형식, 즉 XML 이라는 것이다.

DataSet 이란 클래스는 무수한 기능을 가진 컬렉션이다.
이부분은 ADO.NET에 대해서 더 공부하면 알겠지만, 메모리 상의 작은 데이터베이스라고 칭할만큼 무수한 기능이 많다.
DataSet 의 ReadXml 이란 메서드는 XML 형식의 데이터를 DataSet 으로 파싱할 수 있게 된다.
(단, 모든 DataSet 에 변환가능한 형식 이어야 한다.)

파싱의 예는 다음과 같다.
string QueryURL = "쿼리문"
XmlTextReader txtReader = new XmlTextReader(QueryURL);
while(txtReader.Read())
{
 if(txtReader.NodeType == XmlNodeType.Element)
 Response.Write(txtReader.Name + " : ");
 if(txtReader.NodeType == XmlNodeType.Text)
 Response.Write (txtReader.Value + "<br>");
}

쿼리문을 던져 해당 노드의 타입을 보고 Element와 Text를 구분하여 출력해 주는 예제이다.
하지만, 문제가 있다.
naver 내PC 검색의 리턴XML의 출력은 표준 형식인 RSS 2.0 형식 (http://blogs.law.harvard.edu/tech/rss)을 따른다.
표준 RSS에 내PC검색 API용으로 추가된 태그는 nns XML namespace를 가진다.

<?xml version="1.0" encoding="UTF-8" ?>
- <rss version="2.0" xmlns:nns="http://mypc.naver.com/nnsrss">
- <channel>
  <title>Naver OpenAPI - MyPC Search Result</title>
  <link>http://127.0.0.1:4311/openapi/search?key=mypc&query=%BF%E4%BF%F8</link>
  <description>Naver MyPC Search Result</description>
  <language>ko</language>
  <generator>Nano Search 2.0</generator>
  <nns:total>5</nns:total>
  <nns:start>1</nns:start>
  <nns:display>5</nns:display>
  <nns:errorcode>0</nns:errorcode>
- <item>
- <title>
<![CDATA[alias.2x03.cipher.ws_dvdrip_xvid-fov.avi  ]]>
  </title>
- <link>
<![CDATA[G:\alias.s02\alias.2x03.cipher.ws_dvdrip_xvid-fov.avi  ]]>
  </link>
- <description>
- <![CDATA[ 

와 같은 형식은 <TAG><![CDATA[TEXT]]</TAG> 형식이다. 위의 파싱 방법으로 파싱을 할 경우에는, 올바로 파싱이 되지 않는다. <![ 형식을 Element로 판단하지 못하고 무시해 버린다.
위 파싱 방법의 소스 중, Value는 Xml Element 의 내용을 그대로 가져오게 된다.
ReadElementString() 메서드를 사용하면 말끔히 해결된다.
다음 예제는 이러한 문제도 말끔히 해결된다.

XMLFile1.XML
<?xml version="1.0" encoding="utf-8" ?>
<title><![CDATA[타이틀]]></title>
Program.CS
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
namespace ConsoleTest
{
 class Program
 {
  static void Main(string[] args)
  {
   XmlTextReader reader = new XmlTextReader("../../XMLFile1.xml");
   while (reader.Read())
   {
    if (reader.NodeType == XmlNodeType.Element && reader.Name == "title")
     Console.WriteLine(reader.ReadElementString());
   }
   reader.Close();
  }
 }
}

이상. XML의 파싱은 여기까지.
XML을 적절히 파싱한다면, 이를 이용하는 방법은 헤아릴 수도 없을 정도일 것이다.
이것이 XML의 강점(?) 이며, openAPI의 매력일지도 모르겠다. *-_-*
하이퍼링크 or Method=GET : Request.QueryString
폼Method="POST" : Request.Form

가끔, 어떤 경우는 GET 방식으로도, POST 방식으로도 같은 이름의 데이터가 넘어오는 경우가 있을 수 있다.
그러한 경우에는 동일한 이름을 사용하여 GET 혹은 POST로 넘어 오는 데이터를 얻어낼 수 있는 방법이 필요한데, 그러한 경우에는 어떻게 대처해야 하는가? Request 개체는 그러한 경우에 사용할 수 있는 특별한 컬렉션을 별도로 준비해 두었는데, 그것은 Params 이다.

Request.Params 속성은 내부적으로 QueryString과 Form을 모두 수행한다.
그러므로 ASP.NET 페이지가 어떠한 경우는 GET방식으로 넘어오는 "email" 이라는 이름의 값을 얻어내야 하고, 어떠한 경우는 POST 방식으로 넘어오는 "email"이라는 이름의 값을 얻어내야 한다면 다음과 같이 작성하여, 두 가지 모두의 경우를 대비할 수 있다.

Request.Params["email"]

이 코드는 내부적으로 먼저 email이라는 키에 대해서 QueryString을 수행하고, 그에 해당하는 값이 없으면 Form 작업도 수행한다. 그리고, 지정된 키에 해당하는 값을 찾으면 그 값을 읽어 온다. 또한, 이 코드는 다음과 같이 줄여서 사용할 수도 있다.

Request["email"]

내 참, 캐스팅 때문에 또 이렇게 시간을 허비하다니.
문법을 다 배우는 게 너무 오랜 시간이 걸린다고 생각해서 간단한 거 하나 만들어 보자는 생각에,
무턱 대고 만들기 시작했는데 생각 외로 많은 문제들에 부딪힌다.
다음은 C#에서의 String Type to Integer Type 캐스팅

int nNumber = Convert.ToInt32(Text1.Text);

ToInt16은 short Type으로 변환되고 ToInt32는 int Type으로, ToInt64는 long Type으로 변환.
다른 Type으로도 변환이 가능한데 Convert의 메소드를 보면 알 수 있다.

주의 할 점이 있다.
String Type에서 Integer Type으로 변환시, 문자열이 정수로 변환할 문자열에 낑겨져 있다면 오류.
변환하기전에 숫자만이 입력 됐는지 체크를 하시던지 아니면 try를 걸어서 예외처리.