如果我不想加载主窗体,我如何处理Winforms中的命令行参数?
本文关键字:Winforms 处理 参数 命令行 加载 我不想 窗体 何处理 如果 | 更新日期: 2023-09-27 18:12:39
我想创建一个应用程序,其行为如下:
- 如果没有参数,则显示主形式
- 参数"a"做了一个工作,但主表单没有加载。
- 在参数"b"时,使用传递的参数加载表单(加载该文档)
对于1和3,我可以在表单的构造函数中处理如下参数:
public ConfigurationActionManagerForm()
{
InitializeComponent();
Environment.GetCommandLineArgs();
// do stuff with that argument
}
但是这种方法不允许我应用2的行为。
在program.cs
中,我可以编辑它来处理表单甚至创建之前的参数,但是如果我不想传递表单,使用Application.Run()
的正确方法是什么?我要如何通知Program
类实例,我需要终止或显示消息,有些东西出了问题,甚至显示一个小任务栏图标,进程正在做的事情(认为它像解压缩过程)。
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ConfigurationActionManagerForm());
}
MSDN的这种方法对我的应用程序是否正确?
你的意思是和Visual Studio的工作方式一样吗?
如果是这样,那么你不能在一个普通的Windows应用程序中这样做- Visual Studio作弊。
问题是Windows应用程序可以是Windows窗体应用程序或控制台应用程序,但不能两者兼而有之——这是在编译时决定的(对于。net应用程序,这是在项目属性窗口中决定的)。你的选择是:
使您的应用程序成为Windows窗体应用程序
在这种情况下,#1和#3将完美地工作,但对于#2,您将发现无法从控制台读写(因为没有控制台!)。如果您的应用程序不需要提供任何反馈,那么这可能是好的-做你的工作,你通常会,只是不显示一个表单:
[STAThread]
static void Main(string[] args)
{
if (args.Length > 0)
{
// Handle #2 here
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ConfigurationActionManagerForm());
}
}
使您的应用程序成为控制台应用程序
在这种情况下,#2将完美地工作,然而,尽管#1和#3将工作得很好,您将始终在后台打开控制台窗口-如果您关闭控制台窗口,您的应用程序将结束。
再一次,这可能是好的,但我个人认为这是一个hack。
Cheat (do what Visual Studio Does)
Visual Studio有两个独立的应用程序——一个是控制台应用程序,另一个是Windows窗体应用程序。一个简单的解决方案是让它留在那里,并要求用户在运行命令行版本时启动一个不同的可执行文件(例如myprogram_g.exe
和myprogram_w.exe
)。
Visual Studio更进一步,只有一个入口点,devenv
。由于兼容性原因,如果存在任何歧义,Windows shell将始终运行.com
文件而不是.exe
,这是通过使用这一事实来实现的。而所有的捷径等等。指向可执行文件,如果你在命令行上运行devenv
, devenv.com
应用程序将运行,它使用魔法来区分它是作为控制台还是windows应用程序运行。
我的建议是创建两个不同的应用程序,就这样吧。
参见如何编写一个既可以作为控制台又可以作为GUI应用程序运行的程序?要了解更多细节(请务必阅读有额外有用建议的评论)。
请参阅如何使应用程序同时作为GUI和控制台应用程序?ildasm
是如何做到这一点的。
不需要表单实例就可以调用Application.Run()
这样,它将在不打开表单的情况下启动消息循环。
您也可以在调用。run()之前调用MessageBox.Show()。
你甚至可以创建并打开一个表单,然后调用Run()而不指定参数——这只是意味着关闭表单不会自动退出应用程序。
。
MessageBox.Show("Messaage!");
Form1 f = new Form1();
f.Show();
Application.Run();
如上所述,这种运行Run()的方式意味着关闭表单不会自动关闭应用程序。您需要在表单的Close事件处理程序中处理这个问题。(Application.Exit ())
MSDN online可以帮助您解决这个问题-检查Application.Run()的帮助条目。
基本上你想要一个控制台应用程序做一些改变。
下面是一个如何开始的例子,使用一个默认的aboutbox类:
using System;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("No Arguments");
}
else
{
if (args[0] == "a")
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new AboutBox1());
}
}
}
}
}
和AboutBox1类:
using System.Reflection;
using System.Windows.Forms;
namespace ConsoleApplication1
{
partial class AboutBox1 : Form
{
public AboutBox1()
{
InitializeComponent();
this.Text = String.Format("About {0} {0}", AssemblyTitle);
this.labelProductName.Text = AssemblyProduct;
this.labelVersion.Text = String.Format("Version {0} {0}", AssemblyVersion);
this.labelCopyright.Text = AssemblyCopyright;
this.labelCompanyName.Text = AssemblyCompany;
this.textBoxDescription.Text = AssemblyDescription;
}
#region Assembly Attribute Accessors
public string AssemblyTitle
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
if (attributes.Length > 0)
{
AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0];
if (titleAttribute.Title != "")
{
return titleAttribute.Title;
}
}
return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
}
}
public string AssemblyVersion
{
get
{
return Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
}
public string AssemblyDescription
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyDescriptionAttribute)attributes[0]).Description;
}
}
public string AssemblyProduct
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyProductAttribute)attributes[0]).Product;
}
}
public string AssemblyCopyright
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCopyrightAttribute)attributes[0]).Copyright;
}
}
public string AssemblyCompany
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCompanyAttribute)attributes[0]).Company;
}
}
#endregion
private void okButton_Click(object sender, EventArgs e)
{
Close();
}
}
}
我找到了一个简洁的解决方案,使用微软提供的问题示例。
我创建了这个应用程序上下文类,它负责应用程序中的所有内容,我使用它而不是Application.Run()
中的表单,如下所示。为了实现问题中的行为,我使用隐藏的第二个表单,并且只显示任务栏图标。如果用户想看看进程是怎么做的,他们可以点击任务栏图标,看到日志窗口,这实际上是ConfigurationApplierForm
在下面的例子中。
class AnApplicationContext: ApplicationContext
{
private Form _currentForm;
注意构造函数是私有的,main在这个类中并且声明为静态。
private AnApplicationContext()
{
Application.ApplicationExit += new EventHandler(this.OnApplicationExit);
// choose which form to show based on arguments
if(Environment.GetCommandLineArgs().Contains("-apply"))
{
_currentForm = new ConfigurationApplierForm();
}
else
{
_currentForm = new ConfigurationActionManagerForm();
}
// initialize the form and attach event handlers
_currentForm.FormClosed += new FormClosedEventHandler(this.OnCurrentFormClosed);
_currentForm.ShowDialog();
}
Main在这里,和原来的有一点不同。注意Run
方法
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// context is passed instead of a form
Application.Run(new AnApplicationContext());
}
private void OnCurrentFormClosed(object sender, EventArgs e)
{
ExitThread();
}
private void OnApplicationExit(object sender, EventArgs e)
{
/* is there anything to do when all forms are closed
and the application is going to die?*/
}
}
同时,我们需要告诉项目这是启动项目。
Project Properties -> Application -> Startup Project