为所有我的表单设置相同的图标

38

有没有办法在不必一个一个更改的情况下为所有表单设置相同的图标?就像在解决方案中为所有项目设置GlobalAssemblyInfo一样。


我曾经遇到这个问题,但是我找到了答案。使用资源(全局或本地)的完整解释 - Mehdi
8个回答

61
  1. 在项目属性>应用程序>图标和清单中,浏览一个*.ico文件并添加到那里。

  2. 在窗体的构造函数或_Load事件中,只需添加:

  3. this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
    

4
请不要忘记使用命名空间System.Drawing,否则可能会遇到问题。例如:Icon = System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath); - Vikram Singh Saini
很棒的答案,正是我所需。 - Sirop4ik

26
一种选择是从共同的基本表单(base-Form)继承,该表单在构造函数中设置图标(可能来自resx)。另一种选择可能是使用PostSharp - 似乎可以通过AOP来设置.Icon;尽管并不容易。最后,您可以使用一个简单的实用程序方法(可能是扩展方法)来完成相同的操作。
最好的是,使用第一种选项,您可能会冒险将Ctrl+H(替换所有)从: Form: System.Windows.Forms.Form替换为: MyCustomForm

我认为选项#1(从具有构造函数的公共表单派生)在这里是明显的赢家。 - John Rudy
我仍然无法相信继承从未出现在我的脑海中..感谢您快速(真的很快)的回答!!! - Tute
1
很遗憾,VS2012似乎容易通过将默认图标添加到继承窗体的资源中来“重置”图标。当这种情况发生时,请打开设计器视图并选择窗体,在Icon属性的值字段中放置光标,然后按[Delete]键即可。 - Nyerguds
1
@Nyerguds 谢谢!我一直在苦苦思索为什么继承不起作用... - foamy

10

除了Marc的建议外,您可能希望表单自动继承包含/调用它们的执行程序的图标。
这可以通过向继承的表单添加以下代码来完成:

public MyCustomForm()
{
    Icon = GetExecutableIcon();
}

public Icon GetExecutableIcon()
{
    IntPtr large;
    IntPtr small;
    ExtractIconEx(Application.ExecutablePath, 0, out large, out small, 1);
    return Icon.FromHandle(small);
}

[DllImport("Shell32")]
public static extern int ExtractIconEx(
    string sFile,
    int iIndex,
    out IntPtr piLargeVersion,
    out IntPtr piSmallVersion,
    int amountIcons);

7

这是一种将相同图标设置到所有窗体上而不需要一个一个改变的方法。这是我在我的应用程序中编写的代码。

FormUtils.SetDefaultIcon();

这里有一个完整的示例可供使用。

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        //Here it is.
        FormUtils.SetDefaultIcon();

        Application.Run(new Form());
    }
}

这里是FormUtils类:

using System.Drawing;
using System.Windows.Forms;

public static class FormUtils
{
    public static void SetDefaultIcon()
    {
        var icon = Icon.ExtractAssociatedIcon(EntryAssemblyInfo.ExecutablePath);
        typeof(Form)
            .GetField("defaultIcon", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
            .SetValue(null, icon);
    }
}

这里介绍一个名为 EntryAssemblyInfo 的类。由于篇幅所限,本示例对其进行了截断。这是我根据 System.Winforms.Application 编写的自定义类。

using System.Security;
using System.Security.Permissions;
using System.Reflection;
using System.Diagnostics;

public static class EntryAssemblyInfo
{
    private static string _executablePath;

    public static string ExecutablePath
    {
        get
        {
            if (_executablePath == null)
            {
                PermissionSet permissionSets = new PermissionSet(PermissionState.None);
                permissionSets.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
                permissionSets.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
                permissionSets.Assert();

                string uriString = null;
                var entryAssembly = Assembly.GetEntryAssembly();

                if (entryAssembly == null)
                    uriString = Process.GetCurrentProcess().MainModule.FileName;
                else
                    uriString = entryAssembly.CodeBase;

                PermissionSet.RevertAssert();

                if (string.IsNullOrWhiteSpace(uriString))
                    throw new Exception("Can not Get EntryAssembly or Process MainModule FileName");
                else
                {
                    var uri = new Uri(uriString);
                    if (uri.IsFile)
                        _executablePath = string.Concat(uri.LocalPath, Uri.UnescapeDataString(uri.Fragment));
                    else
                        _executablePath = uri.ToString();
                }
            }

            return _executablePath;
        }
    }
}

2

我不确定是否要在这里使用继承,因此我使用了扩展方法:

public static class MyExtensionMethods
{
    public static void SetAppIcon(this Form form)
    {
        form.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
    }
}

然后在任何形式的构造函数中:

this.SetAppIcon();

注意:如果您尝试从网络位置运行应用程序,这将导致崩溃。

1

除了在构造函数中设置之外,另一种方法是重写Owner属性,并获取所有者窗体的图标。

public new Form Owner {
    set {
        this.Icon = (value == null ? null : value.Icon);
        base.Owner = value;
    }

    get {
        return base.Owner;
    }
}

1
这是一个老问题,但是我通过这种方法在不必在每个窗体的属性中添加它的情况下,在所有窗体中获得相同的图标。
首先,在“属性”下的“资源”节点中添加了一个新图标(添加资源=>新建图标)。
默认情况下,会创建并存储某个图标在您的资源位置(在图标上查找“文件名”属性)。
假设您已经准备好了一个.ico文件,您可以将其复制到该文件夹中。
删除Visual Studio在该文件夹中创建的那个图标,并将您自己的图标重命名为完全相同的名称。
Visual Studio将提示您是否重新加载资源,因为它已被修改。(单击“是”)
这样,资源就可在“资源”下使用了。
现在,我已经编写了一个通用方法来更改表单标题为默认值并设置表单图标,并在每个表单中的InitializeComponent()之后调用它。
在表单.cs文件中如何看待它(m是保存通用方法的类):
m.set_form_defaults(this, "Title here");

而这就是方法本身:

    public void set_form_defaults(Form frm,string frmTitle)
    {

        frm.Icon = ((System.Drawing.Icon)(Properties.Resources.Logo_V2));
        frm.Text = frmTitle + " " + show_current_server();

    }

当然,您不需要在此处添加表单标题,但这仅是因为我想向用户显示一些存储的属性(当前服务器)。

-1

我不确定 MS VS 设计器是否能够处理不直接从 Form 派生的窗体。如果不能,则您可以尝试将主窗体的图标复制到所有其他窗体中: 对于 Forms 集合中的每个窗体

form.icon = MainFrom.Icon

或者在每个窗体的_Loaded事件中:

Icon = MainFrom.Icon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接