'mango'에 해당되는 글 3건

방금 기본적인 기능은 모두 완성을 했다. 아주 멋진 디자인은 아니지만, 가뭄에 단비가 내리는 정도로도 기쁘듯이, 그동안 버스 엡을 기다려온 윈폰 유저에게는 좋은 소식이 될 것 같다. 강좌를 마치고 나머지 마무리 작업을 해서 마켓플레이스에 올리도록 하겠다. 금주 내로 올리면 다음주에는 다운 받을 수 있을 것이라 생각한다.

 

1. 로딩 화면을 추가해 보자

목표 화면이다.

 


Windows Phone 7 Toolkit
References 추가해서, 그곳에 있는 PerformanceProgressBar를 사용 하도록 하겠다. 우선 기본 도구에도 ProgressBar가 존재 하지만, 구글링을 해보았을 때 프로그램 성능 저하를 줄 수 있다고 해서 대부분 PerformanceProgressBar를 이용해서 로딩 화면을 구성하는 것을 권장 하고 있으니, 따라 가도록 하겠다.

 

1) Windows Phone 7 Toolkit 추가 방법 1, 직접 빌드해서 추가한다.

Silverlight for Windows Phone Toolkit - Feb 2011

http://silverlight.codeplex.com/releases/view/60291

Recommended Download -> 클릭 -> Download

 

Using WP7 Toolkit Controls in Windows Phone 7.1 Mango

http://windowsphonegeek.com/tips/Using-WP7-Toolkit-Controls-in-Windows-Phone-7-1-Mango

페이지를 참고해서 Microsoft.Phone.Controls.Toolkit 프로젝트만 빌드를 해서 Microsoft.Phone.Controls.Toolkit.dll을 만든 후 프로젝트에 추가한다.

 

2) Windows Phone 7 Toolkit 추가 방법 2, Manage NuGet Packages를 이용해서 설치한다.

VS2010 -> Tools -> Library Package Manager -> Manage NuGet Packages…클릭

검색에 windows phone toolkit을 입력하면 Silverlight for Windows Phone Toolkit이라는 항목이 나온다.

선택 후 Install을 클릭하면 설치된다.

 

참고로 NuGet으로 추가하면 여러 가지 파일들이 함께 프로젝트에 추가가 된다.

 

2. LoadingView.xaml 만들기

 

Views폴더에

Add -> New Item -> Windows Phone User Control -> Name : LoadingView.xaml

F6을 누른 후 Blend로 이동한다.

 

 

완성된 로딩 화면 소스이다.

 

<UserControl

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"

           x:Class="BusInfo.Views.LoadingView"

    mc:Ignorable="d"

    FontFamily="{StaticResource PhoneFontFamilyNormal}"

    FontSize="{StaticResource PhoneFontSizeNormal}"

    Foreground="{StaticResource PhoneForegroundBrush}"

    d:DesignHeight="480" d:DesignWidth="480" Height="800" Width="480">

   

    <Grid x:Name="LayoutRoot">

 

          <Border BorderBrush="Black" BorderThickness="1" Opacity="0.5" Background="Black"/>

          <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" Text="잠시만 기다려 주세요" VerticalAlignment="Center" Margin="0,0,0,50"/>

 

          <toolkit:PerformanceProgressBar Margin="0" IsIndeterminate="True" RenderTransformOrigin="0.5,0.5"/>

 

    </Grid>

</UserControl>

 

3. MainPageViewModel.cs 추가

 

/// <summary>

/// 스플래쉬 팝업

/// </summary>

Popup Splash;

 

생성자에 추가

//스플래쉬 팝업 생성

Splash = new Popup() { IsOpen = false, Child = new LoadingView() };

 

SelectionChangedCommand, RefreshCommand, GetBusRouteListCommand

Splash.IsOpen = true; // 추가 위치는 하단에

 

wc_DownloadStringCompleted

Splash.IsOpen = false; // 추가 위치는 하단에

 

여기 까지 작성 한 후 테스트를 해보자. 너무 순식간에 지나간다면.. Splash.IsOpen = false; 문장을 잠깐 주석 처리 해서 확인 한다.

 

4. 버스 목록 정렬

버스 검색 했을 때 여러 대가 나올 때 정렬이 되어 있지 않아 찾기가 쉽지 않다. 그래서 정렬하는 코드를 추가한다.

BusRouteCollection = new ObservableCollection<BusRouteModel>(rows);

위의 코드를 찾아서 아래와 같이 수정한다.

BusRouteCollection = new ObservableCollection<BusRouteModel>(rows.OrderBy(p => p.BusRouteNm));

 

*즐겨 찾기 기능까지 완성된 화면

5. 즐겨 찾기 기능까지
설명을 하면 좋은데 지금 시간이 너무 늦어서..오늘은 이만 줄여야 할 것 같다. 내용이 너무 많아서 내일이나 모래 정리를 해서 올리도록 하겠다. 그럼 남은 시간 행복하게..

'Windows Phone 8 > Korea Bus Information' 카테고리의 다른 글

Seoul Bus Info Search App Dev 11  (0) 2012.01.13
Seoul Bus Info Search App Dev 10  (0) 2012.01.13
Seoul Bus Info Search App Dev 9  (0) 2012.01.12
My BusInfo app deploy  (0) 2012.01.08
Seoul Bus Info Search App Dev 7  (0) 2012.01.07
Seoul Bus Info Search App Dev 6  (0) 2012.01.07
블로그 이미지

kaki104

/// Microsoft MVP - Windows Development - Apr 2014 ~ Mar 2018 /// email : kaki104@daum.net, twitter : @kaki104, facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

