Miroslav Holec

Software & Cloud Architect

miroslavholec.cz / blog / windows-phone-quick-start-tipy

Windows Phone Quick Start tipy

Miroslav Holec

Publikován 28. února 2015 , aktualizace: 29. března 2016 |

Tento článek je starší 18 měsíců a je proto možné, že popisuje postupy nebo technologie, které v uplynulé době mohly doznat výraznějších změn. Názory a myšlenky v tomto článku již nemusí vyjadřovat současné stanovisko autora nebo autorů. Článek byl napsán 28. února 2015.

Přestože jsem už neměl v plánu vytvářet žádné Windows Phone aplikace, jednu přeci jen ještě výjimečně vydám v rámci studijního předmětu MTE na FIM UHK. I když jsem si platformu Windows Phone zvolil před iOS, jelikož už mám s WP mnoho zkušeností, opět jsem narazil na celou řadu překážek, které mi vzaly mnoho času. V tomto článku popíšu několik problémů, které jsem při vývoji celkem primitivní aplikace řešil.

Architektura

Tady jsem měl od začátku jasno. Vzhledem k použití webových služeb jsem použil architekturu, kterou jsem popsal před několika měsíci v tomto článku společně s MVVM Light Toolkitem. Tady jsem poprvé narazil a udělal zásadní chybu, když jsem si stáhnul nový MVVM Light Toolkit a snažil jsem se vyvíjet WP 8.1 Silverlight aplikaci. Nefungovalo bez jakékoliv příčiny tolik věcí, že jsem se po 5 hodinách dřiny vrátil k osvědčené verzi 4.2. Kdo má hodně času a nervů, nechť si zkusí MVVM verze 5+. Za mě doporučuji:

Předávání dat mezi stránkami

Pokud uvažujete jak předávat data mezi stránkami, já to řešil tak, že při odnavigování z jedné stránky jsem si data uložil do App.xaml.cs a při příchodu na jinou stránku jsem si tato data vyzvedl (nebo když jsem je potřeboval). Výhoda řešení je ta, že když se proklikáte na X-tou stránku a dáte back, pořád tam ta data jsou a lze je použít.

public partial class App : Application
{
    public static string Phrase { get; set; }
    public static string Phrase4List { get; set; }
	...

Šlo by to asi i tak, že bych si předával parametr přes Uri:

navigationService.NavigateTo(new Uri("/Views/DetailPage.xaml?Prop=Value", UriKind.Relative));

Barvy

Osobně s tím už problém nemám ale je třeba myslet na to, že WP prostředí umožňuje nastavovat barvu pozadí a popředí. Tato barva se propisuje do vytvářených aplikací. Pokud chcete aby byla vytvářená aplikace ve stále stejných barvách (což doporučuji), pak je potřeba všechny výskyty typu {StaticResource XXX} projít a nahradit buď vlastní barvou nebo vlastním stylem. Často totiž tyto Resources odkazují na systémové barvy.

Textbox a klávesnice

WP umožňuje při focusu na TextBox zobrazit různé typy klávesnic. Já jsem například pro svůj slovník chtěl klávesnici s našeptáváním. Slouží k tomu vlastnost InputScope

<TextBox InputScope="Formula"/>

a ukázky co tam lze napsat jsou tady:

Tapnutí na Enter

Dále jsem chtěl, aby po tapnutí na Enter button uživatel odpálil TextBox. Řešil jsem to v XAML CodeBehindu a volal jsem si následně RelayCommand ve ViewModelu:

private void PhraseTextBox_OnKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Enter)
    {
        NavigateTo();
    }
}

Metoda NavigateTo() vypadá takto:

private void NavigateTo()
{
    if (string.IsNullOrEmpty(PhraseTextBox.Text))
        return;

    MainViewModel viewModel = (MainViewModel)DataContext;

    if (CheckDetail.IsChecked.HasValue && CheckDetail.IsChecked.Value)
    {
        App.Phrase = PhraseTextBox.Text;
        viewModel.NavigateToDetail();
    }
    else
    {
        App.Phrase4List = PhraseTextBox.Text;
        viewModel.NavigateToList();
    }
}

Práce s RelayCommand je kompletně popsaná tady:

