Упрощаем разработку под WP7 с библиотекой WPExtensions

в 23:25, , рубрики: windows phone, WP7, wp7 development, разработка под windows phone, метки: ,

На днях удалось выпустить релиз библиотеки WPExtensions. Старое рабочее название библиотеки было не очень вразумительное ShWP и в основном в библиотеке собраны расширения и обертки над стандартными элементами управления.

Добавил поддержку пакетного менеджера Nuget. Теперь установить библиотеку можно командой:
Install-Package WPExtensions

Также можно скачать библиотеку, исходные коды и демонстрацию с codeplex
Как обычно для использования библиотеки необходимо добавить соответствующее объявление пространства имен:

xmlns:WPExtensions=«clr-namespace:WPExtensions;assembly=WPExtensions»

Далее рассмотрим основные компоненты библиотеки.

AdvancedApplivationBar

Об этой компоненте была уже публикация на хабре
Коротко повторю что было и опишу что нового в этой версии.

AdvancedApplicationBar представляет собой обертку над стандартным ApplicationBar и добавляет несколько новых возможностей. Так как он реализован как элемент управления, его необходимо поместить внутрь основного контейнера (обычно это grid).

<phone:PhoneApplicationPage  ...>

    <Grid x:Name="LayoutRoot" Background="Transparent">

          ...

       <WPExtensions:AdvancedApplicationBar IsVisible="True" IsMenuEnabled="True">

          <WPExtensions:AdvancedApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
          <WPExtensions:AdvancedApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
          <WPExtensions:AdvancedApplicationBarMenuItem Text="MenuItem 1"/>
          <WPExtensions:AdvancedApplicationBarMenuItem Text="MenuItem 2"/>
      </WPExtensions:AdvancedApplicationBar>
  </Grid>
</phone:PhoneApplicationPage>

Обратите внимание что MenuItem-ы не надо выделять в отдельный тег.

Поддержка Panorama/Pivot.

Часто требуется для разных Panorama/Pivot итемах отображать разный набор кнопок/меню в ApplicationBar. В msdn предлагается решение с созданием отдельных ApplicationBar в ресусре и смены ApplicationBar при смене актвиного Item-а

Здесь мы можем перенести соответствующую кнопку внутрь PanoramaItem/PivotItem для того что бы обеспечить отображание кнопки/меню только в этом item-е (Button 1/Menu item 1).

При этом остальные кнопки меню по умолчанию будут отображаться ПОСЛЕ всех элементов. Если необходимо что бы кнопка/меню отображалась ДО элементов в панораме, достаточно перенести меню/кнопку ДО панорамы (Button 2):

<phone:PhoneApplicationPage 
      ....
      xmlns:WPExtensions="clr-namespace:WPExtensions;assembly=WPExtensions"
       ...>
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <!-- Эта кнопка будет отображена ДО всех остальных кнопок -->
        <WPExtensions:AdvancedApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
        <Grid x:Name="ContentPanel" Margin="12,0,12,0">
            <controls:Panorama>
                <controls:PanoramaItem Header="Item1">
                    <Grid>
                         ...
                         <!-- Эти кнопка и меню будут отображаться только при активном PanoramaItem -->
                         <WPExtensions:AdvancedApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
                        <WPExtensions:AdvancedApplicationBarMenuItem Text="MenuItem 1"/>
                    </Grid>
                </controls:PanoramaItem>
                <controls:PanoramaItem Header="Item2">
                      ...
                </controls:PanoramaItem>
            </controls:Panorama>            
        </Grid>

       <WPExtensions:AdvancedApplicationBar IsVisible="True" IsMenuEnabled="True">
       <!-- Эта кнопка будет отображаться ПОСЛЕ всех кнопок -->
       <WPExtensions:AdvancedApplicationBarMenuItem Text="MenuItem 2"/>
     </WPExtensions:AdvancedApplicationBar>
    </Grid>
</phone:PhoneApplicationPage>

Поддержка Binding

Как и было описано в прошлый раз, свойства AdvancedApplicationBar, в отличае от оригинала, поддерживают привязку данных.

   <WPExtensions:AdvancedApplicationBarIconButton 
                Text="{Binding AppBarIconButtonText}"
                IconUri="{Binding AppBarIconButtonText}"
                Visibility="{Binding Visibility}"
                Command="{Binding DeleteCommand}"
                CommandParameter="42" 
                /> 

Поддержка обновления Binding-а для элемента в фокусе.

Это одно из нововведений в новой версии, особенно полезных при активном использовании DataBinding-а.
Остановимся на этом пункте поподробнее.

Допустим у нас на форме есть TextBox с Binding-ом.

<TextBox Text="{Binding Text,Mode=TwoWay}" />

И есть соответствующая кнопка Button на форме и стандартная кнопка <shell:ApplicationBarIconButton которые в обработчике отображают текст привязанного свойства в MessageBox:

MessageBox.Show(Text);

Если мы редактируем текст и все еще находимся в режиме редактирования (в фокусе в TextBox) при нажатии на ApplicationBarIconButton и при нажатии на Button увидим разный результат. При тапе на ApplicationBarIconButton увидим что отображается старый текст. Это связано с тем что текст обновляется только при потере фокуса а стандартные AppBar кнопки не приводят к потере фокуса.

В AdvancedApplicationBar добавлена потеря фокуса при нажатии на кнопки(фокус передается странице) и мы можем увидеть что кнопки теперь отработают как ожидаются и мы увидим новый текст.
В случае необходимости можно вернуть поведение по умолчанию атрибутом DisableLostFocus=«True»

<WPExtensions:AdvancedApplicationBarIconButton 
             ...
            DisableLostFocus="True"
            />

Mode=«Default» IsVisible=«True»
Еще пара атрибутов ApplicationBar которые отличаются от значений по умолчанию.
По умолчанию значение атрибутов Mode, IsVisible в ApplicationBar установлены в Mode=«Default» IsVisible=«True»

В AdvancedApplicationBar значение этих атрибутов по умолчанию не фиксировано и зависит от следующих условий:

Если у нас на на странице и/или PanoramaItem/PivotItem есть кнопки то значения атрибутов равны Mode=«Default» IsVisible=«True»
image

Если у нас только элементы меню то значения атрибутов равны: Mode=«Minimized» IsVisible=«True»

image

Если у нет ни одной кнопки/элментов меню значение атрибута IsVisible=«False»

image

На этом завершается обзор AdvancedApplicationBar. Далее будут идти описания TextBox Extensions

TextBox Extensions

Довольно часто нам не хватает базовой функциональности TextBox. Я планирую в дальнейшем расширять список расширений, но пока внес в библиотеку два расширания для двух наиболее часто встречающихся проблем.

Эти расширения можно применить как к отдельному элементу так и к элементам в контейнере (Page, StackPanel, Grid). Например, если мы хотим установить поведение для всех текстовых полей на странице то достаточно добавить атрибут к Page:

<phone:PhoneApplicationPage 
   ...
   WPExtensions:Extensions.UpdateBindingOnChange="True"
   WPExtensions:Extensions.SelectAllOnFocus="True">

UpdateBindingOnChange

Допустим у нас есть текстовое поле привязанное к определенной модели:

<TextBox Text="{Binding Text,Mode=TwoWay}" />

Довольно часто надо обновлять модель во время изменения текста, обычно для этого в событии TextChanged производится обновление Binding-а.

Теперь можно вместо этого воспользоватся атрибутом: Extensions.UpdateBindingOnChange=«True»

<TextBox Text="{Binding Text,Mode=TwoWay}"  WPExtensions:Extensions.UpdateBindingOnChange="True" />

SelectAllOnFocus

Часто можно увидеть приложения, где при редактировании значений приходится предварительно стирать старое значение, например редактирование цены/количества и т.д… Например заменить 10 на 20. Можно значительно упростить утомительную процедуру для пользователя, если при фокусе в текстовом поле выделить полностью текстовое поле. Пользователь сможет или оставить текущее значение еще раз тапнув или заменить значения просто начав набор нужного значения.

image

Для этого обычно перехватывается GotFocus где вызывается метод txtBox.SelectAll().
Теперь мы можем установить такое поведение с помощью расширения WPExtensions:Extensions.SelectAllOnFocus=«True»

<TextBox WPExtensions:Extensions.SelectAllOnFocus="True" />

Поддержка микрофона MicrophoneWrapper

В последней версии 1.3 было добавлена обертка над микрофоном в пространстве имен Audio (WPExtensions.Audio)

Воспользоваться оберткой тоже достаточно просто:

var microphoneWrapper=new MicrophoneWrapper();

Запись звука:

microphoneWrapper.Record();

Остановка:

microphoneWrapper.Stop();

Проигрывание звука:

microphoneWrapper.Play();

Что бы получить записанный звук есть два метода:

получение «сырой» или оригинальной записи:

microphoneWrapper.GetContent();

получение записи в WAV формате:

microphoneWrapper.GetWavContent();

Надеюсь библиотека кому нибудь пригодится, и само собой буду рад любым отзывам. :)

Офтоп:
Коллеги, 31 матра состоится конференция для стартапов Microsoft BizSpark Camp по Windows Phone.
Мне любезно было предложено поучаствовать в этом мероприятии в качестве эксперта-консультанта.
Я постараюсь оправдать столь лестное звание и буду рад пообщаться и поделиться опытом с коллегами (или получить новый опыт:). Всех заинтересовавшихся мероприятием приглашаю присоединиться, буду рад обсудить с вами разработку под WP7 и не только и постараюсь помочь в решении Ваших задач.

Автор: Atreides07


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js