블로그 이전을 성공적으로 마무리 했으니, 이제 강좌를 마무리 할 차례인 것 같다. 그런데 블로그 유입 통계를 보면 Search라는 검색어로 들어오는 유저들이 많은데.. 개발자들이 들어오는 것이 아닌 것 같은 불길한 느낌이 든다. -0- 또한, 어제 오늘 윈폰을 열심히 사용해 봤는데.. 아무래도 한글로 만들어진 엡은 찾아보기가 어렵다. 그러니, 강좌를 접한 분들은 꼭 하나씩 자신만의 엡을 만들어서 올려야 한다. 이렇게 자세하게 강좌를 올리는 이유가 쉽게 접근 할 수 있는 길을 하나 뚫어 주는 것이라고 생각하기 때문임을 잊으면 아니 된다.(잊으면 폭력행사 들어감 퍽!퍽~퍽@)

1. 어떤 버스의 노선 정보 인가?

MainPageViewModel.cs

BusRouteModel busCurrent;
/// <summary>
/// 선택된 버스 정보 프로퍼티
/// </summary>
public BusRouteModel BusCurrent
{
    get { return busCurrent; }
    set
    {
        busCurrent = value;
        FirePropertyChange("BusCurrent");
    }
}
프로퍼티를 추가한다.

SelectionChangedCommand에

//선택된 버스 정보 저장
BusCurrent = route;

코드 추가 F6키를 눌러서 빌드하고 Blend로 이동


1차 적으로 ContentPanel에 구역을 추가하고 상단 구역에 Grid를 추가 후 위와 같은 디자인을 만들었다. 지금 보이는 글씨들은 위치나 크기를 알아 보기 위해 직접 입력 해 놓은 데이터이다. 어느 정도 디자인이 완료가 되면 바인딩에 들어간다.

버스별 색상 입력
3100-1의정부라는 TextBlock은 Border로 Grouping되어 있으며, 우리는 Border에 Converter를 이용해서 색을 추가할 것이다.
Border 선택 -> BorderBrush 프로퍼티 오른쪽 네모 클릭 -> Data Binding -> BusCurrent 확장 -> RouteType 선택
-> Value converter 프로퍼티 오른쪽 Combobox -> RouteTypeToColorConverter 선택 -> OK
 


위와 같이 선택하면 Border의 테두리 색이 BusCurrent 프로퍼티의 RouteType에 따라서 변경이 된다.

이제 나머지 TextBlock로 각각 바인딩을 해 보자
1) 3100-1의정부 TextBlock 선택 -> Text 프로퍼티 오른쪽 네모 클릭 -> Data Binding -> BusCurrent 확장 -> BusRouteNm 선택 -> OK
2) 지선 TextBlock 선택 -> Text 프로퍼티 오른쪽 네모 클릭 -> Data Binding -> BusCurrent 확장 -> RouteType 선택
-> Value converter 오른쪽 Combobox -> RouteTypeToNameConverter 선택 -> OK
3) 내유동종점 TextBlock 선택 -> Text 프로퍼티 오른쪽 네모 클릭 -> Data Binding -> BusCurrent 확장 -> StartStationNm 선택 -> OK
4) 영등포소방서,타임스퀘어 TextBlock 선택 -> Text 프로퍼티 오른쪽 네모 클릭 -> Data Binding -> BusCurrent 확장 -> EndStationNm 선택 -> OK
** 전체적으로 화면 디자인을 변경하였기 때문에 MainPage.xaml, StationByRouteView.xaml, BusInfoResourceDictionary.xaml 파일의 전체 소스를 강좌 하단에 추가하도록 하겠다.
실행 결과를 확인해 보자
 

