티스토리 뷰

반응형

강좌가 길어져서 2번에 나누어서 작성한다.

1. 데이터의 저장과 복구
이글을 보기 전에 먼저 아래 링크에서 대략적인 내용을 읽어 볼 것을 권한다.

Execution Model Overview for Windows Phone
http://msdn.microsoft.com/en-us/library/ff817008(v=vs.92).aspx

윈폰7 App은 어러가지 4가지 Event와 3가지 상태를 가지게 되는데,
Event는 Application Launching, Application Closing, Application Deactivated, Application Activated
State는 Running, Dormant, Tombstoned이다.
쉽게 이야기하면 App실행 시키다가(Running상태) 윈도우 버튼을 눌러서 바탕화면으로 넘어가면 Dormant상태로 변하고, 그 상태로 좀더 있으면 Tombstoned상태로 변하는데 이 상태가 되면 엡이 사용하던 메모리를 모두 날리게 된다.

상태를 왜 이야기 하는가? 여기서 Running상태였다가 Dormant상태로 변경 되었다가 언제 Tombstoned으로 넘어갈지 모르기 때문에, Dormant 상태로 넘어가면 데이터를 저장 해야 하는 필요성이 있는 것이다. 대부분의 데이터는 인터넷을 통해서 전달되어 지는 데이터 있데, 이 데이터를 매번 다시 받아 와야 한다면 무제한 요금제가 아닌 분들에게는 너무나 가혹한 일이 될 것이기 때문이다. 그래서 이번 강좌에서는 거의 전체 소스 목록을 적어 놓겠다. 그리고, 저장과 복구에 해당하는 부분은 굵은 글씨로 표시 해서 구분을 하겠다.

2. App.xaml.cs - 일부 소스

private void Application_Activated(object sender, ActivatedEventArgs e)
{
    //엡의 상태가 복구되면 격리 저장소의 데이터를 복구 시킨다.
    StaticFunctions.ActiveApp();
}

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
    //상태가 변경될 때 격리 저장소의 데이터를 저장한다.
    StaticFunctions.SaveIS();
}

private void Application_Closing(object sender, ClosingEventArgs e)
{
    //엡이 종료될 때 격리 저장소의 데이터를 저장한다.
    StaticFunctions.SaveIS();
}


3. StaticFunctions.cs

using System.IO.IsolatedStorage;
using BusInfo.ViewModels;
using System.Linq;

namespace BusInfo.Functions
{
    public static class StaticFunctions
    {
        /// <summary>
        /// 격리 저장소에 데이터 저장
        /// </summary>
        /// <param name="key">키</param>
        /// <param name="data">데이터</param>
        /// <returns></returns>
        public static bool AddToIS(string key, object data)
        {
            if (IsolatedStorageSettings.ApplicationSettings.Contains(key) == false)
            {
                IsolatedStorageSettings.ApplicationSettings.Add(key, data);
            }
            else
            {
                IsolatedStorageSettings.ApplicationSettings[key] = data;
            }
            return true;
        }

        /// <summary>
        /// 격리 저장소에서 데이터 조회
        /// </summary>
        /// <param name="key">키</param>
        /// <returns>데이터</returns>
        public static object GetFromIS(string key)
        {
            object data;
            if (IsolatedStorageSettings.ApplicationSettings.Contains(key) == false)
            {
                data = null;
            }
            else
            {
                data = IsolatedStorageSettings.ApplicationSettings[key];
            }

            return data;
        }

        /// <summary>
        /// 격리 저장소에서 데이터 삭제
        /// </summary>
        /// <param name="key"></param>
        public static void RemoveFromIS(string key)
        {
            if (key == "all")
            {
                IsolatedStorageSettings.ApplicationSettings.Clear();
            }
            else
            {
                IsolatedStorageSettings.ApplicationSettings.Remove(key);
            }
        }

