티스토리 뷰
버스 정보 검색 엡 만들기 강좌를 빨리 마무리를 하기 위해 속도를 올리고 있는데… 따라 하기는 잘 진행이 되고 있는 지 궁금하다.
이렇게 이야기를 해도 반응은 거의 없으니..후딱 시작 해야겠다.
1. StationDataTemplate 만들기
처음에 BusRouteDataTemplate 만드는 방법을 참고해서 StationDataTemplate 만들어 보자.
완성된 템플릿
<DataTemplate x:Key="StationDataTemplate">
<Border BorderThickness="0" Width="450">
<Grid >
<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">
<TextBlock TextWrapping="Wrap" Text="◎ 순번 : "/>
<TextBlock TextWrapping="Wrap" Text="{Binding Seq}"/>
<TextBlock TextWrapping="Wrap" Text="◎ 정류장번호 : " Margin="10,0,0,0"/>
<TextBlock TextWrapping="Wrap" Text="{Binding StationNo}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="1">
<TextBlock TextWrapping="Wrap" Text="◎ 정류장 : "/>
<TextBlock TextWrapping="Wrap" Text="{Binding StationNm}"/>
</StackPanel>
<TextBlock Grid.Column="1" TextWrapping="Wrap" Text="운행정보"/>
<TextBlock Grid.Column="1" TextWrapping="Wrap" Text="차량번호" Grid.Row="1" FontSize="13.333" VerticalAlignment="Center"/>
</Grid>
</Border>
</DataTemplate>
실행해서 결과를 확인한다.
2. 중복 조회를 하지 못하게 조회 버튼 막기
WebClient를 이용해서 조회를 한번 실행 후 결과를 기다리는 동안 다시 조회를 실행하지 못하도록 BoolToBoolRevConvert를 하나 만들어서 처리하자.
using System;
using System.Windows.Data;
namespace BusInfo.Converters
{
public class BoolToBoolRevConvert : IValueConverter
{
/// <summary>
/// IsBusy 프로퍼티 데이터를 반대로 반환하는 컨버터
/// IsBusy가 True이면 조회 중이기 때문에 조회 버튼의 IsEnabled를 False로 변경해 주어야 하고
/// IsBusy가 False이면 조회를 할 수 있기 때문에 버튼의 Isenabled를 True로 변경해 주는 작업이 필요
/// 이런 작업을 하기 위해 만든 컨버터
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool isbusy = System.Convert.ToBoolean(value);
bool returnValue = false;
if (isbusy == true)
returnValue = false;
else
returnValue = true;
return returnValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
MainPageViewModel.cs에서 IsBusy 프로퍼티를 추가한다.
/// <summary>
/// 웹 클라이언트
/// </summary>
WebClient wc;
bool isBusy;
/// <summary>
/// 웹 클라이언트 조회 중 여부
/// </summary>
public bool IsBusy
{
get { return isBusy; }
private set
{
isBusy = value;
FirePropertyChange("IsBusy");
}
}
GetBusRouteListCommand에서
//비동기 호출, 호출 구분자로 GetBusRouteList를 사용함
wc.DownloadStringAsync(uri, "GetBusRouteList");
IsBusy = wc.IsBusy; //여기 하나 추가
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)에서
IsBusy = wc.IsBusy; //맨 첫 번째 줄에 하나 추가
F6을 눌러 빌드 해준다. 이제 Blend로 이동한다.
조회 버튼 클릭 -> IsEnabled 프로퍼티 오른쪽에 네모 선택 -> Data Binding 선택
IsBusy 프로퍼티 선택 -> Value Converter 오른쪽에 […] 선택 -> BoolToBoolRevConvert 선택 -> OK
여기까지 확인 되었으면 OK 실행해서 결과를 확인하자.
조회 글씨가 회색으로 변한 것을 볼 수 있다.(조회가 완료되기 전까지는 조회 버튼과 작별이다)
3. 뷰 모델 저장하는 위치 수정
MainPageViewModel.cs의 생성자에 넣어 놓았던,
//격리 저장소에 뷰모델을 저장
StaticFunctions.SaveToIS("MainPageViewModel", this);
이 부분에 오류가 발생한다. 위치를 변경한다.
private ICommand loadCommand;
/// <summary>
/// 엡이 로드가 될때 실행
/// </summary>
public ICommand LoadCommand
{
get
{
if (loadCommand == null)
{
loadCommand = new ActionCommand(() =>
{
//격리 저장소에 뷰모델을 저장
StaticFunctions.SaveToIS("MainPageViewModel", this);
});
}
return loadCommand;
}
}
그리고 Blend에서 InvokeCommandAction을 PhoneApplicationPage에 추가 하고
EventName : Loaded -> Command : LoadCommand로 선택 해준다.
이렇게 하면 폼이 로드 될 때 한번 실행된다.
4. 1번에서 DataTemplate을 이용해서 경유정류소 목록을 조회해 봤는데..약간 부족한 점은 도대체 무슨 어떤 버스의 정류소 목록인지를 알 수가 없는 것과 운행정보, 차량 번호를 표시하지 못하는 것이다. 그 부분은 다음 강좌에서 처리하도록 하겠다.
추가로 약간의 수정 사항이 있는데 그것은 뷰 모델의 전체 소스를 참고 하기 바란다.
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");
}
}
ObservableCollection<StationByRouteModel> stationCollection;
/// <summary>
/// 노선별 경유 정류소 컬렉션 - 프로퍼티
/// </summary>
public ObservableCollection<StationByRouteModel> StationCollection
{
get { return stationCollection; }
set
{
stationCollection = value;
FirePropertyChange("StationCollection");
}
}
//메인 프레임
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);
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)
{
//정류소 조회
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;
}
}
}
}
5. 버스 정보를 제공하는..
서버가 응답 속도가 평소에 비해 무지하게 느린 것이 날씨가 추워서 성능 저하가 된 것 같다.
앞으로 2회 강좌로 마무리를 할 수 있도록 노력하겠다.
'Previous Platforms > KBI' 카테고리의 다른 글
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 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 |
- Total
- Today
- Yesterday
- kiosk
- PRISM
- LINQ
- ComboBox
- windows 11
- ef core
- MVVM
- XAML
- .net 5.0
- #Windows Template Studio
- uno platform
- #MVVM
- #prism
- Windows 10
- Build 2016
- Always Encrypted
- dotNETconf
- UWP
- IOT
- WPF
- visual studio 2019
- Visual Studio 2022
- .net
- #uwp
- Behavior
- Bot Framework
- Cross-platform
- uno-platform
- Microsoft
- C#
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |