示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载本指南以 Samples/PresenceSensor 示例为蓝本系统讲解 UWPUniversal Windows Platform中Windows.Devices.Sensors.HumanPresenceSensorAPI 的定位、获取、选择与数据读取方法。阅读完本文你将掌握如何获取默认存在传感器、按检测距离筛选传感器、通过系统选择器与设备监视器DeviceWatcher让用户自主选传感器以及如何通过事件与轮询两种方式读取实时数据并能在 Windows 11 设备上完成构建与部署。示例概述与场景矩阵本示例用于定位存在传感器Presence Sensor并从中读取数据覆盖了 HumanPresenceSensor API 的六个核心使用场景场景核心 API / 机制说明获取默认存在传感器HumanPresenceSensor.GetDefaultAsync()获取系统默认传感器并实时显示数据从可用传感器中选择一个GetDeviceSelector()DeviceInformation.FindAllAsync()FromIdAsync()枚举全部传感器按检测范围等条件挑选让用户选择传感器DevicePicker弹出系统标准选择器对话框检测传感器的接入与移除DeviceInformation.CreateWatcher()实时监控传感器热插拔存在传感器数据事件ReadingChanged事件传感器上报新读数时实时刷新 UI轮询存在传感器读数GetCurrentReading()按需读取当前读数快照在 SampleConfiguration.cs 中三个场景被注册为导航条目Data EventsScenario1、PollingScenario2、ChoosingScenario3对应功能名称Presence Sensor。仓库同时提供了 C#cs与 C/WinRTcppwinrt两种实现C 版本通过 Project.idl 声明运行时类界面则统一复用 shared 目录下的 XAML 文件。场景一数据事件——监听默认传感器的实时上报获取默认传感器点击 Get default sensor 按钮后示例通过HumanPresenceSensor.GetDefaultAsync()获取系统默认存在传感器并将结果绑定到ReadingChanged事件上数据会实时更新显示。核心代码见 Scenario1_DataEvents.xaml.cs// Try to get the default presence sensor. try { sensor await HumanPresenceSensor.GetDefaultAsync(); } catch (UnauthorizedAccessException) { // The user denied this app presence sensor access. sensor null; } if (sensor ! null) { VisualStateManager.GoToState(this, Ready, true); // Begin listening for data reports. sensor.ReadingChanged ReadingChanged; } else { rootPage.NotifyUser(No presence sensor found, NotifyType.ErrorMessage); }值得注意的细节权限拒绝处理若用户拒绝了本应用的传感器访问权限GetDefaultAsync()会抛出UnauthorizedAccessException示例捕获后将sensor置为null避免后续空引用。导航离开时解除订阅在OnNavigatedFrom中执行sensor.ReadingChanged - ReadingChanged并置空引用防止页面退出后事件继续触发导致泄漏。事件回调与读数结构ReadingChanged回调携带HumanPresenceSensorReadingChangedEventArgs其Reading属性为HumanPresenceSensorReading。示例在回调中通过Dispatcher.RunAsync回到 UI 线程更新界面Scenario1_DataEvents.xaml.csasync private void ReadingChanged(HumanPresenceSensor sender, HumanPresenceSensorReadingChangedEventArgs e) { await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () { HumanPresenceSensorReading reading e.Reading; if (null ! reading) { if (sensor.IsEngagementSupported) { EngagementStateTextBlock.Text reading.Engagement.ToString(); } else { EngagementStateTextBlock.Text Not Supported; } if (sensor.IsPresenceSupported) { DetectionStateTextBlock.Text reading.Presence.ToString(); } else { DetectionStateTextBlock.Text Not Supported; } // Show the detection distance, if available DetectionDistanceTextBlock.Text reading.DistanceInMillimeters null ? Unavailable : reading.DistanceInMillimeters.ToString(); TimestampTextBlock.Text reading.Timestamp.ToString(u); } }); }每次上报的读数包含四类信息对应界面上的四行显示见 Scenario1_DataEvents.xamlEngagement State参与状态由reading.Engagement提供仅在sensor.IsEngagementSupported为真时有效否则显示 Not SupportedDetection State存在检测状态由reading.Presence提供仅在sensor.IsPresenceSupported为真时有效Distance in mm检测距离毫米reading.DistanceInMillimeters为可空值为null时显示 UnavailableTimestamp时间戳reading.Timestamp以u通用可排序格式格式化输出。这种先查能力位、再读对应字段的防御式写法是因为不同硬件所支持的检测能力并不相同示例为不支持的能力预留了降级显示。UI 侧通过VisualStateManager的Ready状态在获取到传感器后将 Get default sensor 按钮收起、展开数据面板见 Scenario1_DataEvents.xaml。场景二轮询——枚举传感器并按检测范围挑选枚举全部存在传感器与场景一直接取默认传感器不同场景二先通过HumanPresenceSensor.GetDeviceSelector()获取设备选择器字符串再用DeviceInformation.FindAllAsync()枚举系统全部存在传感器为挑选最合适的传感器提供基础Scenario2_Polling.xaml.csstring selector HumanPresenceSensor.GetDeviceSelector(); DeviceInformationCollection deviceInfos await DeviceInformation.FindAllAsync(selector); foreach (DeviceInformation deviceInfo in deviceInfos) { HumanPresenceSensor foundSensor null; try { foundSensor await HumanPresenceSensor.FromIdAsync(deviceInfo.Id); } catch (UnauthorizedAccessException) { // The user denied this app presence sensor access. foundSensor null; } ... }按检测距离区间筛选示例以传感器报告的检测距离范围作为挑选依据演示了用数据指导选型的思路。MinDetectableDistanceInMillimeters与MaxDetectableDistanceInMillimeters分别表示该传感器可检测的最小/最大距离毫米示例要求候选传感器覆盖 200mm1200mm0.2m1.2m的区间const uint distanceInMillimetersLValue 200; // 0.2m const uint distanceInMillimetersRValue 1200; // 1.2m if (foundSensor.MinDetectableDistanceInMillimeters distanceInMillimetersLValue foundSensor.MaxDetectableDistanceInMillimeters distanceInMillimetersRValue) { rootPage.NotifyUser(Found a presence sensor that meets the detection range, NotifyType.StatusMessage); sensor foundSensor; } else { rootPage.NotifyUser(Presence sensor does not meet the detection range, using it anyway, NotifyType.StatusMessage); sensor foundSensor; // Your app may decide not to use this sensor and keep looking for another. }代码注释明确指出这两个阈值是TODO: Customize these values to your applications needs——生产应用应根据自身业务场景如近场交互、远距离探测调整该区间。同时注意部分传感器不报告检测范围MaxDetectableDistanceInMillimeters为null示例对这种传感器采用照常使用策略而真实应用可能选择继续寻找更合适的设备。读取单次读数快照选定传感器后点击 Get Data 按钮即可通过GetCurrentReading()同步读取当前读数Scenario2_Polling.xaml.csHumanPresenceSensorReading reading; try { reading sensor.GetCurrentReading(); } catch (UnauthorizedAccessException) { reading null; } if (reading ! null) { // 与场景一相同的字段输出逻辑Engagement / Presence / DistanceInMillimeters / Timestamp }轮询与事件的差异在于事件模式由硬件主动推送、适合持续监控轮询模式按需取快照、适合用户点击才刷新的交互。示例中GetCurrentReading()为同步调用无需await。UI 侧 Scenario2_Polling.xaml 在进入Ready状态后才启用 Get Data 按钮。场景三选择——系统选择器与动态监视器使用 DevicePicker 让用户挑选点击 Use picker 按钮时示例使用DevicePicker弹出系统标准设备选择对话框用户选定后应用立即读取一次读数Scenario3_Choosing.xaml.csDevicePicker picker new DevicePicker(); picker.Appearance.Title Select a presence sensor from which to read data; picker.Filter.SupportedDeviceSelectors.Add(HumanPresenceSensor.GetDeviceSelector()); // Calculate the position of the button next to which we will place the picker. GeneralTransform transform ScenarioPickButton.TransformToVisual(null); Rect rect transform.TransformBounds(new Rect(0.0, 0.0, ScenarioPickButton.ActualWidth, ScenarioPickButton.ActualHeight)); DeviceInformation deviceInfo await picker.PickSingleDeviceAsync(rect); if (deviceInfo ! null) { await ReadOneReadingFromSensorAsync(deviceInfo); }要点通过picker.Filter.SupportedDeviceSelectors.Add(HumanPresenceSensor.GetDeviceSelector())限定选择器只显示存在传感器PickSingleDeviceAsync(rect)以按钮的屏幕坐标为锚点弹出选择器返回用户选中的DeviceInformation选中后复用统一的ReadOneReadingFromSensorAsync辅助方法先FromIdAsync打开传感器再GetCurrentReading()读取并展示若打开失败用户拒绝授权则提示 Could not access sensor。使用 DeviceWatcher 动态监视传感器插拔点击 Start watcher 按钮时示例通过DeviceInformation.CreateWatcher(HumanPresenceSensor.GetDeviceSelector())创建设备监视器实时监听传感器设备的添加、移除、更新与枚举完成四种事件Scenario3_Choosing.xaml.cswatcher DeviceInformation.CreateWatcher(HumanPresenceSensor.GetDeviceSelector()); watcher.Added OnHumanPresenceSensorAdded; watcher.Removed OnHumanPresenceSensorRemoved; watcher.Updated OnHumanPresenceSensorUpdated; watcher.EnumerationCompleted OnHumanPresenceSensorEnumerationCompleted; watcher.Start();四个事件处理器的职责事件处理逻辑Added将新发现的传感器以ListBoxItem内容为设备名、Tag存放DeviceInformation加入列表 Scenario3_Choosing.xaml.csRemoved按DeviceInformationUpdate.Id在列表中找到对应项并移除 Scenario3_Choosing.xaml.csUpdated调用itemDeviceInfo.Update(update)刷新设备信息并同步更新显示名称 Scenario3_Choosing.xaml.csEnumerationCompleted通知用户 All sensors found. Monitoring for changes...表示首次枚举完成、进入持续监视阶段 Scenario3_Choosing.xaml.cs所有回调都通过Dispatcher.RunAsync切回 UI 线程再操作ListBox符合 UWP 的线程模型要求。页面离开时在OnNavigatedFrom中调用watcher.Stop()停止监视Scenario3_Choosing.xaml.cs。从列表中选中某传感器并点击 Poll selected sensor 按钮即可读取该传感器的当前读数。界面布局见 Scenario3_Choosing.xaml设备列表SensorsList居中占满一行读数面板置于底部。权限声明humanPresence 设备能力HumanPresenceSensor 属于受保护的系统设备应用必须在清单中显式声明对应的设备能力。C# 版本的 Package.appxmanifest 中声明如下Capabilities DeviceCapability NamehumanPresence/ /Capabilities此外清单的TargetDeviceFamily声明了最低目标版本MinVersion10.0.22621.1778这与 README 中Windows 11 build 22624 或更高的系统要求一致——HumanPresenceSensor API 是较新的传感器 API仅在较新版本的 Windows 11 上可用。若缺少该能力声明运行时访问传感器会抛出UnauthorizedAccessException这正是三个场景的代码中反复捕获该异常的原因。C/WinRT 版本同样在 cppwinrt 的清单 中声明了该能力。系统要求与构建运行系统要求Windows 11 build 22624 或更高版本存在传感器 API 依赖较新的系统版本旧版本系统上无法正常运行。构建示例若下载的是示例 ZIP 压缩包务必解压整个压缩包而不是只解压包含目标示例的文件夹——示例依赖仓库根目录的SharedContent目录中的共享代码与资源README 头部 frontmatter 中的extendedZipContent也指定了SharedContent与LICENSE需要一并解压。启动 Microsoft Visual Studio选择文件打开项目/解决方案。在解压目录中依次进入Samples子目录 → 本示例子目录 → 首选语言子目录C 或 C#双击其中的解决方案文件.sln。本仓库提供了 PresenceSensor.slnC#与 PresenceSensor.slnC/WinRT两个解决方案。按CtrlShiftB或选择生成生成解决方案。运行示例后续步骤取决于你是只部署还是既要部署又要运行仅部署选择生成部署解决方案。部署并运行调试按F5或选择调试开始调试。运行不调试按CtrlF5或选择调试开始执行不调试。运行时请确认设备具备存在传感器硬件如支持用户存在检测的笔记本/一体机并在系统弹出权限提示时允许应用访问否则三个场景均会因UnauthorizedAccessException而提示传感器不可用。相关主题本示例聚焦读取一侧的传感器 API与之互补的周边主题包括ProximitySensor接近传感器示例Samples/ProximitySensor——同为设备感应类 API关注近距离探测可与存在传感器对照学习DeviceEnumerationAndPairing设备枚举与配对示例Samples/DeviceEnumerationAndPairing——展示更多针对设备的操作如高级枚举、配对与筛选可用于深化场景三中选择传感器部分的实现。小结PresenceSensor 示例完整覆盖了 HumanPresenceSensor API 的两条主线事件驱动ReadingChanged实时推送与按需轮询GetCurrentReading()快照读取并在此基础上演示了三种获取传感器的方式——默认传感器、按能力筛选、用户主动选择DevicePicker/DeviceWatcher。从源码可以提炼出四条可复用的工程经验始终捕获UnauthorizedAccessException以优雅处理权限拒绝读取字段前先检查IsEngagementSupported/IsPresenceSupported能力位处理可空字段如DistanceInMillimeters在页面导航离开时解除事件订阅并停止 DeviceWatcher。配合humanPresence设备能力声明与 Windows 11 build 22624 的系统前提即可在真实设备上构建出可靠的存在感知能力。赞分享示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载相关推荐Easy-Query实体代理机制解析如何实现零反射高性能Easy Query实体代理机制解析如何实现零反射高性能 在Java ORM框架中反射机制虽然简化了开发但往往成为性能瓶颈。Easy Query作为一款轻示例工程OnnxStream源码深度解读核心操作符实现与执行流程OnnxStream源码深度解读核心操作符实现与执行流程 OnnxStream是一款轻量级ONNX推理库采用C编写能够在资源受限设备上高效运行各类ON示例工程arduino-esp32 BLE 验证测试双 DUT 安全配对、特性读写与广播解析回归的完整实现剖析arduino esp32 BLE 验证测试双 DUT 安全配对、特性读写与广播解析回归的完整实现剖析 本篇技术文章围绕 tests/validation/b示例工程上一篇Notepads 终极指南为什么这款现代文本编辑器完胜传统记事本下一篇构建高性能C网络通信架构brynet跨平台TCP库的深度技术实现方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
大模型Agent技能库:从Prompt到可复用技能包的工程实践 最近好几个团队朋友都在聊同一个话题:大模型 Agent 跑起来不难,三行代码就能让模型调工具,可真要多步任务稳定执行、跨项目复用,几乎每个人都在重复造轮子。我自己的做法是把这类可复用的能力沉淀成一套结构化的技能包,… · 2026/9/25 7:09:54
前端工程师必备:用浏览器开发者工具精准获取HTML/CSS/JS源码 1. 这不是“扒”,是前端工程师的日常基本功很多人一看到“获取网页源码”“扒JS CSS HTML”这几个词,第一反应是带点灰色色彩的操作——好像得用什么神秘工具、绕过什么限制、偷偷摸摸搞点东西。其实完全不是。我干这行十多年,每天打开浏览器… · 2026/9/25 7:09:54
LM Studio本地大模型部署实战:GGUF量化与OpenAI兼容API 1. 为什么现在必须亲手部署一个本地大模型?——LM Studio 不是玩具,而是生产力工具你有没有过这样的时刻:在写一份技术方案时卡在第三段,反复删改却始终找不到精准的表达;调试一段 Python 脚本,报错信息像天… · 2026/9/25 7:09:54
小红书香港老号自动筛选全流程:量化标准与批量部署实操 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 7:35:16
嵌入式MCU开发全链路:编译、烧录与仿真流程详解 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 7:35:16
钕铁硼磁体原料组成与配方设计关键技术解析 1. 烧结钕铁硼磁体的原料组成概述 烧结钕铁硼(NdFeB)作为第三代稀土永磁材料,其优异的磁性能主要来源于精心设计的化学成分和微观结构。在实际工业生产中,配方设计就像烹饪一道美味佳肴——主料决定基本风味,而辅料和… · 2026/9/25 7:35:16
微信读书下载工具:Python开源方案实现本地备份 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 7:35:16
I2C总线调试实战:开漏输出、上拉电阻与多主仲裁全解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 7:35:16
C# 实现欧姆龙 FINS 协议通信:AMS Net ID、字节序与TCP握手详解 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 7:35:10
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37