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):
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:
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: