Как мне обрабатывать аргументы командной строки в Winforms, если я не хочу загружать основную форму?

#c# #winforms #command-line-arguments

#c# #winforms — формы #аргументы командной строки

Вопрос:

Я хочу создать приложение, которое ведет себя следующим образом:

  1. При отсутствии аргумента отображается основная форма
  2. При аргументе «a» выполняется задание, но основная форма не загружается.
  3. При аргументе «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