Опубликован: 14.08.2012 | Уровень: специалист | Доступ: платный
Самостоятельная работа 27:

Акселерометр, микрофон, панель приложения

Аннотация: В этой работе будет рассмотрена работа с акселерометром, использование его для управления экранными объектами, кроме того, мы поработаем с микрофоном устройства для записи и последующего воспроизведения звука.

Цель работы: Научиться работать с акселерометром, микрофоном, панелью приложения в Silverlight-приложениях

34.1. Акселерометр

В этом примере мы хотели бы использовать данные, получаемые с акселерометра, для управления экранным объектом. Объект должен перемещаться в том направлении, в котором наклонён телефон, если телефон лежит экраном вверх на горизонтальной поверхности, объект должен быть неподвижным.

Создадим новый проект, P27_1, он будет состоять из одной страницы, оформление которой, в целом, аналогично тому, которое было представлено в проекте P26_1. На рис. 34.1 вы можете видеть экран приложения, в листинге 34.1 – код страницы.

Экран проекта P27_1

Рис. 34.1. Экран проекта P27_1
<phone:PhoneApplicationPage 
    x:Class="P27_1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="480"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Landscape" Orientation="LandscapeLeft"
    shell:SystemTray.IsVisible="False">

    <!--LayoutRoot представляет корневую сетку, где размещается все содержимое страницы-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>


        <!--ContentPanel — поместите здесь дополнительное содержимое-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="0,0,0,0">
            <Image Height="480" HorizontalAlignment="Left" Name="image1" Stretch="Fill" 
            VerticalAlignment="Top" Width="800" Source="/P27_1;component/Res/Background.jpg" />
            <Canvas>
                <Ellipse Height="100" 
                     Name="ellipse1" 
                     Stroke="Black" 
                     StrokeThickness="1" 
                     Width="100" 
                     Fill="#FF00CB00" 
                     Canvas.Top="190"
                     Canvas.Left="350"/>
            </Canvas>
        </Grid>
    </Grid>

</phone:PhoneApplicationPage> 
Листинг 34.1. Код страницы MainPage

Обратите внимание на то, что здесь мы размещаем элемент Ellipse внутри элемента Canvas (холст). В результате, у элемента Ellipse появляются присоединенные свойства (Canvas.Top и Canvas.Left). Они задают позиционирование объекта внутри Canvas, модифицируя их, мы сможем перемещать объект по экрану, ориентируясь на них сможем предотвратить пересечение объектом границ экрана.

Для успешной работы с приведенным примером нам понадобится подключить библиотеки Microsoft.Devices.Sensors и Microsoft.Xna.Framework. Первая нужна для работы с акселерометром. Вторая – для обработки значений типа Vector3, с которыми мы столкнёмся при получении данных от акселерометра.

В листинге 34.2 приведен программный код, обеспечивающий работу нашего примера.

using System;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;
namespace P27_1
{
    public partial class MainPage : PhoneApplicationPage
    {
        //Для акселерометра
        Accelerometer accelerometer;
        // Конструктор
        public MainPage()
        {
            InitializeComponent();
            //Новый экземпляр объекта Accelerometer
            accelerometer = new Accelerometer();
            //Время между обновлениями показаний акселерометра
            accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
            //Подключаем обработчик события, возникающего при получении новых данных
            accelerometer.CurrentValueChanged += new EventHandler<SensorReadingEventArgs
            <AccelerometerReading>>(accelerometer_CurrentValueChanged);
           //Запуск акселерометра
            accelerometer.Start();
        }
        //Обработчик
        void accelerometer_CurrentValueChanged(object sender, 
        SensorReadingEventArgs<AccelerometerReading> e)
        {
            //Вызов метода из потока пользовательского интерфейса
            Dispatcher.BeginInvoke(() => MoveObject(e.SensorReading));
        }
        //Метод для перемещения объекта
        void MoveObject(AccelerometerReading accData)
        {
            //Переместим объект по оси Y
            Canvas.SetLeft(ellipse1, Canvas.GetLeft(ellipse1) - accData.Acceleration.Y*5);
            //Переместим объект по оси X
            Canvas.SetTop(ellipse1, Canvas.GetTop(ellipse1) - accData.Acceleration.X*5);
            //Проверим на столкновение с границами экрана
            CheckBounds();
        }
        void CheckBounds()
        {
            //При выходе объекта за границы экрана
            //Установим позицию так, чтобы он касался
            //границ экрана
            if (Canvas.GetLeft(ellipse1) < 0 )          
            {
                Canvas.SetLeft(ellipse1, 0);
            }
            if (Canvas.GetLeft(ellipse1) > 700)
            {
                Canvas.SetLeft(ellipse1, 700);
            }
            if (Canvas.GetTop(ellipse1) < 0)
            {
                Canvas.SetTop(ellipse1, 0);
            }
            if (Canvas.GetTop(ellipse1) > 380)
            {
                Canvas.SetTop(ellipse1, 380);
            }
        }

    }
}
Листинг 34.2. Программный код страницы

В конструкторе мы инициализируем объект типа Accelerometer, задаём интервал обновления данных, назначаем обработчик события, возникающего при получении новых данных и запускаем акселерометр.

Обратите внимание на обработчик accelerometer_CurrentValueChanged. Этот обработчик выполняется в собственном потоке, а пользовательский интерфейс – в собственном, так называемом UI-потоке. В итоге, для того, чтобы обратиться к элементу пользовательского интерфейса, нам понадобится воспользоваться диспетчером (Dispatcher), с помощью которого можно направить задание из одного потока в другой. В данном случае мы используем лямбда-выражение.

Перемещая объект, мы модифицируем его свойства Canvas.Top и Canvas.Left. Для работы с ними существуют соответствующие методы класса Canvas, например Canvas.GetTop(object) получает значение Top для объекта, SetTop – устанавливает.

После перемещения мы проверяем, не пересек ли объект границы экрана (мы работаем в ландшафтной ориентации), если пересек – возвращаем его к границам экрана.

Гулич Анна
Гулич Анна
Невозможно пройти тесты, в окне с вопросами пусто
Сашечка Огнев
Сашечка Огнев
Россия, Красноярский край
Андрей Корягин
Андрей Корягин
Россия, Пенза, Вазерская средняя школа, 2001