2. 운행 정보 추가하기
노선버스위치 정보 목록조회(http://api.bus.go.kr/contents/sub02/getBusPosByRtid.html) 서비스를 이용해서 운행 정보에 표시를 하면 된다. 그러면, 웹 페이지의 정보와 실제 반환 되는 결과를 가지고 모델을 만들어 보자.
(참고로 바인딩을 하지 않는 프로퍼티는 간단하게 줄여서 써도 상관없다.)

Models 폴더 -> Add -> Class -> name : BusPosModel.cs -> OK

BusPosModel.cs
using System.ComponentModel;
using System;

namespace BusInfo.Models
{
    //노선버스위치 정보 목록조회 http://api.bus.go.kr/contents/sub02/getBusPosByRtid.html
    //<busType>0</busType>
    //<dataTm>20111223181759</dataTm>
    //<gpsX>127.16104980422071</gpsX>
    //<gpsY>37.85877293616452</gpsY>
    //<lastStTm>15685</lastStTm>
    //<lastStnId>57431</lastStnId>
    //<nextStTm>0</nextStTm>
    //<plainNo>경기72바6196</plainNo>
    //<sectDist>1211</sectDist>
    //<sectOrd>3</sectOrd>
    //<sectionId>90011557</sectionId>
    //<stopFlag>1</stopFlag>
    //<vehId>12805</vehId>
    //<fullSectDist>1930</fullSectDist>
    //<trnstnid>6330</trnstnid>

    public class BusPosModel : INotifyPropertyChanged
    {
        #region PropertyChange
        public event PropertyChangedEventHandler PropertyChanged;

        private void FirePropertyChange(string PropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
            }
        }
        #endregion

        int sectOrd;
        /// <summary>
        /// 구간순번
        /// </summary>
        public int SectOrd
        {
            get { return sectOrd; }
            set
            {
                sectOrd = value;
                FirePropertyChange("SectOrd");
            }
        }

        float fullSectDist;
        /// <summary>
        /// 정류소간 거리
        /// </summary>
        public float FullSectDist
        {
            get { return fullSectDist; }
            set
            {
                fullSectDist = value;
                FirePropertyChange("FullSectDist");
            }
        }

        int sectDist;
        /// <summary>
        /// 구각옵셋거리Km
        /// </summary>
        public int SectDist
        {
            get { return sectDist; }
            set
            {
                sectDist = value;
                FirePropertyChange("SectDist");
            }
        }

        bool stopFlag;
        /// <summary>
        /// 정류소도착여부 (0:운행중, 1:도착)
        /// </summary>
        public bool StopFlag
        {
            get { return stopFlag; }
            set
            {
                stopFlag = value;
                FirePropertyChange("StopFlag");
            }
        }

        int sectionId;
        /// <summary>
        /// 구간ID
        /// </summary>
        public int SectionId
        {
            get { return trnstnId; }
            set
            {
                trnstnId = value;
                FirePropertyChange("TrnstnId");
            }
        }

        DateTime dataTm;
        /// <summary>
        /// 제공시간
        /// </summary>
        public DateTime DataTm
        {
            get { return dataTm; }
            set
            {
                dataTm = value;
                FirePropertyChange("DataTm");
            }
        }

        double gpsX;
        /// <summary>
        /// X좌표 WGS 84
        /// </summary>
        public double GpsX
        {
            get { return gpsX; }
            set
            {
                gpsX = value;
                FirePropertyChange("GpsX");
            }
        }

        double gpsY;
        /// <summary>
        /// Y좌표 WGS 84
        /// </summary>
        public double GpsY
        {
            get { return gpsY; }
            set
            {
                gpsY = value;
                FirePropertyChange("GpsY");
            }
        }

        int vehId;
        /// <summary>
        /// 버스 ID
        /// </summary>
        public int VehId
        {
            get { return vehId; }
            set
            {
                vehId = value;
                FirePropertyChange("VehId");
            }
        }

        string plainNo;
        /// <summary>
        /// 차량번호
        /// </summary>
        public string PlainNo
        {
            get { return plainNo; }
            set
            {
                plainNo = value;
                FirePropertyChange("PlainNo");
            }
        }

        int busType;
        /// <summary>
        /// 차량유형 (0:일반버스, 1:저상버스, 2:굴절버스)
        /// </summary>
        public int BusType
        {
            get { return busType; }
            set
            {
                busType = value;
                FirePropertyChange("BusType");
            }
        }

        int lastStTm;
        /// <summary>
        /// 종점도착소요시간
        /// </summary>
        public int LastStTm
        {
            get { return lastStTm; }
            set
            {
                lastStTm = value;
                FirePropertyChange("LastStTm");
            }
        }

        int lastStnId;
        /// <summary>
        /// 종점정류소ID
        /// </summary>
        public int LastStnId
        {
            get { return lastStnId; }
            set
            {
                lastStnId = value;
                FirePropertyChange("LastStnId");
            }
        }

        int nextStTm;
        /// <summary>
        /// 다음정류소도착소요시간
        /// </summary>
        public int NextStTm
        {
            get { return nextStTm; }
            set
            {
                nextStTm = value;
                FirePropertyChange("NextStTm");
            }
        }

        int trnstnId;
        /// <summary>
        /// 회차지정류소ID
        /// </summary>
        public int TrnstnId
        {
            get { return trnstnId; }
            set
            {
                trnstnId = value;
                FirePropertyChange("TrnstnId");
            }
        }
    }
}

모델이 다 만들어 졌으면, 이제 노선버스 위치 정보 조회 서비스를 호출해서 데이터를 넣어야 하는데.. 호출 위치는 정류소 목록의 조회 처리가 완료 된 후에 하는 것으로 하겠다. 왜냐하면, 기본적으로 WebClient는 한번에 하나의 처리만 가능하고, 정류소 목록이 없으면, 노선버스 위치 정보 데이터도 의미가 없기 때문이다.

MainPageViewModel.cs에 추가

ObservableCollection<BusPosModel> busPosCollection;
/// <summary>
/// 버스 위치 정보 컬렉션
/// </summary>
public ObservableCollection<BusPosModel> BusPosCollection
{
    get { return busPosCollection; }
    set
    {
        busPosCollection = value;
        FirePropertyChange("BusPosCollection");
    }
}


StationCollection = new ObservableCollection<StationByRouteModel>(stations); //<-- 소스가 있는 위치를 찾아서 그 아래 추가

//노선버스 위치 정보 조회
var uri = new Uri("http://ws.bus.go.kr/api/rest/buspos/getBusPosByRtid?ServiceKey=" + SKey.BusRouteInfo + "&busRouteId=" + BusCurrent.BusRouteId);
wc.DownloadStringAsync(uri, "GetBusPosByRtid");

//노선버스 위치 정보 파싱
case "GetBusPosByRtid":
 var busposs = from item in xml.Descendants("itemList")
              let dt = item.Element("dataTm").Value
              let year = dt.Substring(0, 4) + "-"
              let month = dt.Substring(4, 2) + "-"
              let day = dt.Substring(6, 2) + " "
              let hour = dt.Substring(8, 2) + ":"
              let min = dt.Substring(10, 2) + ":"
              let sec = dt.Substring(12, 2)
              select new BusPosModel
              {
                  BusType = Convert.ToInt32(item.Element("busType").Value),
                  DataTm = DateTime.Parse(year + month + day + hour + min + sec),
                  GpsX = Convert.ToDouble(item.Element("gpsX").Value),
                  GpsY = Convert.ToDouble(item.Element("gpsY").Value),
                  LastStTm = Convert.ToInt32(item.Element("lastStTm").Value),
                  LastStnId = Convert.ToInt32(item.Element("lastStnId").Value),
                  NextStTm = Convert.ToInt32(item.Element("nextStTm").Value),
                  PlainNo = item.Element("plainNo").Value,
                  SectDist = Convert.ToInt32(item.Element("sectDist").Value),
                  SectOrd = Convert.ToInt32(item.Element("sectOrd").Value),
                  SectionId = Convert.ToInt32(item.Element("sectionId").Value),
                  StopFlag = item.Element("stopFlag").Value == "1" ? true : false,
                  VehId = Convert.ToInt32(item.Element("vehId").Value),
                  FullSectDist = Convert.ToSingle(item.Element("fullSectDist").Value),
                  TrnstnId = Convert.ToInt32(item.Element("trnstnid").Value)
              };
