#c# #winforms #command-line-arguments
#c# #winforms — формы #аргументы командной строки
Вопрос:
Я хочу создать приложение, которое ведет себя следующим образом:
- При отсутствии аргумента отображается основная форма
- При аргументе «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 правильным для моего приложения?
Ответ №1:
Вы имеете в виду то же самое, что работает в Visual Studio?
Если это так, то вы не можете сделать это в обычном приложении Windows — Visual Studio cheats.
Проблема в том, что приложение Windows может быть либо приложением Windows Forms, либо консольным приложением, но оно не может быть и тем, и другим — это решается во время компиляции (для .Net applications это находится в окне свойств проекта). Ваши варианты:
Сделайте свое приложение приложением Windows Forms
В этом случае # 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 будут работать нормально, у вас всегда будет открыто окно консоли в фоновом режиме — если вы закроете окно консоли, ваше приложение завершится.
Опять же, это может быть хорошо, но лично я считаю это взломом.
Обманывать (делать то, что делает Visual Studio)
Visual Studio обманывает, имея 2 отдельных приложения: одно — консольное приложение, а другое — приложение Windows Forms. Простое решение — оставить все как есть и потребовать, чтобы пользователи запускали другой исполняемый файл при запуске версии командной строки (например myprogram_g.exe
, and myprogram_w.exe
).
Однако Visual Studio делает еще один шаг вперед и имеет единственную точку входа, devenv
. Он делает это, используя тот факт, что по соображениям совместимости оболочка Windows всегда будет запускать .com
файл вместо a .exe
, если есть какая-либо двусмысленность. Где все ярлыки и т. Д. Указывают На исполняемый файл, Если вы запустите devenv
в командной строке devenv.com
, вместо этого будет запущено приложение, которое использует magic, чтобы определить, работает ли оно как консольное или Windows-приложение.
Я бы посоветовал создать два разных приложения и оставить все как есть.
Смотрите, как мне написать программу, которую можно запускать либо как консоль, либо как приложение с графическим интерфейсом?для получения более подробной информации (обязательно прочитайте комментарии, в которых есть дополнительные полезные предложения).
Также смотрите, как создать приложение как с графическим интерфейсом, так и с консольным приложением?для как ildasm
это сделать.
Ответ №2:
Вы можете вызвать Application.Run() без экземпляра формы.
Таким образом, он запустит цикл сообщений, не открывая форму.
Вы можете вызвать MessageBox .Show() перед вызовом .Run() тоже.
Вы даже можете создать и открыть форму, а затем вызвать Run() без указания аргумента — это просто означает, что закрытие формы не приводит к автоматическому выходу из приложения.
Например.
MessageBox.Show("Messaage!");
Form1 f = new Form1();
f.Show();
Application.Run();
Как указано выше, этот способ выполнения функции Run() означает, что закрытие форм не приводит к автоматическому закрытию приложения. Вам нужно обработать это в обработчике событий закрытия формы. (Заявление.Exit())
MSDN online может помочь вам с этим — проверьте запись справки для Application.Run() .
Ответ №3:
По сути, вам нужно консольное приложение с несколькими изменениями.
Вот пример того, как начать работу, используя класс 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();
}
}
}
Ответ №4:
Я нашел аккуратное и простое в реализации решение, используя пример в моем вопросе, предоставленный Microsoft.
Я создал этот класс контекста приложения, который отвечает за все в приложении, и я использую его вместо формы, 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