65.9K
CodeProject 正在变化。 阅读更多。
Home

WP7 模拟器上的加速度计支持

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (18投票s)

2010年12月14日

CPOL

6分钟阅读

viewsIcon

50893

downloadIcon

556

Windows Phone 7 模拟器不支持加速度计。此项目将帮助您在 Windows Phone 7 模拟器上测试启用加速度计的应用程序!

目录

引言

众所周知,Windows Phone 7 模拟器不支持加速度计。如果您正在创建一些基于加速度计的应用程序,您必须将其部署到您的 Windows Phone 设备上进行测试。当然,有些项目使用 Wii 或 Xbox 360 控制器等硬件来模拟移动设备运动。但是当您尝试使用它们时,您会发现它们有一个弱点——它们需要硬件!有一天,当我有了更多空闲时间时,我决定为这个问题找到一些解决方案。几个小时后,我找到了一个,就是它……我想向您介绍 WP7 加速度计模拟器项目。让我们仔细看看它是什么。

Accelerometer force vectors

加速度计力矢量。来源:Windows Phone 开发者博客

它是如何工作的?(最终用户视角)

解决方案由三个相互连接的项目组成

  1. MaciejGrabek.WP7Accelerometer - 这是您项目中使用的核心库。它包含 WP7AccelerometerProvider 类,该类提供 Microsoft.Devices.Sensors 中真实加速度计提供的所有功能,即 Start Stop 方法以及 ReadingChanged 事件,该事件提供有关每个轴重力信息。没有 IAccelerometer 接口可以实现,所以我只是简单地从加速度计类清单中复制了所有使用项的名称。
  2. MaciejGrabek.WP7AccelerometerEmulatorUI - 此项目允许您通过简单地使用三个 X、Y 和 Z 旋转滚动条来模拟手机的位置。它将所有必需的数据发送到代理。
  3. MaciejGrabek.WP7AccelerometerEmulatorProxy - 此代理用于从 UI 接收数据,并允许从 WP7AccelerometerProvider 读取数据。

如果您在模拟器上运行您的应用程序,那么 WP7AccelerometerProvider 会尝试从代理读取数据——如果检索此数据时出现问题(例如,代理不可用),它会简单地切换到随机数据模式。您可以通过简单地使用 Stop Start 方法来重试从代理接收数据。另一种方法是重新启动应用程序。当然,如果您在设备上运行应用程序,它将不会使用代理,而是会为您提供硬件内置的加速度计数据。

如何使用?

它非常简单——就像使用真正的加速度计一样。

当您创建 WP7 应用程序时,您需要做的第一件事是添加对 MaciejGrabek.WP7Accelerometer 库(或项目)的引用。然后像下面这样创建一个加速度计对象

using MaciejGrabek.WP7Accelerometer;

var acc = new WP7AccelerometerProvider();

现在只需添加 AccelerometerProviderReadingChanged 事件的处理,并使用 WP7AccelerometerReadingEventArgs 类提供的数据

acc.ReadingChanged += OnAccelerometerProviderReadingChanged;

private void OnAccelerometerProviderReadingChanged
	(object sender, WP7AccelerometerReadingEventArgs args)
{
    //do what you want with data
    ProcessAccelerometerData(args.X, args.Y, args.Z, args.Timestamp);
}

启动 WP7AccelerometerProvider 并准备获取数据。

try
{
    acc.Start();
}
catch (Exception exc)
{
    txtblk.Text = exc.Message;
}

这就是您需要在应用程序中做的所有事情。现在让我们看看控制面板。为此,您需要启动 MaciejGrabek.WP7AccelerometerEmulatorUI MaciejGrabek.WP7AccelerometerEmulatorProxy (它应该与 MaciejGrabek.WP7AccelerometerEmulatorUI 自动启动,但如果没有,请务必手动启动——否则,您将获得随机数据)。在模拟器上运行您的 WP7 应用程序,并在 MaciejGrabek.WP7AccelerometerEmulatorUI 上标记“将数据发送到模拟器”复选框,尽情享受吧!如果您取消选中“将数据发送到模拟器”,AccelerometerProvider 将简单地读取代理上的内容,而不会更改界面。结果如下所示

WP7 Accelerometer Emulator UI

WP7 Accelerometer Emulator UI

如您所见,它使用起来非常简单直观。

本部分的最后,让我们比较一下 Microsoft.Devices.Sensors.Accelerometer MaciejGrabek.WP7Accelerometer.WP7AccelerometerProvider

加速度计 WP7AccelerometerProvider
public SensorState State { get; }
public SensorState State { get; }
public event EventHandler ReadingChanged; 
//AccelerometerReadingEventArgs
public DateTimeOffset Timestamp { get; }
public double X { get; }
public double Y { get; }
public double Z { get; }
public event EventHandler ReadingChanged; 
//WP7AccelerometerReadingEventArgs
public DateTimeOffset Timestamp { get; }
public double X { get; }
public double Y { get; }
public double Z { get; }
public void Dispose();
public void Dispose();
public void Start();
public void Start();
public void Stop();
public void Stop();

如您所见,这两个类非常相似。没有接口可以实现(例如 IAccelerometer),所以唯一的方法是创建一个“类似”的类。这就是此模拟器“最终用户”最重要的一切。现在让我们看看它是如何真正工作的。:)

幕后

首先,我应该稍微解释一下这个项目中的数据流。如您在下面看到的,主要的通信是单向的。这意味着对 UI 项目来说,重要的是将数据发送到代理。另一方面,WP7AccelerometerProvider 负责从代理或设备(具有更高优先级)读取此数据。

Proxy

作为代理,我决定使用 WCF 服务,该服务允许使用简单的“HTTP GET”获取数据。服务契约及其实现如下所示。

[ServiceContract(Namespace = "http://maciejgrabek.com/WP7AccelerometerEmulatorProxy")]
public interface IAccelerometerEmulatorProxy
{
    [OperationContract]
    [WebGet]
    string GetData();

    [OperationContract]
    void SetData(float x, float y, float z);
}
[AspNetCompatibilityRequirements(RequirementsMode = 
	AspNetCompatibilityRequirementsMode.Allowed)]
public class AccelerometerEmulatorProxy : IAccelerometerEmulatorProxy
{
    public string GetData()
    {
        AccelerometerVector v = HttpRuntime.Cache
        	[AccelerometerVector.CacheKey] as AccelerometerVector;
        if (v != null)
        {
            return v.ToString();
        }
        else
        {
            return AccelerometerVector.Empty.ToString();
        }
    }
    
    public void SetData(float x, float y, float z)
    {
        AccelerometerVector v = new AccelerometerVector()
        {
            X = x,
            Y = y,
            Z = z
        };
        HttpRuntime.Cache.Remove(AccelerometerVector.CacheKey);
        HttpRuntime.Cache.Add(AccelerometerVector.CacheKey,
            v,
            null,
            DateTime.MaxValue,
            Cache.NoSlidingExpiration,
            CacheItemPriority.Default,
            delegate { });
    }
}

重要的是使用 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)][WebGet] 来启用与 WCF 服务的这种通信方式。
如您所见,为了存储来自 UI 的数据,我使用了内置缓存,因为它快速高效。整个逻辑并不是什么高科技,因为我遵循了“保持简单”的原则。:)

UI

MaciejGrabek.WP7AccelerometerEmulatorUI 上,有一些基于 XNA 类的计算,这些计算是获取重力力基矢量的正确值所必需的。3D 图形计算是一个完全不同的主题,所以我会把它留给 XNA 粉丝。所有操作数据都被发送到代理,在那里存储并准备传输到 Windows Phone 模拟器。所有这些计算和数据传输每秒执行 10 次。如果您想更改,有一个名为 InitializeAndRunTimer 的方法,您可以在其中更改计时器频率,但我认为 10Hz 相当不错。

private void InitializeAndRunTimer()
{
    _timer = new DispatcherTimer();
    _timer.Interval = TimeSpan.FromMilliseconds(100);
    _timer.Tick += delegate
    {
        PerformSingleStep();
    };
    _timer.Start();
}

核心

现在是时候看看负责从“正确”源读取数据的核心库了。当然,我指的是 MaciejGrabek.WP7Accelerometer WP7AccelerometerProvider 类。正如我之前提到的,它与真实的加速度计定义相似。最重要的是识别当前环境。您可以在这种情况下使用 Microsoft.Devices.Environment.DeviceType 属性和 <doce>Microsoft.Devices.DeviceType 枚举器。如果它等于 DeviceType.Device,那么我们正在使用加速度计,否则(DeviceType.Emulator)我们正在初始化 WebClient 以从代理获取数据。例如,我们可以使用 Stop() 方法实现

[SecuritySafeCritical]
public void Stop()
{
    if (Microsoft.Devices.Environment.DeviceType == DeviceType.Device)
    {
        _accelerometer.Stop();
    }
    else
    {
        this._timer.Stop();
    }
}

当您创建 WP7AccelerometerProvider 实例时,您可以指定两个参数。第一个是 dataUrl,默认值为 https://:9876/AccelerometerEmulatorProxy.svc/GetData,第二个是 refreshRate,设置为 100(这意味着 10Hz)。当然,将此值设置小于 33 是没有意义的,因为当前显示刷新率是每秒 33 次,所以即使我们读取数据,用户也无法看到。

当我测试这个应用程序时,我发现在模拟器或网络服务器端存在一些缓存问题。即使数据在服务器上已更改,也无法获取新版本。这就是使用一个小技巧的原因

if (!this._dataUrlError)
{
    if (!this._client.IsBusy)
        this._client.DownloadStringAsync(new Uri(String.Format("{0}?{1}", 
		this._dataUrl, this._rand.NextDouble())), null);
}

当我们向 URL 添加一些随机项时,我们可以确保我们的请求将返回未缓存的数据。如果从代理读取数据时出现问题,WP7AccelerometerProvider 将使用随机生成器获取一些数据。从代理重试读取的唯一方法是在 WP7AccelerometerProvider 实例上调用 Stop()Start() 方法,或者简单地重新启动应用程序。

在哪里可以找到它?

我已附上包含二进制文件的代码,但将来会对其进行修改和扩展。如果您想获取当前版本,只需下载 MaciejGrabek.WP7AccelerometerEmulator 并在您的项目中使用它。我将在此处放置所有代码更新,所以如果您感兴趣,请关注项目站点。当然,还有一个演示可以确切地了解如何使用它,并且它已附加到提供的解决方案中。

未来版本中会出现什么?

  1. 有时,您会看到万向节锁效应——我目前正在尝试解决它
  2. 添加鼠标控制旋转
  3. 添加运动序列(您可以记录摇晃、滚动等运动,保存它,并在每次需要时快速运行)
  4. 为运动(摇晃等)添加额外的加速度

欢迎评论!

有用链接

© . All rights reserved.