Download - 윈도우 8.1 앱개발 새로운 API 들
윈도우 8.1 앱개발새로운 API 들이길복 / 주신영
Speakers
이길복 MVP휴즈플로우 CTO주신영 MVP스마트쉐어 CEO
Windows 8.1: Free for all Windows 8 PCs
1
TextBlock<TextBlock Text="First line is using the defaults" />
<TextBlock Text="Second line"
FontSize="40" FontWeight="Bold" FontStyle="Italic"
FontFamily="Times New Roman"/>
<TextBlock Text="I will not be able to finish this sentence."
FontSize="30" HorizontalAlignment="Left" TextTrimming="WordEllipsis"
Width="450" />
<TextBlock Text="1/4, 1/2, 1/3, 3263827/8675309"
FontSize="40" TextAlignment="Right" Typography.Fraction="Slashed"/>
<TextBlock Text="Microsoft Windows"
FontSize="60" FontFamily="Gabriola" Foreground="Aqua"
Typography.StylisticSet4="True"/>
<TextBlock Text="Microsoft Windows"
FontSize="60" FontFamily="Gabriola"
Typography.StylisticSet5="True"/>
<TextBlock Text="Microsoft Windows"
FontSize="60" FontFamily="Gabriola" Foreground="LightGreen"
Typography.StylisticSet6="True"/>
<TextBlock Text="Microsoft Windows"
FontSize="60" Foreground="#FFAA00FF" FontFamily="Gabriola"
Typography.StylisticSet7="True"/>
RichTextBlock<RichTextBlock OverflowContentTarget="{Binding ElementName=SecondColumnOverflow}" FontSize="25" Grid.Column="0" Margin="5"> <Paragraph TextAlignment="Justify" Margin="5"> This is justified text. Lorem ipsum dolor sit amet, consectetur … </Paragraph> <Paragraph> <Hyperlink NavigateUri="http://microsoft.com" FontSize="25">Link to Microsoft Main Site</Hyperlink> </Paragraph> <Paragraph TextAlignment="Right" Margin="5"> This is right-justified text. Integer hendrerit diam vitae …. <InlineUIContainer> <Button Content="Button" Width="120" Height="40" /> </InlineUIContainer> <Run Foreground="LightBlue"> And so is this. Class aptent taciti sociosqu ad … </Run> </Paragraph> <Paragraph TextAlignment="Center" Margin="5"> This is centered text. Duis vel semper augue... <Run Text="This is some text in its own run, using its own text style" FontStyle="Italic" Foreground="Orange"/> This is also centered. In commodo eros … </Paragraph></RichTextBlock>
<RichTextBlockOverflow x:Name="SecondColumnOverflow" Grid.Column="1" Margin="5"/>
TextBox and PasswordBox<TextBox Text="Hello world" /> <TextBox Text="Headers can be templated" Header="TextBox Header Text"/>
<TextBox Text="I am going to the store for moar bread." Header="Spell-checking" IsSpellCheckEnabled="True"/>
<TextBox Header="Placeholder text" PlaceholderText="please enter your first name"/>
<TextBox Header="Color Font Support" Text="I like tapioca. 😀" IsColorFontEnabled="True" FontFamily="Segoe UI Emoji" />
<TextBox Text="For on-screen keyboards only" Header="Text Prediction" IsTextPredictionEnabled="True"/> <TextBox Text="[email protected]" Header="Input scope control" PlaceholderText="For touch keyboard" InputScope="EmailSmtpAddress"/>
<TextBox Text="Peter piper picked a peck" Header="Selection highlight color control" SelectionHighlightColor="Orange"/>
<PasswordBox Header="Please enter your password" FontSize="40" Margin="20" IsPasswordRevealButtonEnabled="True" Password="Password1" />
<TextBox InputScope="EmailSmtpAddress"/>
<TextBox InputScope="Formula"/>
<TextBox InputScope="Number"/>
Input scope키보드 레이아웃 결정 .
데이터 검증까지 제공하진 않음 .
좋은 UX 에 도움되는 것은 알지만 , 설정하는 것을 잊기 쉬운데…타블렛과 터치스크린 사용자들을 위해서 꼭 신경써줘야 할 것 .
DatePicker and TimePicker<DatePicker Header="Gregorian Calendar Identifier" CalendarIdentifier="GregorianCalendar" DayFormat="{}{day.integer} {dayofweek.full}" />
<DatePicker Header="Korean Calendar Identifier" CalendarIdentifier="KoreanCalendar" DayFormat="{}{day.integer} {dayofweek.full}" />
<DatePicker Header="Julian Calendar Identifier" CalendarIdentifier="JulianCalendar" DayFormat="{}{day.integer} {dayofweek.full}" />
<DatePicker Header="Day of week without day" DayFormat="{}{dayofweek.solo.full}" />
<DatePicker Header="Day of week abbreviated" DayFormat="{}{day.integer} {dayofweek.abbreviated}" />
<TimePicker Header="Time Picker with 12 hour clock" ClockIdentifier="12HourClock" />
<TimePicker Header="Time Picker with 24 hour clock" ClockIdentifier="24HourClock" />
Date
Pick
erTi
meP
icke
r
Flyouts<Button Content="Show Normal Flyout" Margin="100, 20, 100, 20"> <Button.Flyout> <Flyout> <StackPanel Width="250"> <TextBlock Text="Some header text" FontSize="24" Margin="0,0,0,20" FontWeight="Light" Foreground="CornflowerBlue"/> <TextBlock Text="This type of flyout is a ..." FontSize="16" TextWrapping="Wrap" /> <Button Content="Do Something" HorizontalAlignment="Right" Margin="0,20,0,0"/> </StackPanel> </Flyout> </Button.Flyout></Button>
<Button Content="Show Menu Flyout" Margin="20, 20, 100, 20"> <Button.Flyout> <MenuFlyout> <MenuFlyoutItem Text="Option 1" /> <MenuFlyoutItem Text="Option 2" /> <MenuFlyoutSeparator /> <ToggleMenuFlyoutItem Text="Toggle Option 1" IsChecked="True" /> <ToggleMenuFlyoutItem Text="Toggle Option 2" /> </MenuFlyout> </Button.Flyout></Button>
AppBar
Image<TextBlock Text="UI Resize" FontSize="30" /><Image Source="ms-appx:///Assets/Images/Pro2.png" Width="400"/>
<TextBlock Text="Decode Resize" FontSize="30" /><Image Width="400"> <Image.Source> <BitmapImage DecodePixelWidth="600" UriSource="ms-appx:///Assets/Images/Pro2.png" /> </Image.Source></Image>
DecodePixelWidth/Height불러올 때 크기를 제공하면 메모리를 절약할 수 있다 . 퍼포먼스도 좋아진다 . 확대 / 축소된 결과도 더 품질이 좋다 .
2
ChineseFrenchGermanIndianItalianMexican
DataData template
ListView
<ListView x:Name="ItemListView" Height="325" HorizontalAlignment="Left" ItemTemplate="{StaticResource StoreFrontTileTemplate}" ItemContainerStyle="{StaticResource ContainerStyle}" ShowsScrollingPlaceholders="False" BorderBrush="LightGray" BorderThickness="1" SelectionMode="None"/>
GridView<GridView x:Name="ItemGridView2" ItemTemplate="{StaticResource StoreFrontTileTemplate}" ItemContainerStyle="{StaticResource StoreFrontTileStyle}" ItemsPanel="{StaticResource StoreFrontGridItemsPanelTemplate}" ShowsScrollingPlaceholders="False" BorderBrush="LightGray" BorderThickness="1" />
<FlipView x:Name="FlipView1" Width="480" Height="270" BorderBrush="Black" BorderThickness="1"> <FlipView.ItemTemplate>
<DataTemplate> <Grid> <Image Width="480" Height="270" Source="{Binding Image}" Stretch="UniformToFill"/> <Border Background="#A5000000" Height="80" VerticalAlignment="Bottom"> <TextBlock Text="{Binding Title}" FontFamily="Segoe UI" FontSize="26.667" Foreground="#CCFFFFFF" Padding="15,20"/> </Border> </Grid> </DataTemplate>
</FlipView.ItemTemplate></FlipView>
Data
Tem
plat
eFlipView
DataContext for binding is the item being ren-dered
Panning perf overview – UI virtualization
Panning perf overview – UI virtualization
88.1
가상화 불가새 가상화는 기본으로 활성화 되어있음 .ItemsStackPanel 과 ItemsWrapGrid
가변사이즈 아이템을 지원할 때는 가상화 불가 .같은 크기에 , 같은 템플릿을 사용하는 경우에만 가상화 작동 .VariableSizedWrapGrid 는 가상화 불가
가상화 가능
가상화 불가
Large list performance
<GridViewItemPresenter SelectionCheckMarkVisualEnabled="False" SelectedBackground="#FFFF8c00" SelectedBorderThickness="5" />
+ =
퍼포먼스 개선불필요한 엘리먼트의 생성을 줄이기 .GridViewItemPresenter 의 사용 .
<GridView ShowsScrollingPlaceholders="true">
Placeholders 로 가시적인 퍼포먼스 개선
Incrementally updating the data tem-plate
GridView 의 ContainerContentChanging이벤트
3
Windows 8 view states
Full landscape
FilledSnapped
Full portrait
Windows in Windows 8.1
Wider than tall window
Taller than wide win-
dow
Taller than wide win-
dowTaller than wide
window
Windows 8.1 접근앱은 최소 500px 폭을 지원해야함 .세로로 긴 레이아웃을 지원할 것 .
320px 에서 499px 는 선택적으로 지원Page 기초 클래스나 View State 를 더 이상 지원 안 함 .이제 좋은 툴킷을 맘대로 쓰고 개발자 마음대로 하세용동시에 두 개 이상의 앱을 지원대형화면은 앱을 다섯 개까지 ! 보통은 두 , 세 가지 .
App-specific visual states<VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="PrimaryLayout"> <Storyboard> ... </Storyboard> </VisualState> <VisualState x:Name="NarrowLayout"> <Storyboard> ... </Storyboard> </VisualState> <VisualState x:Name="TallLayout"> <Storyboard> ... </Storyboard> </VisualState> <VisualState x:Name="ExtraLargeLayout"> <Storyboard> ... </Storyboard> </VisualState> </VisualStateGroup></VisualStateManager.VisualStateGroups>
Visual StatesVisual states 는 UI 와 코드를 분리해 주죠 .
코드에서 수동으로 엘리먼트 이동하고 , 크기변경하고 하는 대신에 간단히 이 변경사항들을 처리하는 Storyboard 를 가진 visual state 로 변경하는 게 깔끔하죠 .
Setting visual states from codeconst string _primaryVS = "PrimaryLayout";const string _narrowVS = "NarrowLayout";const string _tallVS = "TallLayout";const string _xlVS = "ExtraLargeLayout";
const double _minPrimaryWidth = 500.0;const double _maxPrimaryWidth = 1920.0;const double _maxPrimaryHeight = 1080.0;
Use constantsSizes and state names will almost certainly change during design iterations
void OnWindowSizeChanged(object sender, WindowSizeChangedEventArgs e){ if (e.Size.Width < _minPrimaryWidth) VisualStateManager.GoToState(this, _narrowVS, true);
else if (e.Size.Width < e.Size.Height) VisualStateManager.GoToState(this, _tallVS, true);
else if (e.Size.Width > _maxPrimaryWidth && e.Size.Width > _maxPrimaryWidth) VisualStateManager.GoToState(this, _xlVS, true);
else VisualStateManager.GoToState(this, _primaryVS, true);}
방향과 위치OrientationApplicationView.Orientation (Landscape 또는 Portrait 을 반환 )
PlacementApplicationView.AdjacentToLeftDisplayEdgeApplicationView.AdjacentToRightDisplayEdge
Full ScreenApplicationView.IsFullScreen
Window 크기페이지 불러올 때 창크기Window.Current.Bounds : 초기 크기런타임 사이즈는 Window.SizeChanged 이벤트 핸들러에서페이지가 사라질 때는 핸들러를 끊어주는 센스 !
Window 크기와 실제 화면 사이즈와는 아무 관계 없음 !전체화면일 때조차도 픽셀은 논리적 픽셀수 .
Handling the SizeChanged eventprotected override void OnNavigatedTo(NavigationEventArgs e){ navigationHelper.OnNavigatedTo(e); Window.Current.SizeChanged += OnWindowSizeChanged;}
protected override void OnNavigatedFrom(NavigationEventArgs e){ navigationHelper.OnNavigatedFrom(e); Window.Current.SizeChanged -= OnWindowSizeChanged;}
핸들러 제거하는 것 잊지 마세요 !팁 : 모든 닷넷 프로그램에서 메모리 누수가 발생하는 흔한 원인 중 하나가 제대로 이벤트 핸들러를 제거하지 않는 것이다 . 싱글턴 객체나 정적 클래스의 이벤트에 대한 핸들러는 꼭 제거합시다 .
Show
Cre-
ate
Setu
p wi
ndow
con
tent
Show a secondary viewvar view = CoreApplication.CreateNewView();
var viewId = 0;await view.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { viewId = ApplicationView.GetForCurrentView().Id;
var window = Window.Current; var frame = new Frame(); window.Content = frame;
frame.Navigate(typeof(SecondaryWindowContentPage)); });
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(viewId, ViewSizePreference.UseHalf, ApplicationView.GetForCurrentView().Id, ViewSizePreference.UseHalf);
ViewSizePrefer-enceDefault기본값은 UseHalf 와 같은 절반 .
UseMore가로 50% 이상을 차지UseHalf절반UseLess가로 50% 이하를 차지UseMinimumManifest 에 정해 놓은 최소값인320 또는 500 픽셀UseNone보여주지 않음
4Speech Synthesis
Speech synthesis
Voice David(en-US, 남성 )
Zira(en-US, 여성 )
Hazel(en-UK, 여성 )
Heami(ko-KR, 여성 )
외 13 개국 음성 지원
Code
Speech synthesis 단순 텍스트 음성 출력
synthesizeTextToStreamAsync PC 의 위치 설정에 따라 음성 지원
var synth = new Windows.Media.SpeechSynthesis.SpeechSynthe-sizer();
SpeechSynthesisStream stream = await synth.SynthesizeText-ToStreamAsync("Welcome!");
media.SetSource(stream, stream.ContentType); media.Play();
Speech synthesis SSML(Speech Synthesis Markup Lan-
guage) synthesizeSsmlToStreamAsync 음성 특징 , 발음 , 볼륨 , 피치 , 비율 / 속도 , 강도Code
string Ssml = @"<speak version='1.0' " + "xmlns='http://www.w3.org/2001/10/synthesis' xml:lang='en-US'>" + "<prosody contour='(0%,+80Hz) (10%,+80%) (40%,+80Hz)'>Welcome! Shinyoung" + "<break time='500ms' />" + "Have a good time" + "</prosody></speak>";
var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer(); SpeechSynthesisStream stream = await synth.SynthesizeSsmlToStrea-mAsync(Ssml);
media.SetSource(stream, stream.ContentType); media.Play();
5Contact &Appointment
Contact People 앱을 통한 연락처 관리
이메일 및 소셜 계정의 연락처 연동됨 모든 연락처의 추가 / 수정 / 삭제
ContactPickerUI 를 통한 연락처들 호출 ContactManager.ShowContactCard() 를
통해 바로 원하는 연락처의 ContactCard 를 호출
대부분의 사용자는 개인정보 유출에 대한 우려로 앱 자체에서 연락처정보의 관리 / 보호 / 저장 하는 것을 원하지 않음 .
Contact Picker Appxmanifest 에서 Contact Picker 사용 선언
Contact Picker
Code
ContactPicker picker = new ContactPicker();
picker.SelectionMode = ContactSelectionMode.Contacts;// Contact contacts = await picker.PickContactAsync(); // 1 개IList<Contact> contacts = await picker.PickContactsAsync(); // 여러개foreach (Contact contact in contacts){
// process each contact returnedDebug.WriteLine(contact.FirstName + " " +
contact.LastName);}ContactPickerUI 로 UI 를 커스텀 가능
Contact cardContact card workflow
View Profile
ContactManager
Source App Target App
From: Ben Miller
Windows Contact Store
Windows Runtime
Action + Object
ContactManagerCode
Contact contact = new Contact();contact.FirstName = " 주 ";contact.LastName = " 신영 ";
ContactEmail email = new ContactEmail();email.Address = “[email protected]";contact.Emails.Add(email);
Rect rect = Helper.GetElementRect(sender as FrameworkElement);ContactManager.ShowContactCard(contact, rect, Windows.UI.Popups.-Placement.Default);
Appointments
Calrendar 앱을 통한 일정 관리 이메일 및 소셜 계정의 일정 연동됨 모든 일정의 추가 / 수정 / 삭제
AppointmentManager. ShowAddAp-
pointmentAsync(…) 를 통해 바로 원하는 일정 ContactCard 를 호출
Appointments
Source App Target App
Windows Appointment
Store
Windows Runtime
Action + Object
AppointmentManager. ShowAddAppointmentAsync(…)
AppointmentsCode
private async void AddAppointment_Click(object sender, RoutedEventArgs e) { var appointment = new Appointment();
appointment.Subject = "Prepare for next session"; appointment.StartTime = DateTime.Now.AddMinutes(2); appointment.Duration = TimeSpan.FromHours(1); appointment.Location = "Speaker room"; appointment.Uri = new Uri("http://dev.windows.com"); appointment.Sensitivity = AppointmentSensitivity.Public; appointment.Details = "Nothing like a little procrastination!";
AppointmentsCode
Rect rect = Helper.GetElementRect(sender as FrameworkElement);
var id = await AppointmentManager.ShowAddAppointmentAsync( appointment, rect, Windows.UI.Popups.Placement.Above);
if (!string.IsNullOrEmpty(id)) ResultDisplay.Text = "Returned appointment id " + id; else ResultDisplay.Text = "Appointment not added."; } }
Contact &Appointmentdemo
6
Bluetooth in Windows 8.1
RFCOMM• General device control• Robots• Sphero• Netduino• Gadgeteer• More…
GATT• Custom and low-power devices• Smart watches• Health monitors• Fitness monitors• Home automation• More…
Windows 8.1 PC running your Windows Store app
Windows.Devices.Bluetooth.Rfcomm Windows.Devices.Bluetooth.GenericAt-tributeProfile
Bluetooth Pairing
Bluetooth RFCOMM: Connection Windows.Devices.Bluetooth.RfcommDeviceService _service;Windows.Networking.Sockets.StreamSocket _socket;
async void Initialize(){ // Enumerate devices with the object push service DeviceInformationCollection _DICollection = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync( RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));
if (_DICollection.Count > 0) { // Typically, check protection level and version compatibility here
// Initialize the target Bluetooth device _service = await RfcommDeviceService.FromIdAsync(services[0].Id);
// Create a standard networking socket and connect to the target _socket = new StreamSocket();
await _socket.ConnectAsync(_service.ConnectionHostName, _service.ConnectionServiceName, SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
// The socket is connected. Data transfer happens using standard WinRT Sockets API }}
Bluetooth RFCOMM: receiving data Socket..
StreamSocketListener socketListener = new StreamSocketListener();….
DataReader reader = new DataReader(socket.InputStream);
// Read the message.uint messageLength = reader.ReadByte();// Loads data from the input stream.uint actualMessageLength = await reader.LoadAsync(messageLength);
// Reads a string value from the input stream.string message = reader.ReadString(actualMessageLength);…..
Package.appxmanifest 중요 !
Bluetooth
demo
7
Industry-leading economics
Starts at 70%for new apps
Jumps to 80%once your app makes $25,000
Developer registration
$19 Individual
$99 Business
Registration cov-ers both Win-dows and Win-dows Phone
Trials
Trials Matter
70xdownloads
10%conversion
10xrevenue
Windows Phone Developer blog, March 2011
Simple time-based trials
/* No code*/
Initialize the licenseprivate void InitializeLicense(){#if DEBUG // debug license information licenseInformation = CurrentAppSimulator.LicenseInformation;#else // release license information licenseInformation = CurrentApp.LicenseInformation;#endif }
Use the right license providerWinRT provides the CurrentAppSimulator for testing trial mode, in-app purchases, and more without your app being listed in the Windows Store. CurrentApp is for submission to the Windows Store. You cannot submit an app which uses CurrentAppSimulator.
Handle license events...licenseInformation.LicenseChanged += new LicenseChangedEventHandler(OnLicenseChanged);
private void OnLicenseChanged(){ if (licenseInformation.IsActive) { if (licenseInformation.IsTrial) { // Show the features that are available during trial. } else { // Show the features that are available only with a full license. } } else { // A license is inactive only when there's an error. }}
Conditionally enable featuresprivate void EnableFeatures(){ if (licenseInformation.IsActive) { if (licenseInformation.IsTrial) { // trial mode. You decide if you should inform the user that the // feature is not available, or simply not enable the UI for the feature } else { // enable feature ... } }}
Hide or inform?You may find that providing a UI with a warning that the feature is only enabled in the full version is a better approach than simply hiding the feature. Whenever you prompt, be sure to give the user the option to purchase right then.
Trial
demo
Thank you!