- 示例工程
【免费下载链接】Windows-universal-samples
API samples for the Universal Windows Platform.
本指南以 Windows-universal-samples 仓库中的 SimpleOrientationSensor 示例 为核心,系统讲解 UWP 应用如何通过Windows.Devices.Sensors.SimpleOrientationSensor类获取设备简易方向(未旋转、面朝上、逆时针旋转 90 度等)。文中不仅完整还原官方示例的构建与运行步骤,还结合仓库内 C# 与 C++/CX 双语言源码,深入剖析数据事件监听与轮询读取两种场景的完整实现、UI 线程调度与可见性处理细节,帮助读者直接套用并二次开发自己的方向感应功能。
示例概览与核心 API
SimpleOrientationSensor(简易方向传感器)与需要三轴数据的 OrientationSensor 不同,它返回的是离散的六个方向状态,非常适合实现"旋转屏幕提示""设备翻转检测"这类轻量级需求。本示例位于仓库的 Samples/SimpleOrientationSensor 目录,官方描述为:
Shows how to use the Windows.Devices.Sensors.SimpleOrientationSensor class for a simple device orientation sensor.
示例允许用户实时查看设备简易方向值,并提供两种可选场景:
- Orientation sensor data events(数据事件):注册
OrientationChanged事件监听,传感器方向变化时实时推送更新; - Polling orientation sensor readings(轮询读取):手动调用
GetCurrentOrientation()获取当前方向快照。
核心 API 位于Windows.Devices.Sensors命名空间,关键成员如下:
| 成员 | 类型 | 说明 |
|---|---|---|
SimpleOrientationSensor.GetDefault() | 静态方法 | 获取系统默认方向传感器实例;设备不支持时返回null |
OrientationChanged | 事件 | 方向变化时触发,事件参数为SimpleOrientationSensorOrientationChangedEventArgs,其Orientation属性携带新方向 |
GetCurrentOrientation() | 方法 | 同步读取当前方向(轮询场景使用) |
方向枚举SimpleOrientation的取值,可从源码中的DisplayOrientation辅助方法(Scenario1_DataEvents.xaml.cs)完整看到:
NotRotated——未旋转;Rotated90DegreesCounterclockwise——逆时针旋转 90 度;Rotated180DegreesCounterclockwise——逆时针旋转 180 度;Rotated270DegreesCounterclockwise——逆时针旋转 270 度;Faceup——面朝上;Facedown——面朝下;- 其他情况统一显示为
Unknown orientation。
工程结构与双语言实现
示例按语言分为两个独立子工程,均包含相同的两个场景页面:
Samples/SimpleOrientationSensor/ ├── cpp/ # C++/CX(Windows Runtime C++)版本 │ ├── Scenario1_DataEvents.xaml / .cpp / .h │ ├── Scenario2_Polling.xaml / .cpp / .h │ ├── SampleConfiguration.h / .cpp │ ├── SimpleOrientationSensor.sln / .vcxproj │ └── Package.appxmanifest └── cs/ # C# 版本 ├── Scenario1_DataEvents.xaml / .xaml.cs ├── Scenario2_Polling.xaml / .xaml.cs ├── SampleConfiguration.cs ├── SimpleOrientationSensor.sln / .csproj └── Package.appxmanifest两个语言版本的场景入口由 SampleConfiguration.cs(C++ 侧对应SampleConfiguration.h/.cpp)统一注册:
public const string FEATURE_NAME = "Simple Orientation Sensor"; List<Scenario> scenarios = new List<Scenario> { new Scenario() { Title = "Data Events", ClassType = typeof(SimpleOrientationCS.Scenario1_DataEvents) }, new Scenario() { Title = "Polling", ClassType = typeof(SimpleOrientationCS.Scenario2_Polling) } };清单文件 Package.appxmanifest 声明了Windows.Universal目标设备家族,MinVersion为10.0.10240.0、MaxVersionTested为10.0.22621.0,即面向 Windows 10 及以上版本的通用应用。
场景一:数据事件(Data Events)
数据事件场景的界面(Scenario1_DataEvents.xaml)包含Enable / Disable两个按钮与一个方向输出TextBlock,其说明文字为:"Registers an event listener for orientation changes and displays the new orientation as it is reported."
获取传感器实例
页面构造函数中调用静态工厂方法获取默认传感器,并处理设备不支持的情况(Scenario1_DataEvents.xaml.cs):
private SimpleOrientationSensor _sensor; public Scenario1_DataEvents() { this.InitializeComponent(); _sensor = SimpleOrientationSensor.GetDefault(); if (_sensor == null) { rootPage.NotifyUser("No simple orientation sensor found", NotifyType.ErrorMessage); } }这是所有 UWP 传感器用法的标准模式:先判空,再使用。在没有方向传感器的设备(如部分模拟器或台式机)上运行会得到明确错误提示。
注册与注销事件
点击 Enable 后注册事件并立即显示一次当前方向(Scenario1_DataEvents.xaml.cs):
private void ScenarioEnable(object sender, RoutedEventArgs e) { if (_sensor != null) { Window.Current.VisibilityChanged += new WindowVisibilityChangedEventHandler(VisibilityChanged); _sensor.OrientationChanged += new TypedEventHandler<SimpleOrientationSensor, SimpleOrientationSensorOrientationChangedEventArgs>(OrientationChanged); ScenarioEnableButton.IsEnabled = false; ScenarioDisableButton.IsEnabled = true; // Display the current orientation once while waiting for the next orientation change DisplayOrientation(ScenarioOutput_Orientation, _sensor.GetCurrentOrientation()); } else { rootPage.NotifyUser("No simple orientation sensor found", NotifyType.ErrorMessage); } }两个实现细节值得注意:
- 注册事件的同时也调用
GetCurrentOrientation():事件只在方向变化时触发,因此先主动读取一次当前值,避免按钮点击后界面一直停留在 "No data"; - 同时注册
Window.Current.VisibilityChanged:当应用窗口不可见时注销传感器事件,可见时重新注册(见 VisibilityChanged 处理)。源码注释明确指出:不可见时注销事件可避免传感器数据引发非预期操作,恢复可见后无需手动恢复reportInterval,系统在应用恢复时会自动恢复。
Disable 按钮反向操作,同时注销两类事件并切换按钮可用状态(Scenario1_DataEvents.xaml.cs)。
事件回调与 UI 线程调度
OrientationChanged回调运行在后台线程,必须通过Dispatcher编组到 UI 线程后才能更新TextBlock(Scenario1_DataEvents.xaml.cs):
async private void OrientationChanged(object sender, SimpleOrientationSensorOrientationChangedEventArgs e) { await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { DisplayOrientation(ScenarioOutput_Orientation, e.Orientation); }); }C++/CX 版本实现了完全相同的逻辑(Scenario1_DataEvents.xaml.cpp),同样通过Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ...)将e->Orientation送回 UI 线程,并在头文件 Scenario1_DataEvents.xaml.h 中用EventRegistrationToken(visibilityToken/orientationToken)保存事件句柄以便注销。C++ 版在OnNavigatedFrom中还会判断NavigationMode::Forward && e->Uri == nullptr以避免应用挂起(Phone 场景)时误清理事件。
页面生命周期清理
离开页面时,若传感器事件仍处于启用状态,则注销所有事件(C# 的OnNavigatingFrom,见 Scenario1_DataEvents.xaml.cs):
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) { if (ScenarioDisableButton.IsEnabled) { Window.Current.VisibilityChanged -= new WindowVisibilityChangedEventHandler(VisibilityChanged); _sensor.OrientationChanged -= new TypedEventHandler<SimpleOrientationSensor, SimpleOrientationSensorOrientationChangedEventArgs>(OrientationChanged); } base.OnNavigatingFrom(e); }这一模式保证了导航离开后不再有悬挂的传感器回调,避免内存泄漏与无效 UI 更新。
场景二:轮询读取(Polling)
轮询场景的界面(Scenario2_Polling.xaml)只有一个Get按钮,说明文字为:"Performs a single request to retrieve the current device orientation."
其代码极为精简,核心逻辑只有一步(Scenario2_Polling.xaml.cs):
private void ScenarioGet(object sender, RoutedEventArgs e) { if (_sensor != null) { DisplayOrientation(ScenarioOutput_Orientation, _sensor.GetCurrentOrientation()); } else { rootPage.NotifyUser("No simple orientation sensor found", NotifyType.ErrorMessage); } }GetCurrentOrientation()是同步方法,返回SimpleOrientation枚举值,不涉及事件注册与线程编组——适合需要"按需读取、低功耗"的场景。C++/CX 版实现完全一致(Scenario2_Polling.xaml.cpp)。
两种场景如何选择
| 维度 | 数据事件(Data Events) | 轮询(Polling) |
|---|---|---|
| 数据获取方式 | 事件驱动,方向变化自动推送 | 手动调用GetCurrentOrientation() |
| 适用场景 | 实时响应方向变化(如自动旋转 UI、翻转检测) | 按需读取一次快照(如进入页面时读取初始方向) |
| 线程要求 | 回调在后台线程,需Dispatcher编组到 UI 线程 | 同步调用,无线程切换负担 |
| 资源开销 | 持续监听,需在不可见/离开页面时注销 | 无持续监听,按需消耗 |
构建与运行
系统要求
- Windows 10 及以上操作系统;
- Visual Studio(含 UWP 开发工作负载,支持 C# 与 C++/CX)。
构建步骤
- 若通过 ZIP 方式获取示例,务必解压整个压缩包,而不是只解压单个示例文件夹——整个 Windows-universal-samples 集合共享
SharedContent依赖(本示例的 frontmatter 中extendedZipContent即声明了SharedContent与LICENSE的关联); - 启动 Visual Studio,选择File>Open>Project/Solution;
- 在解压目录下进入
Samples/SimpleOrientationSensor子文件夹,再进入首选语言的子目录(cs或cpp),双击其中的解决方案文件(.sln); - 按Ctrl+Shift+B,或选择Build>Build Solution完成构建。
运行与部署
- 仅部署:选择Build>Deploy Solution;
- 部署并调试运行:按F5,或选择Debug>Start Debugging;
- 部署并无调试运行:按Ctrl+F5,或选择Debug>Start Without Debugging。
运行后进入 "Simple Orientation Sensor" 示例页:选择Data Events场景点击 Enable,旋转或翻转设备即可看到方向实时刷新;选择Polling场景点击 Get,则单次读取当前方向。若设备无方向传感器,界面会显示 "No simple orientation sensor found" 错误提示。
参考与延伸
- 本示例曾提供 JavaScript(HTML/JS)版本,现已归档至 archived/SimpleOrientationSensor 目录;
- 仓库中还包含传感器家族的其他示例,如 OrientationSensor(三轴姿态传感器)、Accelerometer(加速度计)、Inclinometer(倾角计),接口模式与本示例一致(
GetDefault()+ 事件/轮询双场景),可相互参照; - 公共 UI 模板与共享代码位于 SharedContent/Templates 与 SharedContent/cpp(C++ 版示例依赖其中的共享 XAML 与基础设施)。
- 示例工程
【免费下载链接】Windows-universal-samples
API samples for the Universal Windows Platform.
相关推荐
为什么NonSteamLaunchers是Steam Deck玩家必备的终极游戏整合工具?
为什么NonSteamLaunchers是Steam Deck玩家必备的终极游戏整合工具? NonSteamLaunchers是一款专为Steam Deck设计
示例工程Windows-universal-samples Altimeter 示例全解析:UWP 高度计传感器的数据事件与轮询两种实现
Windows universal samples Altimeter 示例全解析:UWP 高度计传感器的数据事件与轮询两种实现 本指南围绕 Windows u
示例工程Qwen Code 接入微信:基于 iLink Bot API 的 WeChat 频道完整配置指南
Qwen Code 接入微信:基于 iLink Bot API 的 WeChat 频道完整配置指南 微信是目前最主流的即时通讯平台之一。Qwen Code 在
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考