Ikonky pro appbar

Pokud hledáte jen ty základní systémové, jsou ve složce:

C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v8.0\Icons

Složka Dark obsahuje světlé ikony pro tmavé pozadí a složka Light přesně naopak. O tom, jak vytvořit AppBar se píše v tomto článku:

ListBox a scrollování

Po třetí v životě jsem použil ListBox a potřetí v životě mi trvalo přes 2 hodiny naučit ho rozumně scrollovat. Dokázal jsem to zase metodou pokus / omyl, nicméně už zhruba vím, kde je problém. Tedy na co dávat pozor při tvorbě scrollovatelného ListBoxu:

  1. pro vsazení do Gridu je nutné, aby řádek Gridu měl Height="Auto" nebo Height="*"
  2. na vybrané místo pak vsadím ScrollViewer (zadám řádek Gridu kam ho chci)
  3. do něj něco nasázím pomocí StackPanelu
  4. a tím něco může být i ListBox a vypnutým scrollbarem (řeší to ScrollViewer)

Takže ve finále:

<Grid x:Name="LayoutRoot" >
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

	<ScrollViewer Grid.Row="0">
		<StackPanel x:Name="SomePanel">
			ListBox  Margin="10" ItemsSource="{Binding Phrases}" 
                      ScrollViewer.VerticalScrollBarVisibility="Disabled"
                      Width="400"
                      HorizontalAlignment="Left">
			</ListBox>
		</StackPanel>
	</ScrollViewer>
</Grid>

Uvnitř ListBoxu je ještě template ale to obvykle není nic zajímavého.

Loading

Při* načítání dat z webu *jsem chtěl zobrazit nějaký progress, použil jsem ProgressBar:

<Grid.Resources>
    <converters:BoolToVisibilityConverter x:Key="BoolToVisibility"/>
</Grid.Resources>

<ProgressBar x:Name="ProgressBar" IsIndeterminate="True"
     Visibility="{Binding IsUpdating, Converter={StaticResource BoolToVisibility}}" Width="450" />

a jak je z kódu vidět, potřeboval jsem také* konverter Boolean hodnoty na Visibility value*:

public class BoolToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool boolean = false;
        if (value is bool) boolean = (bool)value;

        return boolean ? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is Visibility && (Visibility)value == Visibility.Visible;
    }
}

PropertyChanged

Nevím proč, ale i když výše zmíněná vlastnost IsUpdating šlapala jak švýcary pomocí MVVM Light Toolkitu tímto způsobem:

private bool isUpdating;
public bool IsUpdating
{
    get { return isUpdating; }
    set { Set(() => IsUpdating, ref isUpdating, value); }
}

jiné boolean vlastnosti mi takto nešly a vracela se mi výjimka. Vyřešil jsem to oldschool řešením:

private bool isMessageShown;
public bool IsMessageShown
{
    get
    {
        return isMessageShown;
    }

    set
    {
        if (isMessageShown == value)
        {
            return;
        }

        isMessageShown = value;
        RaisePropertyChanged("IsMessageShown");
    }
}

Barva pozadí Buttonu při OnClick

To jsem nevyřešil. Nechápu, proč Button nemá něco jako BackgroundActive. Zkrátka když mi někdo tapne na oranžové tlačítko a drží jej dole, je modré. Progooglil jsem se desítkami webů ale řešení jsem nenašel, byť vše nasvědčuje tomu, že je potřeba někde stranou si napsat vlastní styl a ten aplikovat.

Závěr

Na to, jak málo mobilní aplikace umí jsem se celkem dost nadřel. Na to, že je to asi třetí aplikace, ve které pracuji s webovými službami jsem čekal, že jí sestavím za třetinu času, než jsem jí nakonec věnoval. Přitom 85% času jsem strávil na front endu a řešením UX. Připojuji neoficiální promo z doby prvního návrhu :)

Náhled Windows Phone aplikace

Potřebujete pomoci?

Líbil se Vám článek? Máte dotaz nebo chcete v této oblasti s něčím pomoci? Neváhejte se na mě obrátit.

mirek@miroslavholec.cz

  • Řešení vývojářských problémů
  • Konzultace
  • Firemní školení a workshopy