BusPosCollection = new ObservableCollection<BusPosModel>(busposs);
break;

BusPosCollection에 데이터가 잘 들어오는지 확인 해보자.

지금부터 생각할 문제가 있는데, 우리는 정류소 정보와 위치 정보 2개의 데이터들을 조회해서 컬렉션에 담아 두었다. 그럼 이 2개의 데이터들을 어떻게 하나로 합쳐서 ListBox에 뿌려주고, 어떻게 바인딩을 할 것인가 라는 문제가 생긴다. ListBox에 ItemsSource는 1개의 프로퍼티만 바인딩이 가능하기 때문이다. 혹시, 2개가 바인딩이 된다고 하더라도 2개의 컬렉션들을 연결시키는 방법에 대한 문제가 남는다.

위의 문제를 해결하는 방법은 2개의 데이터를 하나로 묶어 주는 모델을 추가하고, 그 모델의 컬렉션 데이터를 만든 후 ListBox에 바인딩을 하면 깔끔하게 처리가 된다.

3. 연결 모델 추가

Models 폴더에 StationBusPosRow.cs 를 추가한다.

StationBusPosRow.cs

using System.ComponentModel;

namespace BusInfo.Models
{
    public class StationBusPosRow : INotifyPropertyChanged
    {
        #region PropertyChange
        public event PropertyChangedEventHandler PropertyChanged;

        private void FirePropertyChange(string PropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
            }
        }
        #endregion

        StationByRouteModel station;
        /// <summary>
        /// 정류소 정보
        /// </summary>
        public StationByRouteModel Station
        {
            get { return station; }
            set
            {
                station = value;
                FirePropertyChange("Station");
            }
        }

        BusPosModel busPos;
        /// <summary>
        /// 버스 위치 정보
        /// </summary>
        public BusPosModel BusPos
        {
            get { return busPos; }
            set
            {
                busPos = value;
                FirePropertyChange("BusPos");
            }
        }

    }
}

모델을 담을 컬렉션을 MainPageViewModel.cs에 추가

ObservableCollection<StationBusPosRow> rowCollection;
/// <summary>
/// 정류소 목록과 버스 위치 정보
/// </summary>
public ObservableCollection<StationBusPosRow> RowCollection
{
    get { return rowCollection; }
    set
    {
        rowCollection = value;
        FirePropertyChange("RowCollection");
    }
}

아까 추가했던 위치 정보 파싱하는 곳의 하단에 합치는 코드를 추가한다.

//2개의 컬렉션을 1개로 합치기 left join
var SBProws = from station in StationCollection
              join pos in BusPosCollection
              on station.Station equals pos.LastStnId into joiner
              from row in joiner.DefaultIfEmpty()
              select new StationBusPosRow
              {
                  Station = station,
                  BusPos = row
              };
RowCollection = new ObservableCollection<StationBusPosRow>(SBProws);

F6을 눌러서 빌드한 후 Blend로 이동해서 ListBox의 ItemsSource를 RowCollection으로 변경하고, StationDataTemplate에 Binding되어 있던 데이터들도 수정하고, 운행정보 TextBlock, 차량번호 TextBlock의 Text 프로퍼티에도 Binding을 추가한다. 아래는 수정된 템플릿 소스이다.

<DataTemplate x:Key="StationDataTemplate">
 <Border BorderThickness="0" Width="450">
  <Grid Height="64" >
   <Grid.ColumnDefinitions>
    <ColumnDefinition Width="0.8*"/>
    <ColumnDefinition Width="0.2*"/>
   </Grid.ColumnDefinitions>
   <Grid.RowDefinitions>
    <RowDefinition Height="0.5*"/>
    <RowDefinition Height="0.5*"/>
   </Grid.RowDefinitions>
   <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
    <TextBlock TextWrapping="Wrap" Text="{Binding Station.Seq}" Foreground="Gray"/>
    <TextBlock TextWrapping="Wrap" Text="{Binding Station.StationNo}" Margin="20,0,0,0" Foreground="Gray"/>
   </StackPanel>
   <TextBlock Grid.Column="1" TextWrapping="Wrap" Text="{Binding BusPos.StopFlag}" VerticalAlignment="Bottom" Foreground="White"/>
   <StackPanel Orientation="Horizontal" Grid.Row="1" VerticalAlignment="Top">
    <TextBlock TextWrapping="Wrap" Text="{Binding Station.StationNm}"/>
   </StackPanel>
   <TextBlock Grid.Column="1" TextWrapping="Wrap" Text="{Binding BusPos.PlainNo}" Grid.Row="1" FontSize="13.333" VerticalAlignment="Top" Foreground="Gray"/>
  </Grid>
 </Border>
</DataTemplate>

실행해서 결과를 확인 하자.

이제 마지막으로 true, false를 택스트로 변경할 Converter를 하나 추가하여 깔끔하게 마무리를 지어보자

4. StopFlagToTextConverter 추가

using System;
using System.Windows.Data;

namespace BusInfo.Converters
{
    public class StopFlagToTextConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool flag = System.Convert.ToBoolean(value);
            string returnValue = string.Empty;

            if (flag == true)
                returnValue = "도착";
            else
                returnValue = "운행중";

            return returnValue;
           
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

빌드 후 Blend에서 작업을 해서 추가하고, 실행해서 결과를 다시 확인 한다.

5. 위치 재조회 기능
버스 번호를 Button으로 변경하고 버튼을 누르면 위치 정보를 다시 조회해서 화면에 출력하도록 만들면 된다. 그런데, 여기에 한가지 문제점이 숨겨져 있다. 문제는 다시 DownloadStringAsync을 호출한다고 해도 동일한 결과만을 반환한다는 것이다.. 그 문제의 해결은 본인이 스스로 해보기 바란다.(구글을 통해서 찾으면 답이 있다)

6. 지금까지 작업한 최종 화면을 살펴 보자



7. 소스..

MainPage.xaml

<phone:PhoneApplicationPage
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:BusInfo_ViewModels="clr-namespace:BusInfo.ViewModels"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:BusInfo_Converters="clr-namespace:BusInfo.Converters"
    x:Class="BusInfo.MainPage"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">
 
 <phone:PhoneApplicationPage.Resources>
  <BusInfo_Converters:BoolToBoolRevConvert x:Key="BoolToBoolRevConvert"/>
 </phone:PhoneApplicationPage.Resources>
 <i:Interaction.Triggers>
  <i:EventTrigger>
   <i:InvokeCommandAction Command="{Binding LoadCommand, Mode=OneWay}"/>
  </i:EventTrigger>
 </i:Interaction.Triggers>
 
    <!--Sample code showing usage of ApplicationBar-->
    <!--<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>-->

 <phone:PhoneApplicationPage.FontFamily>
  <StaticResource ResourceKey="PhoneFontFamilyNormal"/>
 </phone:PhoneApplicationPage.FontFamily>
 <phone:PhoneApplicationPage.FontSize>
  <StaticResource ResourceKey="PhoneFontSizeNormal"/>
 </phone:PhoneApplicationPage.FontSize>
 <phone:PhoneApplicationPage.Foreground>
  <StaticResource ResourceKey="PhoneForegroundBrush"/>
 </phone:PhoneApplicationPage.Foreground>

 <d:DataContext>
  <BusInfo_ViewModels:MainPageViewModel/>
 </d:DataContext>

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="kaki104.tistory.com App" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="버스 목록 조회" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" FontSize="48" />
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
         <Grid.RowDefinitions>
          <RowDefinition Height="72"/>
          <RowDefinition/>
         </Grid.RowDefinitions>
         <StackPanel Orientation="Horizontal">
          <TextBlock TextWrapping="Wrap" Text="노선번호" VerticalAlignment="Center" Width="80"/>
          <TextBox TextWrapping="Wrap" Text="{Binding SBusNum, Mode=TwoWay}" Width="267" InputScope="Number"/>
          <Button Content="조회" IsEnabled="{Binding IsBusy, Converter={StaticResource BoolToBoolRevConvert}, Mode=OneWay}">
           <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
             <i:InvokeCommandAction Command="{Binding GetBusRouteListCommand, Mode=OneWay}"/>
            </i:EventTrigger>
           </i:Interaction.Triggers>
          </Button>
         </StackPanel>
         <ListBox Grid.Row="1" x:Name="listBox" ItemTemplate="{StaticResource BusRouteDataTemplate}" ItemsSource="{Binding BusRouteCollection}">
          <i:Interaction.Triggers>
           <i:EventTrigger EventName="SelectionChanged">
            <i:InvokeCommandAction Command="{Binding SelectionChangedCommand, Mode=OneWay}" CommandParameter="{Binding SelectedItem, ElementName=listBox}"/>
           </i:EventTrigger>
          </i:Interaction.Triggers>
         </ListBox>
        </Grid>
    </Grid>

</phone:PhoneApplicationPage>


StationbyRouteView.xaml

<phone:PhoneApplicationPage
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:BusInfo_ViewModels="clr-namespace:BusInfo.ViewModels"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    x:Class="BusInfo.Views.StationByRouteView"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">
 
    <!--Sample code showing usage of ApplicationBar-->
    <!--<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>-->

 <d:DataContext>
  <BusInfo_ViewModels:MainPageViewModel/>
 </d:DataContext>

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="kaki104.tistory.com App" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="경유정류소 &amp; 위치" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" FontSize="48"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
         <Grid.RowDefinitions>
          <RowDefinition Height="0.131*"/>
          <RowDefinition Height="0.869*"/>
         </Grid.RowDefinitions>
         <ListBox Grid.Row="1" ItemsSource="{Binding RowCollection}" ItemTemplate="{StaticResource StationDataTemplate}" Margin="0,-1,0,0"/>
         <Grid>
          <Grid.RowDefinitions>
           <RowDefinition Height="0.463*"/>
           <RowDefinition Height="0.537*"/>
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
           <ColumnDefinition Width="0.409*"/>
           <ColumnDefinition Width="0.591*"/>
          </Grid.ColumnDefinitions>
          <Button HorizontalAlignment="Center" Grid.RowSpan="2" VerticalAlignment="Center" Content="{Binding BusCurrent.BusRouteNm}" Background="{Binding BusCurrent.RouteType, Converter={StaticResource RouteTypeToColorConverter}}">
           <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
             <i:InvokeCommandAction Command="{Binding RefreshCommand, Mode=OneWay}"/>
            </i:EventTrigger>
           </i:Interaction.Triggers>
          </Button>
          <TextBlock Grid.Column="1" TextWrapping="Wrap" Text="{Binding BusCurrent.RouteType, Converter={StaticResource RouteTypeToNameConverter}}" Foreground="Gray" VerticalAlignment="Bottom"/>
          <StackPanel Grid.Column="1" Orientation="Horizontal" Grid.Row="1" d:LayoutOverrides="Height">
           <TextBlock TextWrapping="Wrap" Text="{Binding BusCurrent.StartStationNm}" Foreground="Gray" Height="45" VerticalAlignment="Top"/>
           <TextBlock TextWrapping="Wrap" Text="~" Foreground="Gray" Height="45" VerticalAlignment="Top"/>
           <TextBlock TextWrapping="Wrap" Text="{Binding BusCurrent.EndStationNm}" Foreground="Gray" Height="45" VerticalAlignment="Top"/>
          </StackPanel>
         </Grid>
        </Grid>
    </Grid>

</phone:PhoneApplicationPage>


BusInfoResourceDictionary.xaml

<ResourceDictionary
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:BusInfo_Converters="clr-namespace:BusInfo.Converters">
 <BusInfo_Converters:StopFlagToTextConverter x:Key="StopFlagToTextConverter"/>
 <BusInfo_Converters:RouteTypeToColorConverter x:Key="RouteTypeToColorConverter"/>
 <!-- Resource dictionary entries should be defined here. -->
 <BusInfo_Converters:RouteTypeToNameConverter x:Key="RouteTypeToNameConverter"/>
 
 <DataTemplate x:Key="BusRouteDataTemplate">
  <Grid Width="450" Height="64">
   <Grid.RowDefinitions>
    <RowDefinition Height="0.5*"/>
    <RowDefinition Height="0.5*"/>
   </Grid.RowDefinitions>
   <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
    <TextBlock TextWrapping="Wrap" Text="{Binding RouteType, Converter={StaticResource RouteTypeToNameConverter}}"/>
    <Border BorderThickness="10,0,0,0" BorderBrush="{Binding RouteType, Converter={StaticResource RouteTypeToColorConverter}}" Margin="20,0,0,0">
     <TextBlock TextWrapping="Wrap" Text="{Binding BusRouteNm}" Height="27" />
    </Border>
   </StackPanel>
   <StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Top">
    <TextBlock Text="{Binding StartStationNm}" Foreground="Gray" FontSize="18.667"/>
    <TextBlock TextWrapping="Wrap" Text=" ~ " Foreground="Gray" FontSize="18.667"/>
    <TextBlock Text="{Binding EndStationNm}" Foreground="Gray" FontSize="18.667"/>
   </StackPanel>
  </Grid>
 </DataTemplate>
 <DataTemplate x:Key="StationDataTemplate">
  <Border BorderThickness="0" Width="450">
   <Grid Height="64" >
    <Grid.ColumnDefinitions>
     <ColumnDefinition Width="0.8*"/>
     <ColumnDefinition Width="0.2*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
     <RowDefinition Height="0.5*"/>
     <RowDefinition Height="0.5*"/>
    </Grid.RowDefinitions>
    <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
     <TextBlock TextWrapping="Wrap" Text="{Binding Station.Seq}" Foreground="Gray"/>
     <TextBlock TextWrapping="Wrap" Text="{Binding Station.StationNo}" Margin="20,0,0,0" Foreground="Gray"/>
    </StackPanel>
    <TextBlock Grid.Column="1" TextWrapping="Wrap" Text="{Binding BusPos.StopFlag, Converter={StaticResource StopFlagToTextConverter}}" VerticalAlignment="Bottom" Foreground="White"/>
    <StackPanel Orientation="Horizontal" Grid.Row="1" VerticalAlignment="Top">
     <TextBlock TextWrapping="Wrap" Text="{Binding Station.StationNm}"/>
    </StackPanel>
    <TextBlock Grid.Column="1" TextWrapping="Wrap" Text="{Binding BusPos.PlainNo}" Grid.Row="1" FontSize="13.333" VerticalAlignment="Top" Foreground="Gray"/>
   </Grid>
  </Border>
 </DataTemplate>
</ResourceDictionary>

 

 

MainPageViewModel.cs

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Input;
using System.Xml.Linq;
using BusInfo.Functions;
using BusInfo.Models;
using Microsoft.Expression.Interactivity.Core;
using Microsoft.Phone.Controls;

namespace BusInfo.ViewModels
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        #region PropertyChange
        public event PropertyChangedEventHandler PropertyChanged;

