poniedziałek, 16 czerwca 2014

Wieczór z Madonną cz. 1 (Windows Phone 8.1 XAML)

Kilka uwag, jakie nasunęły mi się w związku z migracją do universal app.

1. Dalej w API WP 8.1 nie działa odczytywanie ikon z plików (np. GetThumbnailAsync ze StorageFile), i to mimo … zapewnień dokumentacji MSDN.  O niestandardowych file queries, czy wirtualizowanych wektorach dla plików znanych z Windows nie ma nawet co wspominać (to akurat zgadza się z dokumentacją)

2. AutoSuggestBox nie jest dokładnym odpowiednikiem SearchBox z Windows 8.1.  Funkcjonalnie jest to jakby TextBox, który możemy zasilić ręcznie podpowiedziami. Przycisk szukaj nie wchodzi w jego skład. Poniżej fragment view modelu, pod który podpiąłem tę kontrolkę:

        private IEnumerable<string> _suggestions;
        public IEnumerable<string> Suggestions
        {
            get
            {
                return _suggestions;
            }
            set
            {
                SetProperty<IEnumerable<string>>(ref _suggestions, value);
            }
        }

        public void GenerateSuggestions(string query)
        {
            ClearSuggestions();         

            var localSettings = ApplicationData.Current.LocalSettings;
            if (localSettings.Values.ContainsKey("VideoSuggestions"))
            {
                var data = (string)localSettings.Values["VideoSuggestions"];
                var list = JsonUtils.Deserialize<List<string>>(data);

                if (!string.IsNullOrEmpty(query))                   
                    Suggestions = list.Where(item => item.StartsWith(query)).ToList();
            }
        }

        public void ClearSuggestions()
        {
            Suggestions = null;
        }

        public async Task SearchFiles(string queryText)
        {
            var filter = !string.IsNullOrEmpty(queryText);

            if (filter)
            {
                var localSettings = ApplicationData.Current.LocalSettings;

                var list = new List<string>();
                if (localSettings.Values.ContainsKey("VideoSuggestions"))
                {
                    var data = (string)localSettings.Values["VideoSuggestions"];
                    list = JsonUtils.Deserialize<List<string>>(data);                   
                    if (!list.Contains(queryText))
                        list.Add(queryText);
                }
                else
                {
                    list.Add(queryText);
                }
                var json = JsonUtils.Serialize(list);
                localSettings.Values["VideoSuggestions"] = json;
            }
            …

       }

Jak widać zasymulowałem zachowanie Searchbox-a polegające na zapamiętywaniu wpisywanych fraz.

XAML prezentuje się następująco:

<AutoSuggestBox x:Name="searchBox"  TextChanged="searchBox_TextChanged" SuggestionChosen="searchBox_SuggestionChosen"
                        ItemsSource="{Binding Suggestions}" PlaceholderText="Search Videos"/>
<AppBarButton Grid.Column="1" Margin="0,-12,0,0" Icon="Find" Click="OnSearchButtonClicked"/>

Połączyłem go z view modelem posiłkując się wstawkami w code-behind strony (pozwoliłem sobie tym razem nie stosować bardziej ortodoksyjnego podejścia MVVM w stylu Caliburn czy Prism):

autosuggestbox

3. Korzystanie z Cortany jest bardzo przyjemne.  Oto fragment mojego pliku z komendami głosowymi:

<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.1">
 
  <CommandSet xml:lang="en-US" Name="myEnglishCommands">
    <CommandPrefix>My Movies</CommandPrefix>
    <Example>Play last</Example>

     …

    <Command Name="findVideo">
      <Example>Find Eminem</Example>
      <ListenFor>Find {text}</ListenFor>
      <Feedback>Searching for {text}</Feedback>
      <Navigate Target="Views/AddNewVideosView.xaml"/>
    </Command>   

    <PhraseTopic Label="text" Scenario="Search">
      <Subject>Music</Subject>
    </PhraseTopic>

  </CommandSet>

Wypowiadam słowa jak niżej:

cortana1

Słowa “Madonna” nie ma w definicji komend. To Cortana sama rozpoznaje (w tym przykładzie optymalnie podpowiedziałem jej by spodziewała się słowa używanego w wyszukiwarkach i związanego z muzyką, ale można też określić, by rozpoznawała dowolnie wypowiedziany tekst). Obsługując aktywację aplikacji za pomocą komendy głosowej przekierowuję na odpowiednią stronę:

        protected override void OnActivated(IActivatedEventArgs args)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            if (rootFrame == null)
            {
                rootFrame = new Frame();
                SuspensionManager.RegisterFrame(rootFrame, "AppFrame");
                rootFrame.CacheSize = 1;
                Window.Current.Content = rootFrame;

                if (args.Kind != ActivationKind.VoiceCommand)
                    rootFrame.Navigate(typeof(HomeView));
            }

            Window.Current.Activate();

            base.OnActivated(args);
           
            if (args.Kind == ActivationKind.VoiceCommand)
            {
                var commandArgs = args as VoiceCommandActivatedEventArgs;
                var speechRecognitionResult = commandArgs.Result;                            
                var navigationTarget = speechRecognitionResult.SemanticInterpretation.Properties["NavigationTarget"][0];

                if (!String.IsNullOrEmpty(navigationTarget))
                {
                    Type pageType = Type.GetType(typeof(HomeView).Namespace + "." + navigationTarget.Replace("Views/","").Replace(".xaml",""));
                   
                    if (pageType != null)
                    {
                        rootFrame.Navigate(pageType, speechRecognitionResult);
                    }
                }               
            }
        }

W kodzie strony obsługuję przychodzące polecenie:

madonna

Brak komentarzy: