티스토리 뷰

반응형

3회 강좌에서 OpenAPI 호출 후 결과까지 받아오도록 프로그램을 만들었다. 혹시 아직까지 완성을 하지 못했다면 다시 돌아가서 만들어 보기 바란다. 이 강좌에서는 소스를 파일로 첨부하지 않을 예정이니..기다려도 소용이 없다..아하하하;; (리플로 요청을 하면 요청자에 한해서만 살짝 보내줘야징..ㅎ)
4회에서는 모델을 만들고, 모델에 데이터를 쑤셔 넣고, 그 데이터를 화면에 출력하는 부분까지 진행 하도록 하겠다.

1. BusRouteModel.cs
실버라이트는 기본적으로 오브젝트를 이용한 프로그램을 지향한다. 과거에 개발 했던 프로그램들이 데이터를 순수 데이터로만 처리를 방식을 생각하고 프로그램을 하면 쉽게 적응하지 못 할 것이다. 이제는 인식의 전환이 필요한 때이다. 물론 본 프로그램에서는 단순히 조회해서 결과를 보여주는 용도만 있기 때문에 크게 못 느낄 수도 있지만, 상상을 해보면 정말 많은 가능성이 존재한다는 것을 알게 될 것이다.

여기서는 조회된 결과를 모두 오브젝트로 만들어서 사용하게 된다. (단순하게 이야기하면 클래스 만들어서 쑤셔 넣고 그걸 모아서 보여주겠다는 이야기다,)
버스 노선 목록 조회의 결과를 이용해서 만든 모델을 살펴 보자

using System.ComponentModel;

namespace BusInfo.Models
{
    //버스 노선 목록 조회 모델 http://api.bus.go.kr/contents/sub02/getBusRouteList.html
    public class BusRouteModel : INotifyPropertyChanged
    {
        #region PropertyChange
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 프로퍼티 체인지 이벤트
        /// </summary>
        /// <param name="PropertyName"></param>
        private void FirePropertyChange(string PropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
            }
        }
        #endregion

        int busRouteId;
        /// <summary>
        /// 노선ID
        /// </summary>
        public int BusRouteId
        {
            get { return busRouteId; }
            set
            {
                busRouteId = value;
                FirePropertyChange("BusRouteId");
            }
        }

        string busRouteNm;
        /// <summary>
        /// 노선명
        /// </summary>
        public string BusRouteNm
        {
            get { return busRouteNm; }
            set
            {
                busRouteNm = value;
                FirePropertyChange("BusRouteNm");
            }
        }

        string startStationNm;
        /// <summary>
        /// 기점
        /// </summary>
        public string StartStationNm
        {
            get { return startStationNm; }
            set
            {
                startStationNm = value;
                FirePropertyChange("StartStationNm");
            }
        }

        string endStationNm;
        /// <summary>
        /// 종점
        /// </summary>
        public string EndStationNm
        {
            get { return endStationNm; }
            set
            {
                endStationNm = value;
                FirePropertyChange("EndStationNm");
            }
        }

        int routeType;
        /// <summary>
        /// 노선 유형(1:공항, 3:간선, 4:지선, 5:순환, 6:광역, 7:인천, 8:경기, 9:폐지, 0:공용)
        /// </summary>
        public int RouteType
        {
            get { return routeType; }
            set
            {
                routeType = value;
                FirePropertyChange("RouteType");
            }
        }

        int term;
        /// <summary>
        /// 배차간격 (분)..여기서 조회되는 배차 간격은 진짜와는 좀 많은 차이가 있음
        /// </summary>
        public int Term
        {
            get { return term; }
            set
            {
                term = value;
                FirePropertyChange("Term");
            }
        }

    }
}

모델은 크게 어려운 점이 없으니 넘어 가도록 한다. 앞으로도 모델을 만들 때는 리턴된 결과와 설명 웹 페이지의 데이터를 비교해서 하나씩 만들어서 사용하면 된다.

2. MainPageViewModel.cs 추가 작업
방금 만든 모델에 xml 파싱 데이터를 넣는 작업을 진행해 보자. 우선 BusRouteModel을 여러개를 넣어 놓고 바인딩 할 프로퍼티를 하나 만든다.

ObservableCollection<BusRouteModel> busRouteCollection;
/// <summary>
/// 버스 목록 컬렉션 - 프로퍼티
/// </summary>
public ObservableCollection<BusRouteModel> BusRouteCollection
{
    get { return busRouteCollection; }
    set
    {
        busRouteCollection = value;
        FirePropertyChange("BusRouteCollection");
    }
}

지난 시간에 만들었던 wc_DownloadStringCompleted 이벤트에 코드를 추가한다.

/// <summary>
/// 웹클라이언트 다운로드스트링 컴플릿트 이벤트 구현
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Error != null)
        return;
    //xml을 xElement라는 객체로 바로 파싱해서 사용한다.
    XElement xml = XElement.Parse(e.Result);
    //어떤 서비스의 결과인지에 따라서 각각 다른 처리를 한다.
    switch (e.UserState as string)
    {
        case "GetBusRouteList":
            BusRouteCollection = new ObservableCollection<BusRouteModel>();

            foreach (var item in xml.Descendants("itemList"))
            {
                BusRouteModel row = new BusRouteModel();
                row.BusRouteId = Convert.ToInt32(item.Element("busRouteId").Value);
                row.BusRouteNm = item.Element("busRouteNm").Value;
                row.StartStationNm = item.Element("stStationNm").Value;
                row.EndStationNm = item.Element("edStationNm").Value;
                row.RouteType = Convert.ToInt32(item.Element("routeType").Value);
                row.Term = Convert.ToInt32(item.Element("term").Value);
                BusRouteCollection.Add(row);
            }
            break;
    }
    //debug용
    if (1 == 1)
    { // <- 요위치에 브레이크 포인트
    }
}

위와 같이 코드를 입력 한 후 실행하고, 택스트 박스에 버스 번호 2자리만 입력하고 조회 버튼을 클릭하고, 조금 있으면 브레이크 포인트에서 실행을 멈추게 된다.

BusRouteCollection의 내용을 확인 해보자. 아마 원하는 결과가 차곡 차곡 들어 가 있는 것을 알 수 있을 것이다.

그런데, 위의 코드는 데이터가 많아지는 경우 약간의 랙을 유발한다. 윈폰에 랙을 만들어 줄 수는 없는 것 아닌가..그래서 처음에 데이터를 넣는 코딩을 할 때는 위와 같은 방법으로 테스트를 해서 에러가 없으면 다음과 같이 코드를 변경해 주도록 하자.

using System.Linq; //상단에 추가

/// <summary>
/// 웹클라이언트 다운로드스트링 컴플릿트 이벤트 구현
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
  if (e.Error != null)
      return;
  //xml을 xElement라는 객체로 바로 파싱해서 사용한다.
  XElement xml = XElement.Parse(e.Result);
  //어떤 서비스의 결과인지에 따라서 각각 다른 처리를 한다.
  switch (e.UserState as string)
  {
      case "GetBusRouteList":
          var rows = from item in xml.Descendants("itemList")
                     select new BusRouteModel
                     {
                         BusRouteId = Convert.ToInt32(item.Element("busRouteId").Value),
                         BusRouteNm = item.Element("busRouteNm").Value,
                         StartStationNm = item.Element("stStationNm").Value,
                         EndStationNm = item.Element("edStationNm").Value,
                         RouteType = Convert.ToInt32(item.Element("routeType").Value),
                         Term = Convert.ToInt32(item.Element("term").Value)
                     };
          BusRouteCollection = new ObservableCollection<BusRouteModel>(rows);

          break;
  }

  if (1 == 1)
  {
  }
}

이제 조회 결과는 모두 컬렉션에 담아 놓았으니 이걸 화면에 출력하기면 하면 된다. (F6을 눌러 빌드를 한번 해주고 넘어가도록 한다.)

3. MainPage.xaml - 블랜드에서 DataTemplate 만들고 바인딩 하기
정겨운 블랜드 화면으로 전환


일단 ListBox를 클릭

