Windows7进度条在 C # 的任务栏?

如果你已经注意到在 Windows 7 beta 中,如果你复制文件或者其他系统操作,任务栏中的文件资源管理器图标将会填充一个绿色的进度条,相当于表单中的进度条。有没有办法,在我的 C # 形式,我可以强制我的任务栏进度条匹配的进度,无论我正在做什么任务?转换、传输、生成,这个进度条有很多用途。

34254 次浏览

Yes, Microsoft covered the new taskbar functions in the following document (sources included): Windows 7 taskbar: Developer Resources

For people who want to skip reading the documentation and just get something that works...

  • Download the Windows API Code Pack for Microsoft .Net Framework.
  • Run the installer which creates a zip file
  • Extract the following dlls from the binaries folder of the zip file:
    • Microsoft.WindowsAPICodePack.dll
    • Microsoft.WindowsAPICodePack.Shell.dll
  • Add a reference to them in your project
  • Put the following code into your app and modify as necessary:

--

  int max = 100;
var prog = Microsoft.WindowsAPICodePack.Taskbar.TaskbarManager.Instance;
prog.SetProgressState(Microsoft.WindowsAPICodePack.Taskbar.TaskbarProgressBarState.Normal);
for(int i=0;i<max;i++) {
prog.SetProgressValue(i, max);
Thread.Sleep(100);
}
prog.SetProgressState(Microsoft.WindowsAPICodePack.Taskbar.TaskbarProgressBarState.NoProgress);

I found a beautiful article (Link) that provides a simple solution to the taskbar progress bar problem. In summary, it instructs you to download the Windows API pack from the MSDN website, adding a reference to the Microsoft.WindowsAPICodePack.Shell.dll that it contains, and finally add three lines of code to your application:

Imports Microsoft.WindowsAPICodePack
Imports Microsoft.WindowsAPICodePack.Taskbar
// ...
TaskbarManager.Instance.SetProgressValue(X, 100)

where X is the progress you want to display.

I just wanted to add some taskbar progress animation to my WinForms application, without having to download code packs or switch to WPF to use TaskbarItemInfo.

The solution was a class that uses the ITaskbarList3 interface:

using System;
using System.Runtime.InteropServices;


