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

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

  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 правильным для моего приложения?

Ответы [ 4 ]

8 голосов
/ 26 октября 2011

Вы имеете в виду так же, как работает Visual Studio?

Если это так, то вы не можете сделать это в обычном приложении Windows - читы Visual Studio.

Проблема в том, что приложение Windows может быть либо приложением Windows Forms, либо консольным приложением, но не может быть и тем и другим - это решается во время компиляции (для приложений .Net это находится в окне свойств проекта). Ваши варианты:

Сделайте ваше приложение приложением 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 использует два отдельных приложения: одно - консольное, а другое - приложение Windows Forms. Простое решение - оставить все как есть и потребовать, чтобы пользователи запускали другой исполняемый файл при запуске версии командной строки (например, myprogram_g.exe и myprogram_w.exe).

Однако Visual Studio идет на шаг дальше и имеет единственную точку входа, devenv. Это достигается за счет того факта, что по соображениям совместимости оболочка Windows всегда будет запускать файл .com вместо .exe, если есть какая-либо неопределенность. Если все ярлыки и т. Д. Указывают на исполняемый файл, если вы запустите devenv в командной строке, вместо этого будет запущено приложение devenv.com, которое использует магию, чтобы выяснить, работает ли оно как консольное приложение или приложение Windows.

Мой совет - создать два разных приложения и оставить все как есть.

См. Как написать программу, которая может быть запущена в виде консоли или приложения с графическим интерфейсом? для получения более подробной информации (обязательно прочитайте комментарии, в которых содержатся дополнительные полезные предложения).

Также см. Как сделать приложение как графическим, так и консольным приложением? о том, как ildasm делает это.

3 голосов
/ 26 октября 2011

Вы можете вызвать Application.Run () без экземпляра формы.

Таким образом, он запустит цикл сообщений, не открывая форму.

Вы можете вызвать MessageBox.Show () перед вызовом .Run () тоже.

Вы даже можете создавать и открывать форму, а затем вызывать Run () без указания аргумента - это просто означает, что закрытие формы не приводит к автоматическому выходу из приложения.

1009 * Е.Г. *

        MessageBox.Show("Messaage!");

        Form1 f = new Form1();
        f.Show();

        Application.Run();

Как указано выше, этот способ выполнения Run () означает, что закрытие форм не приводит к автоматическому закрытию приложения. Вы должны обработать это в обработчике события Close формы. (Application.Exit ())

MSDN онлайн может помочь вам в этом - проверьте запись справки для Application.Run ().

2 голосов
/ 26 октября 2011

Я нашел изящное и простое в реализации решение, используя пример из моего вопроса, предоставленного Microsoft.

Я создал этот класс контекста приложения, который отвечает за все в приложении, и я использую его вместо формыв Application.Run(), как показано ниже.Чтобы добиться поведения в вопросе, я использую вторую форму, которая скрыта, и отображается только значок панели задач.Если пользователь хочет увидеть, как идет процесс, он может щелкнуть значок на панели задач и увидеть окно ведения журнала, которое на самом деле ConfigurationApplierForm в приведенном ниже примере.

class AnApplicationContext: ApplicationContext
{
private Form _currentForm;

Обратите внимание, что конструктор является приватным, main находится внутри этого класса и объявлен как static.

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
1 голос
/ 26 октября 2011

Обычно вам нужно консольное приложение с несколькими изменениями.

Вот пример того, как начать работу, используя класс 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();
        }
    }
}
...