Speakers 이길복 MVP 휴즈플로우 CTO 주신영 MVP 스마트쉐어 CEO Windows 8.1: Free for all Windows 8 PCs TextBlock TextBlock TextBlock FontSize="40" FontWeight="Bold" FontStyle="Italic" FontFamily="Times New Roman" TextBlock TextTrimming="WordEllipsis" TextBlock Typography.Fraction="Slashed" TextBlock Typography.StylisticSet4="True" TextBlock Typography.StylisticSet5="True" TextBlock Typography.StylisticSet6="True" TextBlock Typography.StylisticSet7="True" RichTextBlock RichTextBlock OverflowContentTarget="{Binding ElementName=SecondColumnOverflow}" Paragraph Paragraph Paragraph Hyperlink Hyperlink Paragraph Paragraph InlineUIContainer Button InlineUIContainer Run Run Paragraph Paragraph Run Paragraph RichTextBlock RichTextBlockOverflow x:Name="SecondColumnOverflow" 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. &#x1F600;" IsColorFontEnabled="True" FontFamily="Segoe UI Emoji" /> <TextBox Text="For on-screen keyboards only" Header="Text Prediction" IsTextPredictionEnabled="True"/> <TextBox Text="pete@contoso.com" 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" /> Input scope <TextBox InputScope="EmailSmtpAddress"/> <TextBox InputScope="Formula"/> <TextBox InputScope="Number"/> DatePicker and TimePicker DatePicker CalendarIdentifier="GregorianCalendar" DatePicker DatePicker CalendarIdentifier="KoreanCalendar" DatePicker CalendarIdentifier="JulianCalendar" DatePicker DayFormat="{}{dayofweek.solo.full}" DatePicker TimePicker DayFormat="{}{day.integer} {dayofweek.abbreviated}" TimePicker ClockIdentifier="12HourClock" TimePicker ClockIdentifier="24HourClock" Flyouts Button <Button.Flyout> <Flyout> StackPanel TextBlock TextBlock Button StackPanel </Flyout> </Button.Flyout> Button Button <Button.Flyout> <MenuFlyout> MenuFlyoutItem MenuFlyoutItem MenuFlyoutSeparator ToggleMenuFlyoutItem ToggleMenuFlyoutItem </MenuFlyout> </Button.Flyout> Button AppBar Image TextBlock Image TextBlock Image Image.Source BitmapImage DecodePixelWidth="600" Image.Source Image DecodePixelWidth/Height 불러올 때 크기를 제공하면 메모리를 절약할 수 있다. 퍼포먼스도 좋아진다. 확대/축소된 결과도 더 품질이 좋다. Data Data template ListView ListView GridView GridView FlipView FlipView FlipView.ItemTemplate Data Template DataTemplate Grid Image Border TextBlock Border Grid DataTemplate FlipView.ItemTemplate FlipView Panning perf overview – UI virtualization Panning perf overview – UI virtualization 8 8.1 가상화 불가 가상화 가능 ItemsStackPanel과 ItemsWrapGrid 같은 크기에, 같은 템플릿을 사용하는 경우에만 가상화 작동. VariableSizedWrapGrid는 가상화 불가 가상화 불가 Large list performance GridViewItemPresenter + 퍼포먼스 개선 불필요한 엘리먼트의 생성을 줄이기. GridViewItemPresenter의 사용. = Placeholders로 가시적인 퍼포먼스 개선 <GridView ShowsScrollingPlaceholders="true"> Incrementally updating the data template GridView의 ContainerContentChanging이벤트 Windows 8 view states Full landscape Full portrait Snapped Filled Windows in Windows 8.1 Wider than tall window Taller than wide window Taller than w ide window Taller tha n wide wi ndow Windows 8.1 접근 세로로 긴 레이아웃을 지원할 것. 이제 좋은 툴킷을 맘대로 쓰고 개발자 마음대로 하세용 대형화면은 앱을 다섯 개까지! 보통은 두, 세 가지. App-specific visual states VisualStateManager.VisualStateGroups VisualStateGroup VisualState PrimaryLayout Storyboard Storyboard VisualState VisualState NarrowLayout Storyboard Storyboard VisualState VisualState TallLayout Storyboard Storyboard VisualState VisualState ExtraLargeLayout Storyboard Storyboard VisualState VisualStateGroup VisualStateManager.VisualStateGroups Visual States Visual states는 UI와 코드 를 분리해 주죠. 코드에서 수동으로 엘리먼 트 이동하고, 크기변경하고 하는 대신에 간단히 이 변 경사항들을 처리하는 Storyboard를 가진 visual state로 변경하는 게 깔끔 하죠. Setting visual states from code const string const string const string const string PrimaryLayout void object NarrowLayout TallLayout ExtraLargeLayout if this true const double const double else if this const double true else if this true else this Use constants Sizes and state names will almost certainly change during design iterations true 방향과 위치 ApplicationView.Orientation (Landscape 또는 Portrait을 반환) ApplicationView.AdjacentToLeftDisplayEdge ApplicationView.AdjacentToRightDisplayEdge ApplicationView.IsFullScreen Window 크기 Window.Current.Bounds : 초기 크기 페이지가 사라질 때는 핸들러를 끊어주는 센스! 전체화면일 때조차도 픽셀은 논리적 픽셀수. Handling the SizeChanged event protected override void Window.Current.SizeChanged += OnWindowSizeChanged; protected override void Window.Current.SizeChanged -= OnWindowSizeChanged; 핸들러 제거하는 것 잊지 마세요! 팁: 모든 닷넷 프로그램에서 메모리 누수가 발생하는 흔한 원인 중 하나가 제대로 이벤트 핸들러를 제 거하지 않는 것이다. 싱글턴 객체나 정적 클래스의 이벤트에 대한 핸들러는 꼭 제거합시다. Create Show a secondary view Default 기본값은 UseHalf와 같은 절반. var UseMore 가로 50% 이상을 차지 var await view.Dispatcher Setup window content UseHalf 절반 var var new typeof Show await ViewSizePreference ViewSizePreference UseLess 가로 50% 이하를 차지 UseMinimum Manifest에 정해 놓은 최소값인 320 또는 500 픽셀 UseNone 보여주지 않음 Speech Synthesis Speech synthesis Voice David(en-US, 남성) Zira(en-US, 여성) Hazel(en-UK, 여성) Heami(ko-KR, 여성) 외 13개국 음성 지원 Speech synthesis 단순 텍스트 음성 출력 synthesizeTextToStreamAsync PC의 위치 설정에 따라 음성 지원 Code var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer(); SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync("Welcome!"); media.SetSource(stream, stream.ContentType); media.Play(); Speech synthesis SSML(Speech Synthesis Markup Language) 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.SynthesizeSsmlToStreamAsync(Ssml); media.SetSource(stream, stream.ContentType); media.Play(); Contact & 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 returned Debug.WriteLine(contact.FirstName + " " + contact.LastName); } ContactPickerUI 로 UI를 커스텀 가능 Contact card Contact card workflow From: Ben Miller ContactManager View Profile ContactManager Code Contact contact = new Contact(); contact.FirstName = "주"; contact.LastName = "신영"; ContactEmail email = new ContactEmail(); email.Address = “bit1010@live.com"; contact.Emails.Add(email); Rect rect = Helper.GetElementRect(sender as FrameworkElement); ContactManager.ShowContactCard(contact, rect, Windows.UI.Popups.Placement. Default); Appointments Calrendar 앱을 통한 일정 관리 이메일 및 소셜 계정의 일정 연동됨 모든 일정의 추가/수정/ 삭제 AppointmentManager. ShowAddAppointmentAsync(…) 를 통해 바로 원 하는 일정 ContactCard를 호출 Appointments AppointmentManager. ShowAddAppointmentAsync(…) Appointments Code 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!"; Appointments Code 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."; Bluetooth in Windows 8.1 Windows 8.1 PC running your Windows Store app Windows.Devices.Bluetooth.Rfcomm Windows.Devices.Bluetooth.GenericAttributeProfile RFCOMM GATT • General device control • Custom and low-power devices • Robots • Smart watches • Sphero • Health monitors • Netduino • Fitness monitors • Gadgeteer • Home automation • More… • More… 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 중요! Industry-leading economics 70% for new apps 80% once your app makes $25,000 Developer registration Trials Matter 70x 10% 10x downloads conversion revenue Windows Phone Developer blog, March 2011 Simple time-based trials Initialize the license private void #if // debug license information #else // release license information #endif Use the right license provider WinRT 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. Yo u cannot submit an app which uses CurrentAppSimulator. Handle license events private void if if // 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 features private void if if // 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 i s a better approach than simply hiding the feature. Whenever you prompt, be sure to give the user the option to purchase right then.