        /// <summary>
        /// 격리 저장소에 데이터 저장
        /// </summary>
        public static void SaveIS()
        {
            var vm = GetFromIS("ViewModel");
            if (vm != null)
            {
                MainPageViewModel ViewModel = vm as MainPageViewModel;
                //저장 전에 데이터에 연결된 ICommand를 제거한다. 이렇게 해야 저장이 된다.
                var r1 = (from row in ViewModel.RowCollection
                          select row.AddCommand = null).Count();

                var r2 = (from row in ViewModel.FavoriteCollection
                          select row.RemoveCommand = null).Count();
            }
            //격리 저장소에 저장
            IsolatedStorageSettings.ApplicationSettings.Save();
        }

        /// <summary>
        /// 엑티브 되었을때
        /// </summary>
        public static MainPageViewModel ActiveApp()
        {
            MainPageViewModel ViewModel;

            var vm = GetFromIS("ViewModel");
            if (vm == null)
            {
                //뷰모델 인스턴스
                ViewModel = new MainPageViewModel();
                StaticFunctions.AddToIS("ViewModel", ViewModel);

                //즐겨찾기 목록 초기화
                ViewModel.FavoriteCollection = new ObservableCollection<FavoriteRow>();
                StaticFunctions.AddToIS("Favorites", ViewModel.FavoriteCollection);
            }
            else
            {
                ViewModel = vm as MainPageViewModel;
                //복구된 데이터들에 ICommand 연결을 복구해준다.
                if (ViewModel.RowCollection != null
                    && ViewModel.RowCollection.Count > 0
                    && ViewModel.RowCollection.FirstOrDefault().AddCommand == null)
                {
                    var r1 = (from row in ViewModel.RowCollection
                              select row.AddCommand = ViewModel.AddCommand).Count();
                }

                if (ViewModel.FavoriteCollection != null
                    && ViewModel.FavoriteCollection.Count > 0
                    && ViewModel.FavoriteCollection.FirstOrDefault().RemoveCommand == null)
                {
                    var r2 = (from row in ViewModel.FavoriteCollection
                              select row.RemoveCommand = ViewModel.RemoveCommand).Count();
                }
            }
            return ViewModel;
        }
    }
}

4. MainPage.xaml.cs

using System.ComponentModel;
using BusInfo.ViewModels;
using Microsoft.Phone.Controls;
using BusInfo.Functions;

namespace BusInfo
{
    public partial class MainPage : PhoneApplicationPage
    {
        /// <summary>
        /// 뷰모델
        /// </summary>
        public MainPageViewModel ViewModel { get; set; }

        // Constructor
        public MainPage()
        {
            InitializeComponent();

            //디자인 타임이 아닌 경우 실행
            if (!DesignerProperties.IsInDesignTool)
            {
                //뷰모델을 격리 저장소에서 받아서 DataContext에 입력
                ViewModel = StaticFunctions.ActiveApp();
                this.DataContext = ViewModel;
            }
        }
    }
}


5. StationByRouteView.xaml.cs

using System.ComponentModel;
using System.Windows;
using BusInfo.Functions;
using BusInfo.ViewModels;
using Microsoft.Phone.Controls;

namespace BusInfo.Views
{
    public partial class StationByRouteView : PhoneApplicationPage
    {
        //뷰모델을 프로퍼티로 선언하고
        public MainPageViewModel ViewModel { get; set; }

        /// <summary>
        /// 생성자
        /// </summary>
        public StationByRouteView()
        {
            InitializeComponent();

            //언로드 이벤트 추가
            this.Unloaded += new RoutedEventHandler(StationByRouteView_Unloaded);

            //디자인 타임이 아닌 경우 실행
            if (!DesignerProperties.IsInDesignTool)
            {
                //뷰모델을 격리 저장소에서 받아서 DataContext에 입력
                ViewModel = StaticFunctions.ActiveApp();
                this.DataContext = ViewModel;

                //뷰모델의 프로퍼티 체인지 이벤트 추가
                ViewModel.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged);
            }
        }

        /// <summary>
        /// 언로드 이벤트 - 네이게이션을 하면 항상 새로운 페이지를 만들어 준다. 그래서, 이곳이 필요 
        /// 더 자세한 사항은 이 부분을 지우고 실행 해보면 어떤 결과가 나오는지 알 수 있을 것이다.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void StationByRouteView_Unloaded(object sender, RoutedEventArgs e)
        {
            if (ViewModel != null)
            {
                //뷰모델의 프로퍼티 이벤트 제거
                ViewModel.PropertyChanged -= ViewModel_PropertyChanged;
                //뷰모델과의 링크 제거
                ViewModel = null;
            }
        }

