В моем
предыдущем посте я обсуждал, как заставить код Javascript, размещенный в элементе управления WebBrowser, выполнять код .NET в хост-приложении и наоборот. Я также продемонстрировал, как получать и отображать информацию о состоянии устройства с помощью HTML5, размещенного в элементе управления WebBrowser.
Для этого примера я хотел бы продемонстрировать, как получить доступ к
датчику акселерометра из HTML5 и Javascript. Чтобы сделать вещи более интересными, данные чтения акселерометра будут постоянно обновляться каждые 100 миллисекунд, а код .NET будет неоднократно вызывать метод Javascript по мере обновления данных чтения акселерометра
А вот код …
Default.html (HTML5 + Javascript)
Приведенный ниже код будет использоваться в качестве локального HTML-файла, который необходимо скопировать в изолированное хранилище. Давайте поместим это в папку с именем HTML
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=480, height=800, user-scalable=no" /> <meta name="MobileOptimized" content="width" /> <meta name="HandheldFriendly" content="true" /> <title>HTML5 and Windows Phone 7</title> <style> body { color: White; background-color: Black; font-family: 'Segoe WP Semibold'; text-align: left; } h3 { font-size: 20pt; } input { color: #ffffff; background-color: #000000; border: 2px solid white; vertical-align: baseline; font-size: 17pt; min-width: 40px; min-height: 40px; margin: 5; } </style> </head> <body onload="onLoad()"> <div> <h3> X:</h3> <input id="x" type="text" value="0" /> <h3> Y:</h3> <input id="y" type="text" value="0" /> <h3> Z:</h3> <input id="z" type="text" value="0" /> </div> <script type="text/javascript"> function onLoad() { window.external.notify("startAccelerometer"); } function accelerometerCallback(x, y, z) { document.getElementById("x").value = x; document.getElementById("y").value = y; document.getElementById("z").value = z; } </script> </body> </html> MainPage.xaml The code below is the main page of the Silverlight application that will host the HTML content <phone:PhoneApplicationPage x:Class="PhoneApp.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="480" d:DesignHeight="768" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" shell:SystemTray.IsVisible="True" Loaded="PhoneApplicationPage_Loaded"> <Grid x:Name="LayoutRoot" Background="Transparent"> <phone:WebBrowser Name="browser" IsScriptEnabled="True" Source="HTML/Default.html" ScriptNotify="browser_ScriptNotify" /> </Grid> </phone:PhoneApplicationPage>
MainPage.xaml.cs
А вот код файла xaml
public partial class MainPage : PhoneApplicationPage { private Microsoft.Devices.Sensors.Accelerometer accelerometer; public MainPage() { InitializeComponent(); } private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) { using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { if (!store.DirectoryExists("HTML")) store.CreateDirectory("HTML"); CopyToIsolatedStorage("HTML\\Default.html", store); } } private static void CopyToIsolatedStorage(string file, IsolatedStorageFile store, bool overwrite = true) { if (store.FileExists(file) && !overwrite) return; using (Stream resourceStream = Application.GetResourceStream(new Uri(file, UriKind.Relative)).Stream) using (IsolatedStorageFileStream fileStream = store.OpenFile(file, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)) { int bytesRead; var buffer = new byte[resourceStream.Length]; while ((bytesRead = resourceStream.Read(buffer, 0, buffer.Length)) > 0) fileStream.Write(buffer, 0, bytesRead); } } private void browser_ScriptNotify(object sender, NotifyEventArgs e) { if (e.Value == "startAccelerometer") { if (accelerometer == null) { accelerometer = new Microsoft.Devices.Sensors.Accelerometer { TimeBetweenUpdates = TimeSpan.FromMilliseconds(100) }; accelerometer.CurrentValueChanged += (o, args) => Dispatcher.BeginInvoke(() => { var x = args.SensorReading.Acceleration.X.ToString("0.000"); var y = args.SensorReading.Acceleration.Y.ToString("0.000"); var z = args.SensorReading.Acceleration.Z.ToString("0.000"); browser.InvokeScript("eval", string.Format("accelerometerCallback({0},{1},{2})", x, y, z)); }); accelerometer.Start(); } } } }
В приведенном выше коде происходит то, что выполняется метод Javascript, который уведомляет хост-приложение о необходимости запустить акселерометр после загрузки HTML. Затем мы добавляем обработчик события в событие Accelerometers
CurrentValueChanged, который вызывает метод Javascript accelerometerCallback и передает в качестве аргументов данные чтения акселерометра. Обратите внимание, что я использую
eval в качестве метода Javascript для вызова и передачи вызова метода в качестве аргумента, это связано с тем, что данные чтения акселерометра извлекаются в рабочем потоке и по какой-то причине возникает неизвестная системная ошибка даже при выполнении кода в потоке пользовательского интерфейса. через метод Page Dispatcher.BeginInvoke (). Я понял, что с помощью
Evalбыл единственный способ выполнить код Javascript из рабочего потока .NET.
Я надеюсь, что вы нашли это полезным. Вы можете получить полный исходный код для примера здесь: