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






4.97/5 (18投票s)
Windows Phone 7 模拟器不支持加速度计。此项目将帮助您在 Windows Phone 7 模拟器上测试启用加速度计的应用程序!
目录
引言
众所周知,Windows Phone 7 模拟器不支持加速度计。如果您正在创建一些基于加速度计的应用程序,您必须将其部署到您的 Windows Phone 设备上进行测试。当然,有些项目使用 Wii 或 Xbox 360 控制器等硬件来模拟移动设备运动。但是当您尝试使用它们时,您会发现它们有一个弱点——它们需要硬件!有一天,当我有了更多空闲时间时,我决定为这个问题找到一些解决方案。几个小时后,我找到了一个,就是它……我想向您介绍 WP7 加速度计模拟器项目。让我们仔细看看它是什么。
加速度计力矢量。来源:Windows Phone 开发者博客
它是如何工作的?(最终用户视角)
解决方案由三个相互连接的项目组成
MaciejGrabek.WP7Accelerometer
- 这是您项目中使用的核心库。它包含WP7AccelerometerProvider
类,该类提供Microsoft.Devices.Sensors
中真实加速度计提供的所有功能,即Start
和Stop
方法以及ReadingChanged
事件,该事件提供有关每个轴重力信息。没有IAccelerometer
接口可以实现,所以我只是简单地从加速度计类清单中复制了所有使用项的名称。MaciejGrabek.WP7AccelerometerEmulatorUI
- 此项目允许您通过简单地使用三个 X、Y 和 Z 旋转滚动条来模拟手机的位置。它将所有必需的数据发送到代理。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
将简单地读取代理上的内容,而不会更改界面。结果如下所示
如您所见,它使用起来非常简单直观。
本部分的最后,让我们比较一下 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 并在您的项目中使用它。我将在此处放置所有代码更新,所以如果您感兴趣,请关注项目站点。当然,还有一个演示可以确切地了解如何使用它,并且它已附加到提供的解决方案中。
未来版本中会出现什么?
- 有时,您会看到万向节锁效应——我目前正在尝试解决它
- 添加鼠标控制旋转
- 添加运动序列(您可以记录摇晃、滚动等运动,保存它,并在每次需要时快速运行)
- 为运动(摇晃等)添加额外的加速度
欢迎评论!