        /// <summary>
        ///  뷰모델 프로퍼티 체인지 이벤트 구현
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "RowCollectionChanged":
                    //정류소 목록 구성 완료 이벤트 처리
                    if (ViewModel.FavoriteCurrent != null)
                    {
                        //리스트 박스에 아이템 하나를 선택하고,
                        listBox.SelectedValue = ViewModel.FavoriteCurrent.Station.Station;
                        //리스트 박스 내용 한번 확인 시키고
                        listBox.UpdateLayout();
                        //리스트 박스에 선택된 아이템으로 화면 이동
                        listBox.ScrollIntoView(listBox.SelectedItem);
                    }
                    break;
            }
        }
    }
}

6. MainPageViewModel.cs

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Xml.Linq;
using BusInfo.Models;
using BusInfo.Views;
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

        string sBusNum;
        /// <summary>
        /// 검색할 버스 노선 번호
        /// </summary>
        public string SBusNum
        {
            get { return sBusNum; }
            set
            {
                sBusNum = value;
                FirePropertyChange("SBusNum");
            }
        }

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

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

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

        /// <summary>
        /// 스플래쉬 팝업
        /// </summary>
        Popup Splash;

        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");
            }
        }

        ObservableCollection<FavoriteRow> favoriteCollection;
        /// <summary>
        /// 즐겨찾기 목록
        /// </summary>
        public ObservableCollection<FavoriteRow> FavoriteCollection
        {
            get { return favoriteCollection; }
            set
            {
                favoriteCollection = value;
                FirePropertyChange("FavoriteCollection");
            }
        }

        FavoriteRow favoriteCurrent;
        /// <summary>
        /// 선택된 즐겨 찾기 정보 프로퍼티
        /// </summary>
        public FavoriteRow FavoriteCurrent
        {
            get { return favoriteCurrent; }
            set
            {
                favoriteCurrent = value;
                FirePropertyChange("FavoriteCurrent");
            }
        }

        //메인 프레임
        PhoneApplicationFrame root;

        /// <summary>
        /// 생성자
        /// </summary>
        public MainPageViewModel()
        {
            //웹클라이언트 생성
            wc = new WebClient();
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
            //서비스키 생성
            SKey = new ServiceKey();
            //스플래쉬 팝업 생성
            Splash = new Popup() { IsOpen = false, Child = new LoadingView() };
        }

        /// <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.OrderBy(p => p.BusRouteNm));

                    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 + "&junk=" + DateTime.Now);
                    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,
                                      AddCommand = this.AddCommand
                                  };
                    RowCollection = new ObservableCollection<StationBusPosRow>(SBProws);

                    //정류소 목록 바인딩 완료 되었다는 이벤트를 강제로 발생
                    FirePropertyChange("RowCollectionChanged");
                    break;
            }
            //스프레시 팝업 닫기
            Splash.IsOpen = false;
        }

        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");

                        SBusNum = "";
                        IsBusy = wc.IsBusy;
                        Splash.IsOpen = true;
                    });
                }
                return getBusRouteListCommand;
            }
        }

        private ICommand selectionChangedCommand;
        /// <summary>
        /// 노선 목록에서 선택된 아이템이 변경된 경우 실행되는 커맨드
        /// </summary>
        public ICommand SelectionChangedCommand
        {
            get
            {
                if (selectionChangedCommand == null)
                {
                    selectionChangedCommand = new ActionCommand(item =>
                    {
                        //WC가 바쁠때나 item이 null일 때는 건들이지 않는다,
                        if (wc.IsBusy == true || item == null)
                            return;

                        //item의 형이름을 가지고 구분해서 처리한다.
                        BusRouteModel route;
                        switch (item.GetType().Name)
                        {
                            case "BusRouteModel":
                                //커맨드 파라메터로 전달 받은 오브젝트를 형변환
                                route = item as BusRouteModel;
                                //현재 선택된 즐겨 찾기 지운다.
                                FavoriteCurrent = null;
                                break;
                            case "FavoriteRow":
                                //형변환
                                route = (item as FavoriteRow).Bus;
                                //즐겨 찾기 선택
                                FavoriteCurrent = item as FavoriteRow;
                                break;
                            default:
                                route = null;
                                break;
                        }
                        //형변환을 성공적으로 처리했다면
                        if (route != null)
                        {
                            //로딩 화면 출력
                            Splash.IsOpen = true;
                            //선택된 버스 정보 저장
                            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;
                        }
                    });
                }
                return loadCommand;
            }
        }

        private ICommand refreshCommand;
        /// <summary>
        /// 위치 정보만 다시 조회
        /// </summary>
        public ICommand RefreshCommand
        {
            get
            {
                if (refreshCommand == null)
                {
                    refreshCommand = new ActionCommand(() =>
                    {
                        Splash.IsOpen = true;

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

        private ICommand addCommand;
        /// <summary>
        /// 즐겨찾기 추가
        /// </summary>
        public ICommand AddCommand
        {
            get
            {
                if (addCommand == null)
                {
                    addCommand = new ActionCommand(item =>
                    {
                        //CommandParameter로 받아온 아이템을 형변환한다.
                        StationBusPosRow row = item as StationBusPosRow;
                        //즐겨찾기 컬렉션에 추가한다. 새로 만들면서 현재 버스 정보, 선택된 row에 있는 정류소 정보를 함께 저장한다.
                        //추가로 MainPageViewModel에 있는 RemoveCommand 링크도 함께 넣는다.
                        FavoriteCollection
                            .Add(new FavoriteRow
                            {
                                Bus = BusCurrent,
                                Station = row.Station,
                                RemoveCommand = this.RemoveCommand
                            });
                        //즐겨찾기 목록을 정렬한다.
                        var sort = FavoriteCollection.OrderBy(p => p.Bus.BusRouteNm).ThenBy(p => p.Station.Station);
                        FavoriteCollection = new ObservableCollection<FavoriteRow>(sort);
                        MessageBox.Show("즐겨찾기에 추가 되었습니다.");
                    });
                }
                return addCommand;
            }
        }

        private ICommand removeCommand;
        /// <summary>
        /// 즐겨찾기 제거
        /// </summary>
        public ICommand RemoveCommand
        {
            get
            {
                if (removeCommand == null)
                {
                    removeCommand = new ActionCommand(item =>
                    {
                        //즐겨찾기 아이템 하나를 형변환
                        FavoriteRow row = item as FavoriteRow;
                        if (row != null)
                        {
                            //컬렉션에서 제거
                            FavoriteCollection.Remove(row);
                        }
                        MessageBox.Show("즐겨찾기에서 제거 되었습니다.");
                    });
                }
                return removeCommand;
            }
        }

        private ICommand nextCommand;
        /// <summary>
        /// 정류소 목록 화면으로
        /// </summary>
        public ICommand NextCommand
        {
            get
            {
                if (nextCommand == null)
                {
                    nextCommand = new ActionCommand(() =>
                    {
                        root.Navigate(new Uri("/Views/StationByRouteView.xaml", UriKind.Relative));
                    });
                }
                return nextCommand;
            }
        }

    }
}

7. 중요한 부분의 소스는 모두 오픈 한것 같다.
전체 프로젝트는 소스는 http://kaki104.codeplex.com/ 이곳에 올릴 예정(정리를 좀 해야하니 몇일 걸릴 듯하다)이니 많은 참고를 바란다. 추가 의문 사항은 페이스북, 트위터, 리플 등으로 요청하면 알려 주도록 하겠다.
음..처음 완성한 윈폰엡과 윈폰 강좌라 잘 되었는지 모르겠다. 강좌를 하면서 항상 느끼는 점이지만..강좌는 다른 사람에게도 도움이 되지만, 나 자신에게도 많은 공부가 된다. 앞으로 이 글을 보고 한국 윈폰엡을 마켓에서 자주 볼 수 있었으면 하는 것이 바람이고, 많은 윈폰 유저들이 이 버스 엡을 좋아해 주었으면 한다.

반응형
댓글