public static class TaskbarProgress
{
public enum TaskbarStates
{
NoProgress    = 0,
Indeterminate = 0x1,
Normal        = 0x2,
Error         = 0x4,
Paused        = 0x8
}


[ComImport()]
[Guid("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface ITaskbarList3
{
// ITaskbarList
[PreserveSig]
void HrInit();
[PreserveSig]
void AddTab(IntPtr hwnd);
[PreserveSig]
void DeleteTab(IntPtr hwnd);
[PreserveSig]
void ActivateTab(IntPtr hwnd);
[PreserveSig]
void SetActiveAlt(IntPtr hwnd);


// ITaskbarList2
[PreserveSig]
void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);


// ITaskbarList3
[PreserveSig]
void SetProgressValue(IntPtr hwnd, UInt64 ullCompleted, UInt64 ullTotal);
[PreserveSig]
void SetProgressState(IntPtr hwnd, TaskbarStates state);
}


[ComImport()]
[Guid("56fdf344-fd6d-11d0-958a-006097c9a090")]
[ClassInterface(ClassInterfaceType.None)]
private class TaskbarInstance
{
}


private static ITaskbarList3 taskbarInstance = (ITaskbarList3)new TaskbarInstance();
private static bool taskbarSupported = Environment.OSVersion.Version >= new Version(6, 1);


public static void SetState(IntPtr windowHandle, TaskbarStates taskbarState)
{
if (taskbarSupported) taskbarInstance.SetProgressState(windowHandle, taskbarState);
}


public static void SetValue(IntPtr windowHandle, double progressValue, double progressMax)
{
if (taskbarSupported) taskbarInstance.SetProgressValue(windowHandle, (ulong)progressValue, (ulong)progressMax);
}
}

Example of how easy it is to use:

TaskbarProgress.SetState(this.Handle, TaskbarProgress.TaskbarStates.Indeterminate);


or


TaskbarProgress.SetValue(this.Handle, 50, 100);
TaskbarProgress.SetState(this.Handle, TaskbarProgress.TaskbarStates.Error);

Tested with Windows 10.0.19044

Easily add taskbar progress to the taskbar icon of an existing form. No NuGet package, no complex coding... just copy/paste.

The only code you need to add to your form, are calls to the new form properties which update the icon. (Why junk up your form with API calls, procs, and an enum... when it can be avoided?)

Put the following code into a new class module in your project.

using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;


namespace System.Windows.Forms
{
[ToolboxBitmap(typeof(Form))]
public class ProgressForm : Form
{
private ThumbnailProgressState m_State = ThumbnailProgressState.NoProgress;
private int m_Maximum = 100;
private int m_Value = 0;


//
// Summary:
//     Gets or sets the state in which progress should be indicated on the task
//     bar.
//
// Returns:
//     One of the System.Windows.Forms.ThumbnailProgressState values. The default is System.Windows.Forms.ThumbnailProgressState.NoProgress
//
// Exceptions:
//   T:System.ComponentModel.InvalidEnumArgumentException:
//     The value is not a member of the System.Windows.Forms.ThumbnailProgressState enumeration.
//
// History:
//   An old Microsoft article
//   July 2022 - Verified with Win10, reworded/reformatted ThumbnailProgressState.
//   Argument exception of property Value is more granular.
//   Windows7orGreater - no longer relevant, but unchanged in case there is a need to distinguish versions beyond Windows 10
//
// Usage:
//   Add class with this code to your project
//   Add the inheritance "ProgressForm" to the form that will show progress.
//   Example: public partial class Form1 : ProgressForm
//
[Browsable(true)]
[DefaultValue(ThumbnailProgressState.NoProgress)]
[EditorBrowsable(EditorBrowsableState.Always)]
public ThumbnailProgressState State
{
get { return m_State; }
set
{
switch (value)
{
case ThumbnailProgressState.NoProgress:
case ThumbnailProgressState.Indeterminate:
case ThumbnailProgressState.Normal:
case ThumbnailProgressState.Error:
case ThumbnailProgressState.Paused:
m_State = value;
OnStateChanged(new EventArgs());
break;
default:
throw new InvalidEnumArgumentException("The value is not a member of the System.Windows.Forms.ThumbnailProgressState enumeration.");
}
}
}


//
// Summary:
//     Gets or sets the current position of the progress bar.
//
// Returns:
//     The position within the range of the progress bar. The default is 0.
//
// Exceptions:
//   T:System.ArgumentException:
//   • The value specified is greater than the value of the System.Windows.Forms.ProgressForm.Maximum property.
//   • The value specified is less than 0.
[Browsable(true)]
[DefaultValue(0)]
[EditorBrowsable(EditorBrowsableState.Always)]
public int Value
{
get { return m_Value; }
set
{
if (value > m_Maximum)
{
throw new ArgumentException("The value specified is greater than the value of the System.Windows.Forms.ProgressForm.Maximum property.");
}
else if(value < 0)
{
throw new ArgumentException("The value specified is less than 0.");
}
else
{
m_Value = value;
OnValueChanged(new EventArgs());
}
}
}


//
// Summary:
//     Gets or sets the maximum value of the range of the control.
//
// Returns:
//     The maximum value of the range. The default is 100.
//
// Exceptions:
//   T:System.ArgumentException:
//     The value specified is less than 0.
[Browsable(true)]
[DefaultValue(100)]
[EditorBrowsable(EditorBrowsableState.Always)]
public int Maximum
{
get { return m_Maximum; }
set
{
if (value < 0)
{
throw new ArgumentException("The value specified is less than 0.");
}
else
{
m_Maximum = value;
if (value < m_Value) m_Value = value;
OnMaximumChanged(new EventArgs());
}
}
}


protected virtual void OnStateChanged(EventArgs e)
{
if (Windows7orGreater) SetProgressState();
}


protected virtual void OnValueChanged(EventArgs e)
{
if (Windows7orGreater) SetProgressValue();
}


protected virtual void OnMaximumChanged(EventArgs e)
{
if (Windows7orGreater) SetProgressValue();
}


protected override void WndProc(ref Message m)
{
if (Windows7orGreater)
{
// if taskbar button created or recreated, update progress status
if (m.Msg == WM_TaskbarButtonCreated) SetProgressState();
}
base.WndProc(ref m);
}


private void SetProgressState()
{
// must be Windows7orGreater
TaskbarList.SetProgressState(Handle, m_State);
SetProgressValue();
}
private void SetProgressValue()
{


switch (m_State)
{
case ThumbnailProgressState.Normal:
case ThumbnailProgressState.Error:
case ThumbnailProgressState.Paused:
TaskbarList.SetProgressValue(Handle, (ulong)m_Value, (ulong)m_Maximum);
break;
}
}


private static int WM_TaskbarButtonCreated = -1;
private static int _winVersion = -1;
internal static bool Windows7orGreater
{
get
{
if (_winVersion < 0)
{
Version osVersion = Environment.OSVersion.Version;
if ((osVersion.Major == 6 && osVersion.Minor > 0) || (osVersion.Major > 6))
{
// Taskbar progress indicator requires Windows 7 Or Greater
_winVersion = 1;


// register taskbar creation window message
WM_TaskbarButtonCreated = RegisterWindowMessage(@"TaskbarButtonCreated");
}
else
{
_winVersion = 0;
}
}
return (_winVersion > 0);
}
}


private static ITaskbarList3 _taskbarList = null;
internal static ITaskbarList3 TaskbarList
{
get
{
if (_taskbarList == null)
{
lock (typeof(ProgressForm))
{
if (_taskbarList == null)
{
_taskbarList = (ITaskbarList3)new CTaskbarList();
_taskbarList.HrInit();
}
}
}
return _taskbarList;
}
}


[DllImport("user32.dll")]
internal static extern int RegisterWindowMessage(string message);


[ComImportAttribute()]
[GuidAttribute("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
internal interface ITaskbarList3
{
// ITaskbarList
[PreserveSig]
void HrInit();
[PreserveSig]
void AddTab(IntPtr hwnd);
[PreserveSig]
void DeleteTab(IntPtr hwnd);
[PreserveSig]
void ActivateTab(IntPtr hwnd);
[PreserveSig]
void SetActiveAlt(IntPtr hwnd);


// ITaskbarList2
[PreserveSig]
void MarkFullscreenWindow(
IntPtr hwnd,
[MarshalAs(UnmanagedType.Bool)] bool fFullscreen);


// ITaskbarList3
void SetProgressValue(IntPtr hwnd, UInt64 ullCompleted, UInt64 ullTotal);
void SetProgressState(IntPtr hwnd, ThumbnailProgressState tbpFlags);
}


[GuidAttribute("56FDF344-FD6D-11d0-958A-006097C9A090")]
[ClassInterfaceAttribute(ClassInterfaceType.None)]
[ComImportAttribute()]
internal class CTaskbarList { }
}


public enum ThumbnailProgressState
{
/// <summary>
/// No progress is displayed.<br>
/// yourFormName.Value is ignored.</br> </summary>
NoProgress = 0,
/// <summary>
/// Normal progress is displayed.<br>
/// The bar is GREEN.</br> </summary>
Normal = 0x2,
/// <summary>
/// The operation is paused.<br>
/// The bar is YELLOW.</br></summary>
Paused = 0x8,
/// <summary>
/// An error occurred.<br>
/// The bar is RED.</br> </summary>
Error = 0x4,
/// <summary>
/// The progress is indeterminate.<br>
/// Marquee style bar (constant scroll).</br> </summary>
Indeterminate = 0x1
}
}

Add ProgressForm to the form which needs the ability to show progress:

public partial class Form1 : ProgressForm

Add this sample code to your form and step through it to watch it work:

    if (this.State == ThumbnailProgressState.NoProgress)
{
// Show the progress with GREEN
this.State = ThumbnailProgressState.Normal;
}
this.Maximum = 512; // set to any integer above zero (defaults to 100)
this.Value = 0;     // Visually equivalent to this.State = ThumbnailProgressState.NoProgress;
this.Value = 256;   // 50% solid GREEN overlay
this.State = ThumbnailProgressState.Error;  // Still 50% but now solid RED overlay
this.State = ThumbnailProgressState.Paused; // Still 50% but now solid YELLOW overlay
this.Value = 384;   // 75% YELLOW overlay (384 / 512 == 75%)
this.Value = this.Maximum;  // 100% YELLOW overlay (512 of 512)
this.State = ThumbnailProgressState.Indeterminate;  // Marquee. (Ignores Value and constantly scrolls with a fade)
this.State = ThumbnailProgressState.NoProgress;     // Ignores Value, there is no overlay