Here are some relevant sections of the code from Ian's sample app.  I've added the interop definitions to PInvoke.net for easy reference.

  void Window1_Loaded(object sender, RoutedEventArgs e)
        {
            source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
            source.AddHook(new HwndSourceHook(WndProc));
            RegisterForPowerNotifications(source.Handle);
        }
  protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            UnregisterForPowerNotifications();
        }

private IntPtr hBattCapacity;
        private IntPtr hMonitorOn;
        private IntPtr hPowerScheme;
        private IntPtr hPowerSrc;

        private void RegisterForPowerNotifications(IntPtr hwnd)
        {
            hPowerSrc = RegisterPowerSettingNotification(hwnd,
            ref GUID_ACDC_POWER_SOURCE,
            DEVICE_NOTIFY_WINDOW_HANDLE);

            hBattCapacity = RegisterPowerSettingNotification(hwnd,
            ref GUID_BATTERY_PERCENTAGE_REMAINING,
            DEVICE_NOTIFY_WINDOW_HANDLE);

            hMonitorOn = RegisterPowerSettingNotification(hwnd,
            ref GUID_MONITOR_POWER_ON,
            DEVICE_NOTIFY_WINDOW_HANDLE);

            hPowerScheme = RegisterPowerSettingNotification(hwnd,
            ref GUID_POWERSCHEME_PERSONALITY,
            DEVICE_NOTIFY_WINDOW_HANDLE);
        }

        private void UnregisterForPowerNotifications()
        {
            UnregisterPowerSettingNotification(hBattCapacity);
            UnregisterPowerSettingNotification(hMonitorOn);
            UnregisterPowerSettingNotification(hPowerScheme);
            UnregisterPowerSettingNotification(hPowerSrc);
        }

        static bool onBattery;
        enum PowerPersonality { Savings, Performance, Mixed };
        static PowerPersonality personality;
        private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_POWERBROADCAST && wParam.ToInt32() == PBT_POWERSETTINGCHANGE)
            {
                // Extract data from message
                POWERBROADCAST_SETTING ps =
                 (POWERBROADCAST_SETTING)Marshal.PtrToStructure(
                     lParam, typeof(POWERBROADCAST_SETTING));
                IntPtr pData = (IntPtr)(lParam.ToInt32() + Marshal.SizeOf(ps));


                // Examine notification

                if (ps.PowerSetting == GUID_POWERSCHEME_PERSONALITY &&
                    ps.DataLength == Marshal.SizeOf(typeof(Guid)))
                {
                    // New power scheme selected.

                    Guid newPersonality =
                        (Guid)Marshal.PtrToStructure(pData, typeof(Guid));

                    if (newPersonality == GUID_MAX_POWER_SAVINGS)
                    {
                        personality = PowerPersonality.Savings;
                    }
                    else if (newPersonality == GUID_MIN_POWER_SAVINGS)
                    {
                        personality = PowerPersonality.Performance;
                    }
                    else if (newPersonality == GUID_TYPICAL_POWER_SAVINGS)
                    {
                        personality = PowerPersonality.Mixed;
                    }
                    else
                    {
                        Debug.WriteLine("switched to unknown Power savings");
                        personality = PowerPersonality.Mixed;
                    }
                }
                else if (ps.PowerSetting == GUID_ACDC_POWER_SOURCE &&
                         ps.DataLength == Marshal.SizeOf(typeof(Int32)))
                {
                    Int32 iData = (Int32)Marshal.PtrToStructure(pData, typeof(Int32));
                    Debug.WriteLine("ACDC: " + iData);

                    onBattery = iData != 0;
                }


                // Select the best resources for the current
                // power state.

                if (personality == PowerPersonality.Performance
                    || (personality == PowerPersonality.Mixed && !onBattery))
                {
                    Application.Current.Resources = fullPowerResources;
                }
                else
                {
                    Application.Current.Resources = lowPowerResources;
                }

            }
           
            return IntPtr.Zero;
        }