基于Visual C#2010 与WPF开发Windows 7电源管理

关注微软动态的用户还记得他发布的那份“Windows 7 Power Management”白皮书吗?这个白皮书详细的讲述了Win7的电源管理技术方案,和如何降低电能消耗的原理。那么这个原理是怎么样的呢?

  1. 空闲资源的能耗

  这是众多省电技术中最根本的一项节电技术。在Win7里,空闲时的耗电量得到有效改善,当某个硬件一定时间不工作后就会进入低功耗状态已达到省电的目的。包括CPU,硬盘,内存以及网络部分都采用了这种技术。举例说就是当系统在空闲状态下基本能耗就是0W。

  2. 通过触发来启动服务

  在Win7里,部分系统服务只有被一些事件触发后才会启动,如插入某个设备或者更改IP。这样可以减少后台进程里长时间运行的服务数量。

  3. 增强的处理器电源管理

  Win7里集成了最新的电源管理技术,该技术能够让Win7根据当前负载情况和性能要求来动态的调节CPU性能。也就是我们常说的自动降频技术。

  4. 自适应的显示亮度调节

  搭载Win7的笔记本中将会内置光线感应器,用来感应使用环境的光线强度,这样操作系统会自动根据周围环境亮度来调整显示器亮度达到省电的目的。

  5. 低功率音频

  Win7将会支持Intel的低功耗HD音频规范,它能让编解码器进入极低的功耗状态。Win7还支持选择性挂起技术,将处于闲置状态的设备关闭,比如麦克风和摄像头这类USB设备。

  6. 计时器整合

  处理器通过利用处理指令的间隙空余时间来达到节能目的,但大部分节能技术都需要一定长度的空闲时间才能获得节能效果。而这项技术通过让Windows内核在同一时间内终止并集中原本较为分散的多个计时器,在短时间内处理完毕,从而增加了处理器的空闲时间。当笔记本在使用电池的情况下,Win7会减少非关键后台程序的活动频率。

  7. 蓝牙设备功耗改进

  当Win7检测到蓝牙设备处于低功耗状态时,会自动切换到“选择性挂起”状态一旦蓝牙设备提高功耗,便将**蓝牙功能。

  8. 网络设备功耗改进

  Win7中对于无线网络控制器低功耗模式的兼容性得到了加强,只有在无线AP设备支持低功耗模式的情况下才会启用。Win7会先检测无线AP是否支持低功耗模式,避免无线网络连接突然中断的发生。

  9. 典型应用的优化方案

  另外Win7还可以将其他硬件能耗降低,如在不影响播放性能的前提下让CPU保持低功耗模式,通过改变架构来改进桌面窗口管理器和GPU的功耗,智能数据缓存能降低光驱转速。

我们来基于Visual C#2010 与WPF实践一下,开发一个Windows 7电源管理演示程序!启动VS2010

创建一个基于.net4.0的WPF文件,然后布局好下列按钮

XAML代码如下

<!-- Copyright (c) Microsoft Corporation. All rights reserved. --> <Window x:Class="Microsoft.WindowsAPICodePack.Samples.PowerMgmtDemoApp.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Microsoft.WindowsAPICodePack.Samples.PowerMgmtDemoApp" Title="电源管理-CSDN专家尹成的杰作" Height="592.163" Width="527.725" Loaded="Window_Loaded" Name="window1" SizeToContent="WidthAndHeight" ResizeMode="CanMinimize" Icon="/PowerMgmtDemoApp;component/powercfg.png" WindowStartupLocation="CenterScreen"> <Window.Resources> <local:MyPowerSettings x:Key="powerSettings"/> <local:YesNoConverter x:Key="boolConverter"/> </Window.Resources> <TabControl Height="533.28" Name="tabControl1" Width="499.95" SelectedIndex="0"> <TabItem Name="PropertiesTab" Header="电源信息"> <StackPanel Height="485" Width="468.842"> <Grid Height="271" Width="457" HorizontalAlignment="Left" Margin="3,3,3,3" VerticalAlignment="Top" DataContext="{StaticResource powerSettings}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" MinWidth="120" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="20.65*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> <RowDefinition Height="18.887*" /> </Grid.RowDefinitions> <TextBlock Name="tb0" FontSize="12" Text="电源类型:" /> <TextBlock Grid.Column="1" Height="29" Name="personalityText" VerticalAlignment="Top" Text="{Binding Path=PowerPersonality}"/> <TextBlock Grid.Column="0" Grid.Row="1" Name="tb1" FontSize="12" Text="电源:"/> <TextBlock Grid.Column="1" Grid.Row="1" Height="29" Name="powerSourceText" VerticalAlignment="Top" Text="{Binding Path=PowerSource}"/> <TextBlock Grid.Column="0" Grid.Row="2" Name="tb2" FontSize="12" Text="是否电池电源:"/> <TextBlock Grid.Column="1" Grid.Row="2" Height="29" Name="batteryPresentText" VerticalAlignment="Top" Text="{Binding Path=BatteryPresent, Converter={StaticResource boolConverter}}" HorizontalAlignment="Stretch" /> <TextBlock Grid.Column="0" Grid.Row="3" Name="tb3" FontSize="12" Text="是否交流电源"/> <TextBlock Grid.Column="1" Grid.Row="3" Height="29" Name="upsText" VerticalAlignment="Top" Text="{Binding Path=UpsPresent, Converter={StaticResource boolConverter}}"/> <TextBlock Grid.Column="0" Grid.Row="4" Name="tb4" FontSize="12" Text="是否短期电池: "/> <TextBlock Grid.Column="1" Grid.Row="4" Height="29" Name="batteryShortTermText" VerticalAlignment="Top" Text="{Binding Path=BatteryShortTerm, Converter={StaticResource boolConverter}}"/> <TextBlock Grid.Column="0" Grid.Row="5" Name="tb5" FontSize="12" Text="电源电量 (%):"/> <ProgressBar Grid.Column="1" Grid.Row="5" Margin="1.111,0.47,0,18.887" Name="progressBar1" SmallChange="1" Value="{Binding Path=BatteryLifePercent}" ToolTip="{Binding Path=BatteryLifePercent}" Grid.RowSpan="2" HorizontalAlignment="Left" Width="255.694" /> <Label FontSize="12" Grid.RowSpan="2" Margin="0,14.229,27.775,0.983" Name="batteryLifePercentLabel" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Right" Width="52.217"></Label> <TextBlock Grid.Column="0" Grid.Row="6" Name="tb6" FontSize="12" Text="是否需要显示器:"/> <TextBlock Grid.Column="1" Grid.Row="6" Height="29" Name="monitorReqText" VerticalAlignment="Top" Text="{Binding Path=MonitorRequired, Converter={StaticResource boolConverter}}"/> <TextBlock Grid.Column="0" Grid.Row="7" Name="tb7" FontSize="12" Text="显示器是否开着:"/> <TextBlock Grid.Column="1" Grid.Row="7" Height="29" Name="monitorOnText" VerticalAlignment="Top" Text="{Binding Path=MonitorOn, Converter={StaticResource boolConverter}}"/> <TextBlock Grid.Column="0" Grid.Row="8" Name="tb8" FontSize="12" Text="电池状态:"/> <TextBlock Grid.Column="1" Grid.Row="8" Grid.RowSpan="6" Name="batteryStateText" VerticalAlignment="Top" Text="{Binding Path=BatteryState}"/> </Grid> <ListBox Name="messagesListBox" Height="193.314" Width="459.954"></ListBox> </StackPanel> </TabItem> <TabItem Name="PowerSourceChangedEventTab" Header="电源事件"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="119*" /> <RowDefinition Height="214.04*" /> </Grid.RowDefinitions> <Button Content="开始寻找" Name="StartStopIndexerButton" Click="StartIndexer" Height="30" Width="137" /> <Label Grid.Row="1" Name="IndexerStatusLabel" Height="70" VerticalAlignment="Top" Content="单击寻找按钮检查电源事件"></Label> <Label Grid.Row="1" Margin="0,70,0,75" Name="IndexerCurrentFileLabel" Content="当前文件:"></Label> </Grid> </TabItem> </TabControl> </Window>

具体代码如下,详细请见代码注释

using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Interop; using System.Windows.Threading; using Microsoft.WindowsAPICodePack.ApplicationServices; using Microsoft.WindowsAPICodePack.Shell; namespace Microsoft.WindowsAPICodePack.Samples.PowerMgmtDemoApp { /// <summary> /// Interaction logic for Window1.xaml /// </summary> /// public partial class Window1 : Window { [DllImport("user32.dll")] private static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam); public delegate void MethodInvoker(); private MyPowerSettings settings; private BackgroundWorker backgroundWorker = new BackgroundWorker(); private string cancelReason = string.Empty; private System.Windows.Threading.DispatcherTimer TimerClock; public Window1() { InitializeComponent(); settings = (MyPowerSettings)this.FindResource("powerSettings"); backgroundWorker.WorkerReportsProgress = true; backgroundWorker.WorkerSupportsCancellation = true; backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork); backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted); // 设置时钟监视电源变化 TimerClock = new DispatcherTimer(); TimerClock.Interval = new TimeSpan(0, 0, 5); TimerClock.IsEnabled = true; TimerClock.Tick += new EventHandler(TimerClock_Tick); } void TimerClock_Tick(object sender, EventArgs e) { GetPowerSettings(); } void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // 更新按钮标题 if (string.IsNullOrEmpty(cancelReason)) { SetLabelButtonStatus(IndexerCurrentFileLabel, "寻找完成!"); SetLabelButtonStatus(IndexerStatusLabel, "点击开始寻找按钮继续开始寻找."); SetLabelButtonStatus(StartStopIndexerButton, "开始寻找电源事件!"); } // 清除所有信息 cancelReason = ""; } void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { SetLabelButtonStatus(IndexerCurrentFileLabel, "检索进行中 ...."); IKnownFolder docs; if (ShellLibrary.IsPlatformSupported) docs = KnownFolders.DocumentsLibrary; else docs = KnownFolders.Documents; ShellContainer docsContainer = docs as ShellContainer; foreach (ShellObject so in docs) { RecurseDisplay(so); if (backgroundWorker.CancellationPending) { SetLabelButtonStatus(StartStopIndexerButton, "开始检索"); SetLabelButtonStatus(IndexerStatusLabel, "点击开始寻找按钮继续开始寻找."); SetLabelButtonStatus(IndexerCurrentFileLabel, (cancelReason == "电源改变") ? "因为电源放弃检索" : "因为使用者放弃检索"); return; } Thread.Sleep(1000); // 休眠1秒,以指示该文件的索引 } } private void Window_Loaded(object sender, RoutedEventArgs e) { CapturePowerManagementEvents(); GetPowerSettings(); } //获取从PowerManager的当前属性值。 //此方法是在启动时调用。 private void GetPowerSettings() { settings.PowerPersonality = PowerManager.PowerPersonality.ToString(); settings.PowerSource = PowerManager.PowerSource.ToString(); settings.BatteryPresent = PowerManager.IsBatteryPresent; settings.UpsPresent = PowerManager.IsUpsPresent; settings.MonitorOn = PowerManager.IsMonitorOn; settings.MonitorRequired = PowerManager.MonitorRequired; if (PowerManager.IsBatteryPresent) { settings.BatteryShortTerm = PowerManager.IsBatteryShortTerm; settings.BatteryLifePercent = PowerManager.BatteryLifePercent; BatteryState batteryState = PowerManager.GetCurrentBatteryState(); string batteryStateStr = string.Format( "ACOnline: {1}{0}最大充电: {2} mWh{0}兆瓦时电流充电: {3} mWh{0}兆瓦时放电率: {4} {0}估计剩余时间: {5}{0}建议临界电池更换: {6} mWh{0}建议兆瓦电池充电警告: {7} mWh{0}", Environment.NewLine, batteryState.ACOnline, batteryState.MaxCharge, batteryState.CurrentCharge, batteryState.ACOnline == true ? "N/A" : batteryState.DischargeRate.ToString() + " mWh", batteryState.ACOnline == true ? "N/A" : batteryState.EstimatedTimeRemaining.ToString(), batteryState.SuggestedCriticalBatteryCharge, batteryState.SuggestedBatteryWarningCharge ); settings.BatteryState = batteryStateStr; } } // 增加了对PowerManager的事件的事件处理程序。 private void CapturePowerManagementEvents() { PowerManager.IsMonitorOnChanged += new EventHandler(MonitorOnChanged); PowerManager.PowerPersonalityChanged += new EventHandler( PowerPersonalityChanged); PowerManager.PowerSourceChanged += new EventHandler(PowerSourceChanged); if (PowerManager.IsBatteryPresent) { PowerManager.BatteryLifePercentChanged += new EventHandler(BatteryLifePercentChanged); SetLabelButtonStatus(batteryLifePercentLabel, string.Format("{0}%", PowerManager.BatteryLifePercent.ToString())); } PowerManager.SystemBusyChanged += new EventHandler(SystemBusyChanged); } // PowerManager的事件处理程序。 void MonitorOnChanged(object sender, EventArgs e) { settings.MonitorOn = PowerManager.IsMonitorOn; AddEventMessage(string.Format("显示器状态改变 (new status: {0})", PowerManager.IsMonitorOn ? "On" : "Off")); } void PowerPersonalityChanged(object sender, EventArgs e) { settings.PowerPersonality = PowerManager.PowerPersonality.ToString(); AddEventMessage(string.Format("电源变化(current setting: {0})", PowerManager.PowerPersonality.ToString())); } void PowerSourceChanged(object sender, EventArgs e) { settings.PowerSource = PowerManager.PowerSource.ToString(); AddEventMessage(string.Format("电源设置变化 (current source: {0})", PowerManager.PowerSource.ToString())); // if (backgroundWorker.IsBusy) { if (PowerManager.PowerSource == PowerSource.Battery) { cancelReason = "电源变化"; backgroundWorker.CancelAsync(); } } else { if (PowerManager.PowerSource == PowerSource.AC || PowerManager.PowerSource == PowerSource.Ups) { SetLabelButtonStatus(IndexerStatusLabel, "点击开始寻找按钮继续开始寻找."); } } } void BatteryLifePercentChanged(object sender, EventArgs e) { settings.BatteryLifePercent = PowerManager.BatteryLifePercent; AddEventMessage(string.Format("电源电量变化了 (new value: {0})", PowerManager.BatteryLifePercent)); // 设置剩余电源电量 SetLabelButtonStatus(batteryLifePercentLabel, string.Format("{0}%", PowerManager.BatteryLifePercent.ToString())); } //事件处理程序必须使用窗口的调度 //更新用户界面直接。这是必要的,因为 //事件处理程序被调用在非UI线程。 void SystemBusyChanged(object sender, EventArgs e) { AddEventMessage(string.Format("系统忙碌变化 at {0}", DateTime.Now.ToLongTimeString())); } void AddEventMessage(string message) { this.Dispatcher.Invoke(DispatcherPriority.Normal, (Window1.MethodInvoker)delegate { ListBoxItem lbi = new ListBoxItem(); lbi.Content = message; messagesListBox.Items.Add(lbi); messagesListBox.ScrollIntoView(lbi); }); } private void StartIndexer(object sender, RoutedEventArgs e) { if (backgroundWorker.IsBusy && ((Button)sender).Content.ToString() == "停止索引") { cancelReason = "userCancelled"; backgroundWorker.CancelAsync(); SetLabelButtonStatus(IndexerStatusLabel, "点击按钮开始寻找"); return; } //如果运行在使用电池,不启动索引 if (PowerManager.PowerSource != PowerSource.Battery) { backgroundWorker.RunWorkerAsync(); SetLabelButtonStatus(IndexerStatusLabel, "索引进行中...."); SetLabelButtonStatus(StartStopIndexerButton, "停止 索引"); } else { SetLabelButtonStatus(IndexerCurrentFileLabel, "电池上运行。没有启动的索引"); } } private void RecurseDisplay(ShellObject so) { if (backgroundWorker.CancellationPending) return; SetLabelButtonStatus(IndexerCurrentFileLabel, string.Format("Current {0}: {1}", so is ShellContainer ? "文件夹" : "文件", so.ParsingName)); // 通过此对象的子项,如果它是一个对象容器 ShellContainer container = so as ShellContainer; if (container != null) { foreach (ShellObject child in container) RecurseDisplay(child); } } private void SetLabelButtonStatus(ContentControl control, string status) { this.Dispatcher.Invoke(DispatcherPriority.Normal, (Window1.MethodInvoker)delegate { control.Content = status; }); } } }

编译运行,见效果