子项在任务栏上形成组

时间:2016-05-10 08:41:16

标签: c# linux windows forms macos

我有一个应用程序,它有一个主窗口,然后它打开新的表单。 整个应用程序就像一个包含多种子表单的文档阅读器。

例如,我打开了主窗口,3个文档详细信息表单和4个其他内容的编辑器。

现在。由于所有子表单都是主表单的子表单,因此它们都被分组在任务栏上的一个图标下,当您尝试搜索悬停时显示的列表中的某个窗口时,这可能会弄得一团糟。

是否可以告诉系统,所有特定表单的实例必须在单独的图标中组合在一起?

喜欢这个

Taskbar - grouped child forms

我通过了一些指南,但不幸的是,我还没有发现这个特定的问题在任何地方都解决了。

通过我在这里寻找C#实现我的应用程序设计和解决方案的简单预览,真正的应用程序可能会在Delphi中实现,所以真正的和主要的问题是关于操作系统是否支持这种行为,因为这是对正常行为的巨大反应 - 甚至可以在Windows中这样做吗?它也可以在Linux(gnome,kde,xfce,unity)和MacOS上完成吗?对于这些问题,我不需要知道HOW-TO,只要有人遇到问题并且可以指出我提到这个问题的文章的解决方案。

提前致谢。

1 个答案:

答案 0 :(得分:1)

我无法帮助您使用其他平台,例如Linux,但这是Windows解决方案:

您可以使用Windows任务栏API。对于 C#,.NET使其以一种简洁的方式可用。您必须引用程序集System.XamlMicrosoft.WindowsAPICodePack.Shell,然后才能使用此代码:

using Microsoft.WindowsAPICodePack.Taskbar;

/* ... */

// Put this code in myForm.OnLoad or so
TaskbarManager.Instance.SetApplicationIdForSpecificWindow(myForm.Handle, "MyInternalGroupID");

这将为您的窗口分配“应用程序模型ID”。 Windows将所有具有相同应用程序型号ID的窗口组合在一起。因此,您必须为不同的组使用不同的名称而不是MyInternalGroupID

请注意,这也可以在多个实例中 ,因此属于同一组的窗口即使来自多个进程也会一起显示。如果您不想这样,则必须在组名中包含当前进程ID。

进一步阅读:Taskbar API overviewThe Old New Thing article (with C++ example)

对于 Delphi ,我找到了一个解决方案here,归功于BjörnOle

unit uAppID;

interface

uses
  Windows,
  ActiveX,
  PropSys,
  PropKey;

function GetAppID(AHandle: THandle): string;
function SetAppID(AHandle: THandle; const AAppID: string): boolean;

implementation

function SHGetPropertyStoreForWindow(hwnd: hwnd; const riid: TGUID; out ppv: IPropertyStore)
  : HRESULT; stdcall; external 'shell32.dll';

function GetAppID(AHandle: THandle): string;
var
  hr: HRESULT;
  pps: IPropertyStore;
  v: TPropVariant;
begin
  hr := SHGetPropertyStoreForWindow(AHandle, IID_IPropertyStore, pps);
  if Succeeded(hr) then
  begin
    pps.GetValue(PKEY_AppUserModel_ID, v);
    result := v.bstrVal;
  end
  else
    result := '';
end;

function SetAppID(AHandle: THandle; const AAppID: string): boolean;
var
  hr: HRESULT;
  pps: IPropertyStore;
  v: TPropVariant;
begin
  hr := SHGetPropertyStoreForWindow(AHandle, IID_IPropertyStore, pps);
  if Succeeded(hr) then
  begin
    v.vt := VT_BSTR;
    v.bstrVal := SysAllocString(PChar(AAppID));
    result := pps.SetValue(PKEY_AppUserModel_ID, v) = S_OK;
  end
  else
    result := false;
end;

end.

您需要以C#中SetAppID的方式呼叫TaskbarManager.Instance.SetApplicationIdForSpecificWindow,基本上。