- 示例工程
【免费下载链接】Windows-universal-samples
API samples for the Universal Windows Platform.
本指南以 Samples/PowerGrid/README.md 为主线,深入讲解 Windows Universal Platform(UWP)下Windows.Devices.Power.PowerGridForecast电网预测 API 的完整用法。你将掌握如何获取电网预测数据、订阅ForecastUpdated更新通知、以及在指定时间范围内筛选最低严重级别时段,并看到 C# 与 C++/WinRT 两套语言实现中对应的源码级细节。
示例概述
PowerGrid 示例展示了如何调用 Windows 11 的 PowerGrid Forecast(电网预测)API。根据官方 README,该示例覆盖三个核心主题:
- Obtaining the power grid forecast:获取电网预测数据;
- Registering for ForecastUpdated notifications:注册预测更新通知;
- Looking for the lowest severity in a specified timeframe:在指定时间段内寻找严重级别(Severity)最低的时段。
预测数据由系统按固定时间块(block)组织:每个块都有一个起止时间(由StartTime与BlockDuration决定)、一个严重级别数值Severity,以及一个布尔标志IsLowUserExperienceImpact,用来标记该时段是否属于“低用户体验影响”窗口(例如适合执行耗电任务或后台更新的时段)。
该示例是 Windows-universal-samples 大型 UWP 示例集合中的一员,需要在 Visual Studio 中构建、在 Windows 11 上运行。示例包含两个场景,注册逻辑位于各语言的SampleConfiguration文件中:
Find best time(Scenario1_FindBest):在用户指定的“未来 N 小时”内寻找严重级别最低的时间块;Display full forecast(Scenario2_PrintFullForecast):把整份预测按时间块逐条展示在列表中。
C# 的注册代码见 Samples/PowerGrid/cs/SampleConfiguration.cs,C++/WinRT 版本见 Samples/PowerGrid/cppwinrt/SampleConfiguration.cpp,两个版本都把FEATURE_NAME定义为"PowerGrid",并分别把两个场景的Type(C#)或xaml_typename(C++/WinRT)注册进导航列表。
系统要求与构建环境
README 明确给出了示例的运行前提,这也是 PowerGridForecast API 的最低要求:
- Windows 11 SDK(build 26100 或更高);
- Windows 11(build 26100 或更高)。
Package.appxmanifest中的目标设备族配置与此一致:C# 与 C++/WinRT 两个工程都把TargetDeviceFamily的MinVersion和MaxVersionTested设置为10.0.26100.0,见 Samples/PowerGrid/cs/Package.appxmanifest 与 Samples/PowerGrid/cppwinrt/Package.appxmanifest。因此若要在低于 build 26100 的系统中编译或运行,API 将不可用。
构建步骤(README 原文要点):
- 如果下载的是示例 ZIP 压缩包,务必解压整个归档,而不是只解压要构建的那一个子目录——整个示例集合共享
SharedContent等公共依赖; - 启动 Microsoft Visual Studio,选择File > Open > Project/Solution;
- 在解压目录下依次进入
Samples子目录、本示例子目录(PowerGrid)、再进入首选语言子目录(cs或cppwinrt),双击其中的解决方案文件(.sln),例如 Samples/PowerGrid/cs/PowerGrid.sln 或 Samples/PowerGrid/cppwinrt/PowerGrid.sln; - 按
Ctrl+Shift+B,或选择Build > Build Solution完成构建。
运行方式取决于需求:
- 仅部署:选择Build > Deploy Solution;
- 部署并调试运行:按
F5,或选择Debug > Start Debugging; - 部署但不调试运行:按
Ctrl+F5,或选择Debug > Start Without Debugging。
示例目录结构
本示例按语言拆分源码,XAML 界面则统一放在共享目录:
Samples/PowerGrid/ ├── README.md # 官方说明文档 ├── cs/ # C# 实现 │ ├── SampleConfiguration.cs # 场景注册 │ ├── Scenario1_FindBest.xaml.cs │ ├── Scenario2_PrintFullForecast.xaml.cs │ ├── PowerGrid.csproj / PowerGrid.sln │ └── Package.appxmanifest ├── cppwinrt/ # C++/WinRT 实现 │ ├── SampleConfiguration.cpp / .h │ ├── Scenario1_FindBest.cpp / .h │ ├── Scenario2_PrintFullForecast.cpp / .h │ ├── Project.idl # 场景类的 IDL 声明 │ └── Package.appxmanifest └── shared/ # 两种语言共用的 XAML ├── Scenario1_FindBest.xaml └── Scenario2_PrintFullForecast.xamlC++/WinRT 版本通过 Samples/PowerGrid/cppwinrt/Project.idl 声明两个页面类以及ForecastItem运行时类(含DateTimeString、SeverityString、LowImpactString三个只读属性),供 XAML 数据绑定使用。
核心 API:PowerGridForecast 与 PowerGridData
示例核心对象来自Windows.Devices.Power命名空间:
PowerGridForecast:代表一份电网预测。关键成员:GetForecast():静态方法,同步获取当前预测;若系统暂时拿不到数据,返回的Forecast集合为空(示例据此判断“No forecast available”);ForecastUpdated:静态事件,当系统发布新预测时触发,可用于主动刷新 UI;StartTime:预测中第一个时间块的开始时间(DateTimeOffset/DateTime);BlockDuration:单个时间块的长度(TimeSpan),示例 UI 中以“分钟”展示;Forecast:PowerGridData的只读集合,每个元素对应一个时间块。
PowerGridData:单个时间块的数据,包含:Severity:该块的严重级别(double),数值越低表示越适合执行高耗电任务;IsLowUserExperienceImpact:布尔值,标记该时段对用户体验的影响是否较低。
场景一:在指定时间段内查找最低严重级别时段
Scenario1_FindBest演示“在指定时间范围内寻找最低严重级别”这一核心场景。其界面(Samples/PowerGrid/shared/Scenario1_FindBest.xaml)包含三个输入控件:
- 文本框
HoursAheadTextBox(默认值12):向前查看的小时数; - 复选框
LowUXImpactCheckBox(默认勾选):是否仅考虑低用户体验影响时段; - 按钮
FindBest(Find best time):触发查询。
C# 实现位于 Samples/PowerGrid/cs/Scenario1_FindBest.xaml.cs,核心流程如下:
// 收集用户输入 if (!uint.TryParse(HoursAheadTextBox.Text, out uint lookAheadHours)) { rootPage.NotifyUser("Unable to parse hours to look ahead", NotifyType.ErrorMessage); return; } TimeSpan lookAhead = TimeSpan.FromHours(lookAheadHours); bool restrictToLowUXImpact = LowUXImpactCheckBox.IsChecked.Value; // 计算放到后台线程,避免阻塞 UI await Task.Run(() => { gridForecast = PowerGridForecast.GetForecast(); DateTimeOffset startTime = DateTimeOffset.Now; DateTimeOffset endTime = startTime + lookAhead; int startBlock = GetForecastIndexContainingTime(gridForecast, startTime); int endBlock = GetForecastIndexContainingTime(gridForecast, endTime + gridForecast.BlockDuration); for (int index = startBlock; index < endBlock; ++index) { PowerGridData data = gridForecast.Forecast[index]; // 限制到低影响时段时,跳过非低影响块 if (restrictToLowUXImpact && !data.IsLowUserExperienceImpact) { continue; } // 只有严重级别更低的块才被采纳 if (data.Severity >= lowestSeverity) { continue; } lowestSeverity = data.Severity; timeWithLowestSeverity = gridForecast.StartTime + new TimeSpan(index * gridForecast.BlockDuration.Ticks); } });要点分析:
- 后台线程调用
GetForecast():C# 用Task.Run,C++/WinRT 用co_await winrt::resume_background()(见 Samples/PowerGrid/cppwinrt/Scenario1_FindBest.cpp),目的是不让网络/系统查询阻塞 UI 线程。 - 时间块索引换算:
GetForecastIndexContainingTime把任意时刻映射为所在块的索引——用(time - StartTime).Ticks / BlockDuration.Ticks计算,并用Math.Max(0, Math.Min(...))(C#)或std::clamp(C++/WinRT)把结果夹在[0, Forecast.Count]之间;同时通过blockDuration == TimeSpan.Zero判断避免除零。C++ 版本用TimeSpan的count()直接比较零值。查询结束块时额外加上一个BlockDuration,保证把“endTime 所在块”也纳入扫描。 - 最小严重级别筛选:遍历
[startBlock, endBlock)区间,在(可选的)低影响过滤之上,只保留严格更低的Severity,最终得到timeWithLowestSeverity与该块的起始时间。 - 结果判定与展示:只有当
lowestSeverity <= 1.0时才认为找到了合适时段,此时显示“最佳时间范围”和“最低严重级别”;否则提示Unable to find a good time to do work。
结果格式化在 C# 中通过Windows.Globalization完成:
var dateFormatter = new DateTimeFormatter("shortdate shorttime"); var severityFormatter = new DecimalFormatter() { FractionDigits = 2, IntegerDigits = 1, IsDecimalPointAlwaysDisplayed = true, NumberRounder = new IncrementNumberRounder() { Increment = 0.01 } }; BestTimeRun.Text = dateFormatter.Format(timeWithLowestSeverity) + " to " + dateFormatter.Format(timeWithLowestSeverity + gridForecast.BlockDuration); LowestSeverityRun.Text = severityFormatter.Format(lowestSeverity);C++/WinRT 版本在 Samples/PowerGrid/cppwinrt/Scenario1_FindBest.cpp 中结构相同,只是通过co_await winrt::resume_foreground(Dispatcher())回到 UI 线程后再更新控件。
场景二:完整打印电网预测
Scenario2_PrintFullForecast演示“获取整份预测”并把每个时间块渲染成表格。界面(Samples/PowerGrid/shared/Scenario2_PrintFullForecast.xaml)包含:
Get forecast按钮触发查询;ForecastStartTimeRun:展示预测起始时间;ForecastBlockDurationRun:展示单个时间块时长(分钟);ForecastList(ListView):逐条展示每个时间块的时间、严重级别、是否低影响,行模板通过{x:Bind DateTimeString}等绑定到ForecastItem。
C# 实现见 Samples/PowerGrid/cs/Scenario2_PrintFullForecast.xaml.cs,核心逻辑:
// 后台线程获取预测,避免阻塞 UI PowerGridForecast gridForecast = await Task.Run(() => PowerGridForecast.GetForecast()); // API 无法获取预测时,Forecast 为空集合 if (gridForecast.Forecast.Count == 0) { rootPage.NotifyUser("No forecast available. Try again later.", NotifyType.ErrorMessage); return; } DateTimeOffset blockStartTime = gridForecast.StartTime; TimeSpan blockDuration = gridForecast.BlockDuration; ForecastStartTimeRun.Text = blockStartTime.ToString("F"); ForecastBlockDurationRun.Text = blockDuration.TotalMinutes.ToString(); var items = new List<ForecastItem> { new ForecastItem { DateTimeString = "Date/Time", SeverityString = "Severity", LowImpactString = "Low impact?" } }; var dateFormatter = new DateTimeFormatter("shortdate shorttime"); var severityFormatter = new DecimalFormatter() { /* 同场景一 */ }; foreach (PowerGridData data in gridForecast.Forecast) { items.Add(new ForecastItem { DateTimeString = dateFormatter.Format(blockStartTime), SeverityString = severityFormatter.Format(data.Severity), LowImpactString = data.IsLowUserExperienceImpact.ToString() }); blockStartTime += blockDuration; } ForecastList.ItemsSource = items;该场景体现了两个值得注意的工程细节:
- 空预测的显式处理:
GetForecast()并不抛异常,而是返回Forecast.Count == 0的空集合,示例据此提示“No forecast available. Try again later.”,这是处理电网数据暂不可用场景的推荐姿势。 - 按块推算时间:列表里的每个时间点并非来自数据本身,而是从
StartTime开始按BlockDuration逐块累加得到,与场景一的索引换算互为印证。
订阅 ForecastUpdated 更新通知
两个场景都在页面导航时注册PowerGridForecast.ForecastUpdated事件、离开时注销,实现“新预测到达时提示用户重新查询”。C# 写法:
protected override void OnNavigatedTo(NavigationEventArgs e) { PowerGridForecast.ForecastUpdated += PowerGridForecast_ForecastUpdated; } protected override void OnNavigatedFrom(NavigationEventArgs e) { PowerGridForecast.ForecastUpdated -= PowerGridForecast_ForecastUpdated; } private void PowerGridForecast_ForecastUpdated(object sender, object e) { // 新预测可用,提示用户重新点击查询按钮 rootPage.NotifyUser("New forecast is available, click \"Find best time\" to find a new best time", NotifyType.StatusMessage); }C++/WinRT 使用事件令牌(event_token)完成注册与注销(见 Samples/PowerGrid/cppwinrt/Scenario1_FindBest.cpp 与 Samples/PowerGrid/cppwinrt/Scenario1_FindBest.h):
// OnNavigatedTo:注册 forecastUpdatedToken = PowerGridForecast::ForecastUpdated( { get_weak(), &Scenario1_FindBest::PowerGridForecast_ForecastUpdated }); // OnNavigatedFrom:注销 PowerGridForecast::ForecastUpdated(forecastUpdatedToken);get_weak()弱引用可避免页面销毁后事件回调悬空;两个场景的事件处理器都只做 UI 提示,不自动重拉数据,把“何时刷新”的决策权留给用户,这是示例刻意保持的简洁交互设计。
总结与延伸阅读
PowerGrid 示例把电网预测 API 的三种典型用法浓缩为两个场景:一是“找最佳时段”(时间块索引换算 + 最小 Severity 扫描 + 低影响过滤),二是“完整展示预测”(空集合判空 + 按块累加时间戳),并以ForecastUpdated事件串起“预测刷新—用户重查”的闭环。所有界面逻辑共享同一套 XAML,C# 与 C++/WinRT 实现保持对等,可作为接入Windows.Devices.Power.PowerGridForecast的参考模板。
延伸阅读入口:
- 示例说明文档:Samples/PowerGrid/README.md;
- 场景一源码:Samples/PowerGrid/cs/Scenario1_FindBest.xaml.cs、Samples/PowerGrid/cppwinrt/Scenario1_FindBest.cpp;
- 场景二源码:Samples/PowerGrid/cs/Scenario2_PrintFullForecast.xaml.cs、Samples/PowerGrid/cppwinrt/Scenario2_PrintFullForecast.cpp;
- 界面定义:Samples/PowerGrid/shared/Scenario1_FindBest.xaml、Samples/PowerGrid/shared/Scenario2_PrintFullForecast.xaml。
如需在 Win32 桌面应用中获取电网预测,可参考 Windows-classic-samples 仓库中的同名 PowerGrid 示例(README 的 Related samples 一节已给出指引)。
- 示例工程
【免费下载链接】Windows-universal-samples
API samples for the Universal Windows Platform.
相关推荐
UWP 相机预览帧获取实战:Windows-universal-samples 中 CameraGetPreviewFrame 样例的 MediaCapture 全流程解析
UWP 相机预览帧获取实战:Windows universal samples 中 CameraGetPreviewFrame 样例的 MediaCapture
示例工程PDF 跨设备中文变方块?PDF 补丁丁字体嵌入与替换的完整修复教程
PDF 跨设备中文变方块?PDF 补丁丁字体嵌入与替换的完整修复教程 一份合同 PDF 发到同事的电脑上,正文中文全成了 □□□,自己这边却显示正常。问题多半出
示例工程Windows-universal-samples 中的 Direct2D 渐变网格(Gradient Mesh)示例解析
Windows universal samples 中的 Direct2D 渐变网格(Gradient Mesh)示例解析 本指南以 Windows unive
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考