        private void FirePropertyChange(string PropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
            }
        }
        #endregion

        /// <summary>
        /// 검색할 버스 노선 번호
        /// </summary>
        public string SBusNum { get; set; }

        /// <summary>
        /// 웹 클라이언트
        /// </summary>
        WebClient wc;

        bool isBusy;
        /// <summary>
        /// 웹 클라이언트 조회 중 여부
        /// </summary>
        public bool IsBusy
        {
            get { return isBusy; }
            private set
            {
                isBusy = value;
                FirePropertyChange("IsBusy");
            }
        }

        /// <summary>
        /// 인증 키
        /// </summary>
        ServiceKey SKey;

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

        BusRouteModel busCurrent;
        /// <summary>
        /// 선택된 버스 정보 프로퍼티
        /// </summary>
        public BusRouteModel BusCurrent
        {
            get { return busCurrent; }
            set
            {
                busCurrent = value;
                FirePropertyChange("BusCurrent");
            }
        }

        ObservableCollection<StationByRouteModel> stationCollection;
        /// <summary>
        /// 노선별 경유 정류소 컬렉션 - 프로퍼티
        /// </summary>
        public ObservableCollection<StationByRouteModel> StationCollection
        {
            get { return stationCollection; }
            set
            {
                stationCollection = value;
                FirePropertyChange("StationCollection");
            }
        }

        ObservableCollection<BusPosModel> busPosCollection;
        /// <summary>
        /// 버스 위치 정보
        /// </summary>
        public ObservableCollection<BusPosModel> BusPosCollection
        {
            get { return busPosCollection; }
            set
            {
                busPosCollection = value;
                FirePropertyChange("BusPosCollection");
            }
        }

        ObservableCollection<StationBusPosRow> rowCollection;
        /// <summary>
        /// 정류소 목록과 버스 위치 정보
        /// </summary>
        public ObservableCollection<StationBusPosRow> RowCollection
        {
            get { return rowCollection; }
            set
            {
                rowCollection = value;
                FirePropertyChange("RowCollection");
            }
        }

        //메인 프레임
        PhoneApplicationFrame root;

        /// <summary>
        /// 생성자
        /// </summary>
        public MainPageViewModel()
        {
            //웹클라이언트 생성
            wc = new WebClient();
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
            //서비스키 생성
            SKey = new ServiceKey();
        }

        /// <summary>
        /// 웹클라이언트 다운로드스트링 컴플릿트 이벤트 구현
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {

            IsBusy = wc.IsBusy;

            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;
                case "GetStaionByRoute":
                    //정류소 목록 파싱
                    var stations = from item in xml.Descendants("itemList")
                                   select new StationByRouteModel
                                   {
                                       BusRouteId = Convert.ToInt32(item.Element("busRouteId").Value),
                                       BusRouteNm = item.Element("busRouteNm").Value,
                                       Seq = Convert.ToInt32(item.Element("seq").Value),
                                       Section = Convert.ToInt32(item.Element("section").Value),
                                       Station = Convert.ToInt32(item.Element("station").Value),
                                       StationNm = item.Element("stationNm").Value,
                                       GpsX = Convert.ToDouble(item.Element("gpsX").Value),
                                       GpsY = Convert.ToDouble(item.Element("gpsY").Value),
                                       FullSectDist = Convert.ToSingle(item.Element("fullSectDist").Value),
                                       StationNo = Convert.ToInt32(item.Element("stationNo").Value),
                                       RouteType = Convert.ToInt32(item.Element("routeType").Value),
                                       BeginTm = item.Element("beginTm").Value,
                                       LastTm = item.Element("lastTm").Value,
                                       TrnstnId = Convert.ToInt32(item.Element("trnstnid").Value)
                                   };
                    StationCollection = new ObservableCollection<StationByRouteModel>(stations);

                    //노선버스 위치 정보 조회
                    var uri = new Uri("http://ws.bus.go.kr/api/rest/buspos/getBusPosByRtid?ServiceKey=" + SKey.BusRouteInfo + "&busRouteId=" + BusCurrent.BusRouteId);
                    wc.DownloadStringAsync(uri, "GetBusPosByRtid");
                    break;
                case "GetBusPosByRtid":
                    //버스 운행 정보 파싱
                    var busposs = from item in xml.Descendants("itemList")
                                  let dt = item.Element("dataTm").Value
                                  let year = dt.Substring(0, 4) + "-"
                                  let month = dt.Substring(4, 2) + "-"
                                  let day = dt.Substring(6, 2) + " "
                                  let hour = dt.Substring(8, 2) + ":"
                                  let min = dt.Substring(10, 2) + ":"
                                  let sec = dt.Substring(12, 2)
                                  select new BusPosModel
                                  {
                                      BusType = Convert.ToInt32(item.Element("busType").Value),
                                      DataTm = DateTime.Parse(year + month + day + hour + min + sec),
                                      GpsX = Convert.ToDouble(item.Element("gpsX").Value),
                                      GpsY = Convert.ToDouble(item.Element("gpsY").Value),
                                      LastStTm = Convert.ToInt32(item.Element("lastStTm").Value),
                                      LastStnId = Convert.ToInt32(item.Element("lastStnId").Value),
                                      NextStTm = Convert.ToInt32(item.Element("nextStTm").Value),
                                      PlainNo = item.Element("plainNo").Value,
                                      SectDist = Convert.ToInt32(item.Element("sectDist").Value),
                                      SectOrd = Convert.ToInt32(item.Element("sectOrd").Value),
                                      SectionId = Convert.ToInt32(item.Element("sectionId").Value),
                                      StopFlag = item.Element("stopFlag").Value == "1" ? true : false,
                                      VehId = Convert.ToInt32(item.Element("vehId").Value),
                                      FullSectDist = Convert.ToSingle(item.Element("fullSectDist").Value),
                                      TrnstnId = Convert.ToInt32(item.Element("trnstnid").Value)
                                  };
                    BusPosCollection = new ObservableCollection<BusPosModel>(busposs);


                    //2개의 컬렉션을 1개로 합치기 left join
                    var SBProws = from station in StationCollection
                                  join pos in BusPosCollection
                                  on station.Station equals pos.LastStnId into joiner
                                  from row in joiner.DefaultIfEmpty()
                                  select new StationBusPosRow
                                  {
                                      Station = station,
                                      BusPos = row
                                  };
                    RowCollection = new ObservableCollection<StationBusPosRow>(SBProws);
                    break;
            }

            if (1 == 1)
            {
            }
        }

        private ICommand getBusRouteListCommand;
        /// <summary>
        /// 노선 목록 조회 커맨드
        /// </summary>
        public ICommand GetBusRouteListCommand
        {
            get
            {
                if (getBusRouteListCommand == null)
                {
                    getBusRouteListCommand = new ActionCommand(() =>
                    {
                        if (SBusNum == null || SBusNum.Length <= 1)
                        {
                            MessageBox.Show("2글자 이상 입력해야 합니다.");
                            return;
                        }
                        //REST 형식 OpenAPI 호출
                        var uri = new Uri("http://ws.bus.go.kr/api/rest/busRouteInfo/getBusRouteList?ServiceKey=" + SKey.BusRouteInfo + "&strSrch=" + SBusNum);
                        //입력데이터 인코딩
                        SBusNum = Uri.EscapeUriString(SBusNum);
                        //비동기 호출, 호출 구분자로 GetBusRouteList를 사용함
                        wc.DownloadStringAsync(uri, "GetBusRouteList");

                        IsBusy = wc.IsBusy;
                    });
                }
                return getBusRouteListCommand;
            }
        }

        private ICommand selectionChangedCommand;
        /// <summary>
        /// 노선 목록에서 선택된 아이템이 변경된 경우 실행되는 커맨드
        /// </summary>
        public ICommand SelectionChangedCommand
        {
            get
            {
                if (selectionChangedCommand == null)
                {
                    selectionChangedCommand = new ActionCommand(item =>
                    {
                        //커맨드 파라메터로 전달 받은 오브젝트를 형변환
                        BusRouteModel route = item as BusRouteModel;
                        //형변환을 성공적으로 처리했다면
                        if (route != null)
                        {
                            //선택된 버스 정보 저장
                            BusCurrent = route;

                            //정류소 조회
                            var uri = new Uri("http://ws.bus.go.kr/api/rest/busRouteInfo/getStaionByRoute?ServiceKey=" + SKey.BusRouteInfo + "&busRouteId=" + route.BusRouteId);
                            wc.DownloadStringAsync(uri, "GetStaionByRoute");

                            //던지고 바로 정류소 목록 조회 화면으로 네비게이션
                            root.Navigate(new Uri("/Views/StationByRouteView.xaml", UriKind.Relative));
                        }
                    });
                }
                return selectionChangedCommand;
            }
        }

        private ICommand loadCommand;
        /// <summary>
        /// MainPage.xaml이 로드가 될때 실행
        /// </summary>
        public ICommand LoadCommand
        {
            get
            {
                if (loadCommand == null)
                {
                    loadCommand = new ActionCommand(() =>
                    {
                        //메인 프레임 입력 - 네비게이션하는데 필요
                        if (root == null)
                        {
                            //생성자에서는 이 데이터를 가지고 올 수가 없음..
                            root = App.Current.RootVisual as PhoneApplicationFrame;
                        }
                        //격리 저장소에 뷰모델을 저장
                        StaticFunctions.SaveToIS("MainPageViewModel", this);
                    });
                }
                return loadCommand;
            }
        }

        private ICommand refreshCommand;
        /// <summary>
        /// 위치 정보만 다시 조회
        /// </summary>
        public ICommand RefreshCommand
        {
            get
            {
                if (refreshCommand == null)
                {
                    refreshCommand = new ActionCommand(() =>
                    {
                        //노선버스 위치 정보 조회
                        var uri = new Uri("http://ws.bus.go.kr/api/rest/buspos/getBusPosByRtid?ServiceKey=" + SKey.BusRouteInfo + "&busRouteId=" + BusCurrent.BusRouteId);
                       
                        wc.DownloadStringAsync(uri, "GetBusPosByRtid");
                    });
                }
                return refreshCommand;
            }
        }
    }
}

8. 이제 기본 기능은 
완성이 된것 같다. 나머지는 즐겨 찾기 기능을 추가하는 정도만 하면 될 것 같다. 이제는 당장 사용해도 문제는 없으니 혹시 xap파일이 필요한 분은 리플로 요청을 하면 메일로 발송 하도록 하겠다.(물론 unlock이 되어야지만 실행이 가능하다.)
내일 부터는 버스가 언제 올지 궁금해 하지 않아도 되겠다. 하하하

'Windows Phone 8' 카테고리의 다른 글

Seoul Bus Info Search App Dev 8  (0) 2012.01.08
블로그 이미지

kaki104

/// Microsoft MVP - Windows Development - Apr 2014 ~ Mar 2018 /// email : kaki104@daum.net, twitter : @kaki104, facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

거의 1년 동안 기다리던 윈폰이 출시가 코앞으로 다가 왔다. 배고프면 뭐든지 다 맛있다는..이야기가 있듯이.. 많은 기다림이 있었으니 폰 사면 기분은 좋을 것 같은데.. 문제는 아직 국내 App이 별로 없다는 불편함이 있다.
그래서 이번 기회에 버스 정보 조회하는 엡을 하나 같이 만들면서 실버라이트에 대해서 배워보도록 하자.

처음에는 공공정보 엡 공모전이 있어서 그곳에 출품을 할까도 생각을 했었는데..프로젝트 진행 중이고..디자인 감각이 제로라..그냥 마음 편하게 강의만 올리기로 했다. 실버라이트를 잘 배워서 필요한 공공정보 엡은 많으니 모두 한팔, 다리하나 끼워서 거들어 주기를 바란다.

1. 공유자원포털(http://www.data.go.kr/Main.do)에 가입하자.
공공정보나 여러가지 OpenAPI를 이용하기 위해서는 각각에 해당하는 서비스별로 Key를 필요로 하는데, 이곳에 가입 후 자신이 만들고자 하는 프로그램에서 사용될 서비스를 선택하고 사용 신청을 해야 키를 발급받을 수 있다.

이곳에서 다루고자 하는 내용이 버스 관련 내용이므로..버스에 대한 서비스를 사용신청을 하고 하루이틀 지나면 승인이 된다. 승인 후에는 인증키 발급을 받아서 사용하면 된다.

여기서는 노선정보조회 서비스, 버스위치정보조회 서비스 정도가 사용된다.(진짜 크게 만들면 좋은데..생각보다 시간이 오래 걸릴것 같다는..ㅎ 딱 필요한 서비스만 가지고 최소한의 프로그램만 만들어 보자)

2. 서울특별시 교통정보센터(http://api.bus.go.kr/index.jsp)
이곳에서 각 서비스 별로 더 자세한 내용을 확인 할 수 있다.(예제라든가 결과 데이터에 대한 설명등을 추가로 얻을 수 있다.)

3. 기본 개발 환경 확인
Visual Studio 2010 SP1, Windows Phone SDK 7.1 Mango, Microsoft Expression Blend 4 정도가 설치되어 있으면 바로 시작 할 수 있다..없다면.. 설치하면 된다.

4. 실행 화면(테스트 버전..)

메인 화면



버스하나 선택시 상세 정류장 목록과 현재 버스 위치를 표시


5. 오늘은 즐거운 크리스마스 이브니..
열심히 코딩을 해보도록 하자..하하하;; 내일도 역시 코딩을..쿨럭..좀 자세하게 강좌를 작성할 예정이라 아마 상당히 많은 분량이 되지 않을까한다. 그리고 될 수 있으면 소스 올리지 않을려고 한다.

그럼..

Windows Phone 7 Mango 버스 정보 검색 App 만들기 1 (Windows Phone 7 Mango Seoul Bus Infomation Search App Dev 1)

'Windows Phone 8 > Korea Bus Information' 카테고리의 다른 글

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 4  (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
블로그 이미지

kaki104

/// Microsoft MVP - Windows Development - Apr 2014 ~ Mar 2018 /// email : kaki104@daum.net, twitter : @kaki104, facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/

티스토리 툴바