상단에  [ ListBox > 요렇게 생긴부분을 클릭 -> Edit Additional Templetes -> Edit Generated Items (ItemTemplate) -> Create Empty 클릭

그러면 Create DataTemplate Resource 창이 출력된다. 여기서 그냥 OK를 눌러도 된다. 그러나, 그렇게 하면 MainPage.xaml에 데이타 템플릿이 만들어 지기 때문에 소스가 복잡하게 바뀐다. 그래서, 우린 리소스 딕셔너리를 이용해서 만들 것이다.

New버튼 클릭


name : BusInfoResourceDictionary.xaml 로 변경 후 Ok

이번에는 우리가 만들 데이터 템플릿의 이름을 지정해 준다. name : BusRouteDataTemplate -> OK

이곳에서 데이터 템플릿을 만들면 된다. 일단 크기를 적당하게 늘려주고, 구역 정하고, 스택 패널 올리고, 택스트 블럭 컨트롤 올려서 대략 구성을 맞추면 된다.

<DataTemplate x:Key="BusRouteDataTemplate">
 <Border BorderThickness="2,1" Width="450" >
  <Grid>
   <Grid.RowDefinitions>
    <RowDefinition Height="0.5*"/>
    <RowDefinition Height="0.5*"/>
   </Grid.RowDefinitions>
   <StackPanel Orientation="Horizontal">
    <TextBlock TextWrapping="Wrap" Text="◎ 종류 : "/>
    <TextBlock TextWrapping="Wrap" Text="버스종류"/>
    <TextBlock TextWrapping="Wrap" Text="◎ 버스명 : " Margin="6,0,0,0"/>
    <TextBlock TextWrapping="Wrap" Text="버스명(번호)" />
   </StackPanel>
   <StackPanel Grid.Row="1" Orientation="Horizontal">
    <TextBlock TextWrapping="Wrap" Text="◎ 노선 : "/>
    <TextBlock Text="기점명"/>
    <TextBlock TextWrapping="Wrap" Text=" ~ "/>
    <TextBlock Text="종점명"/>
   </StackPanel>
  </Grid>
 </Border>
</DataTemplate>

마무리는 코드를 보면서 하지만, 그림 그릴 때는 블랜드에서만 작업하는 것을 연습하자.(블랜드가 손에 익숙해야 작업하기도 좋다)
일단 디자인은 완료~ 다시 리스트 박스로 넘어가자. 상단의 [ListBox] 를 클릭하면 된다.
ListBox를 다시 선택 한 후 ItemsSource 프로퍼티를 찾아가자 그리고 쪼그마한 네모를 클릭해서 팝업 메뉴를 호출 하고 Data Binding을 선택한다. 화면에 우리가 좀전에 만들었던 BusRouteCollection이 보이면 된다.(혹시 보이지 않으면 빌드하고 다시 온다.)
BusRouteCollection을 선택하고 Ok

**** 디자인은 블랜드, 실행은 VS2010으로 하는 것으로 정하자..매번 쓸려니..괴롭다..쿨럭..
블랜드의 변경된 내용을 모두 저장 하고 실행을 해서 결과가 어떻게 나오는지 확인 해보자.


헉..먼가 출력이 되기는 했는데..음..우리가 아까 템플릿에 넣은 글씨들만 잔뜩 나오고 있다.
이렇게 나온 이유는 DataTemplate의 각 항목들에도 바인딩을 해줘야 하는데 안했기 때문이다.(다들 알고 있겠죠?)

그럼 블랜드에서
상단에  [ ListBox ] -> Edit Additional Templetes -> Edit Generated Items (ItemTemplate) -> Edit Current 클릭

버스 종류 클릭 -> Text 프로퍼티 -> 쪼그만 네모 박스 -> Data Binding -> RouteType 선택 -> OK (TextBlock의 Mode는 OneWay이니..)
버스명(번호) 클릭 -> Text 프로퍼티 -> 쪼그만 네모 박스 -> Data Binding -> BusRouteNm 선택 -> OK
기점, 종점도 동일 한 방식으로 처리 한다. (으흐흐..대충 축약 했다는..)
변경된 템플릿 소스

<DataTemplate x:Key="BusRouteDataTemplate">
 <Border BorderThickness="2,1" Width="450" >
  <Grid>
   <Grid.RowDefinitions>
    <RowDefinition Height="0.5*"/>
    <RowDefinition Height="0.5*"/>
   </Grid.RowDefinitions>
   <StackPanel Orientation="Horizontal">
    <TextBlock TextWrapping="Wrap" Text="◎ 종류 : "/>
    <TextBlock TextWrapping="Wrap" Text="{Binding RouteType}"/>
    <TextBlock TextWrapping="Wrap" Text="◎ 버스명 : " Margin="6,0,0,0"/>
    <TextBlock TextWrapping="Wrap" Text="{Binding BusRouteNm}" />
   </StackPanel>
   <StackPanel Grid.Row="1" Orientation="Horizontal">
    <TextBlock TextWrapping="Wrap" Text="◎ 노선 : "/>
    <TextBlock Text="{Binding StartStationNm}"/>
    <TextBlock TextWrapping="Wrap" Text=" ~ "/>
    <TextBlock Text="{Binding EndStationNm}"/>
   </StackPanel>
  </Grid>
 </Border>
</DataTemplate>

다시 실행해서 결과를 확인 한다.


일단은 만족스러운 결과가 만들어 졌다. 마음에 들지 않는 부분이 하나 있다면..저기 보이는 종류이다..숫자로 나오면 뭐가 뭔지 어떻게 알겠는가..그래서 이럴 때 필요한 것이 컨버터라는 기능이다.

4. 다음 강좌에서...
컨버터를 만드는 것, 컨버터를 바인딩 하는 부분들을 다루도록 하겠다.
생각보다 쉽다면 리플을 하나씩 남겨 주기를 바란다. ㅎㅎ

반응형

'Previous Platforms > KBI' 카테고리의 다른 글

Seoul Bus Info Search App Dev 6  (0) 2012.01.07
Seoul Bus Info Search App Dev 5  (0) 2012.01.07
Seoul Bus Info Search App Dev 3  (0) 2012.01.04
Seoul Bus Info Search App Dev 2  (0) 2012.01.04
Seoul Bus Info Search App Dev 1  (0) 2012.01.04
댓글