C# (WinForms-App) экспорт DataSet в Excel

Мне нужно решение для экспорта набора данных в файл Excel без какого-либо кода asp (HttpResonpsne ...), но я не нашел хорошего примера для этого ...

Лучшее спасибо заранее

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
24
0
71 809
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Ответ принят как подходящий

Я создал класс, который экспортирует DataGridView или DataTable в файл Excel. Вы, вероятно, можете немного изменить его, чтобы вместо этого он использовал ваш DataSet (итерация через DataTables в нем). Он также выполняет базовое форматирование, которое вы также можете расширить.

Чтобы использовать его, просто вызовите ExcelExport и укажите имя файла и следует ли открывать файл автоматически после экспорта. Я также мог бы сделать их методами расширения, но я этого не сделал. Не стесняйся.

Обратите внимание, что файлы Excel могут быть сохранены как прославленный документ XML, и это использует это.

Обновлено: раньше использовался ванильный StreamWriter, но, как уже указывалось, во многих случаях экранирование происходило некорректно. Теперь он использует XmlWriter, который сделает экранирование за вас.

Класс ExcelWriter является оболочкой для XmlWriter. Я не стал беспокоиться, но вы, возможно, захотите выполнить дополнительную проверку ошибок, чтобы убедиться, что вы не можете записать данные ячеек перед запуском строки и т. д. Код ниже.

public class ExcelWriter : IDisposable
{
    private XmlWriter _writer;

    public enum CellStyle { General, Number, Currency, DateTime, ShortDate };

    public void WriteStartDocument()
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteProcessingInstruction("mso-application", "progid=\"Excel.Sheet\"");
        _writer.WriteStartElement("ss", "Workbook", "urn:schemas-microsoft-com:office:spreadsheet");
         WriteExcelStyles();
   }

    public void WriteEndDocument()
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteEndElement();
    }

    private void WriteExcelStyleElement(CellStyle style)
    {
        _writer.WriteStartElement("Style", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteAttributeString("ID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
        _writer.WriteEndElement();
    }

    private void WriteExcelStyleElement(CellStyle style, string NumberFormat)
    {
        _writer.WriteStartElement("Style", "urn:schemas-microsoft-com:office:spreadsheet");

        _writer.WriteAttributeString("ID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
        _writer.WriteStartElement("NumberFormat", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteAttributeString("Format", "urn:schemas-microsoft-com:office:spreadsheet", NumberFormat);
        _writer.WriteEndElement();

        _writer.WriteEndElement();

    }

    private void WriteExcelStyles()
    {
        _writer.WriteStartElement("Styles", "urn:schemas-microsoft-com:office:spreadsheet");

        WriteExcelStyleElement(CellStyle.General);
        WriteExcelStyleElement(CellStyle.Number, "General Number");
        WriteExcelStyleElement(CellStyle.DateTime, "General Date");
        WriteExcelStyleElement(CellStyle.Currency, "Currency");
        WriteExcelStyleElement(CellStyle.ShortDate, "Short Date");

        _writer.WriteEndElement();
    }

    public void WriteStartWorksheet(string name)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteStartElement("Worksheet", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteAttributeString("Name", "urn:schemas-microsoft-com:office:spreadsheet", name);
        _writer.WriteStartElement("Table", "urn:schemas-microsoft-com:office:spreadsheet");
    }

    public void WriteEndWorksheet()
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteEndElement();
        _writer.WriteEndElement();
    }

    public ExcelWriter(string outputFileName)
    {
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        _writer = XmlWriter.Create(outputFileName, settings);
    }

    public void Close()
    {
        if (_writer == null) throw new InvalidOperationException("Already closed.");

        _writer.Close();
        _writer = null;
    }

    public void WriteExcelColumnDefinition(int columnWidth)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteStartElement("Column", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteStartAttribute("Width", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteValue(columnWidth);
        _writer.WriteEndAttribute();
        _writer.WriteEndElement();
    }

    public void WriteExcelUnstyledCell(string value)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteStartElement("Cell", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteStartElement("Data", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "String");
        _writer.WriteValue(value);
        _writer.WriteEndElement();
        _writer.WriteEndElement();
    }

    public void WriteStartRow()
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteStartElement("Row", "urn:schemas-microsoft-com:office:spreadsheet");
    }

    public void WriteEndRow()
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteEndElement();
    }

    public void WriteExcelStyledCell(object value, CellStyle style)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        _writer.WriteStartElement("Cell", "urn:schemas-microsoft-com:office:spreadsheet");
        _writer.WriteAttributeString("StyleID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
        _writer.WriteStartElement("Data", "urn:schemas-microsoft-com:office:spreadsheet");
        switch (style)
        {
            case CellStyle.General:
                _writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "String");
                break;
            case CellStyle.Number:
            case CellStyle.Currency:
                _writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "Number");
                break;
            case CellStyle.ShortDate:
            case CellStyle.DateTime:
                _writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "DateTime");
                break;
        }
        _writer.WriteValue(value);
        //  tag += String.Format("{1}\"><ss:Data ss:Type=\"DateTime\">{0:yyyy\\-MM\\-dd\\THH\\:mm\\:ss\\.fff}</ss:Data>", value,

        _writer.WriteEndElement();
        _writer.WriteEndElement();
    }

    public void WriteExcelAutoStyledCell(object value)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");

        //write the <ss:Cell> and <ss:Data> tags for something
        if (value is Int16 || value is Int32 || value is Int64 || value is SByte ||
            value is UInt16 || value is UInt32 || value is UInt64 || value is Byte)
        {
            WriteExcelStyledCell(value, CellStyle.Number);
        }
        else if (value is Single || value is Double || value is Decimal) //we'll assume it's a currency
        {
            WriteExcelStyledCell(value, CellStyle.Currency);
        }
        else if (value is DateTime)
        {
            //check if there's no time information and use the appropriate style
            WriteExcelStyledCell(value, ((DateTime)value).TimeOfDay.CompareTo(new TimeSpan(0, 0, 0, 0, 0)) == 0 ? CellStyle.ShortDate : CellStyle.DateTime);
        }
        else
        {
            WriteExcelStyledCell(value, CellStyle.General);
        }
    }

    #region IDisposable Members

    public void Dispose()
    {
        if (_writer == null)
            return;

        _writer.Close();
        _writer = null;
    }

    #endregion
}

Затем вы можете экспортировать свой DataTable, используя следующее:

public static void ExcelExport(DataTable data, String fileName, bool openAfter)
{
    //export a DataTable to Excel
    DialogResult retry = DialogResult.Retry;

    while (retry == DialogResult.Retry)
    {
        try
        {
            using (ExcelWriter writer = new ExcelWriter(fileName))
            {
                writer.WriteStartDocument();

                // Write the worksheet contents
                writer.WriteStartWorksheet("Sheet1");

                //Write header row
                writer.WriteStartRow();
                foreach (DataColumn col in data.Columns)
                    writer.WriteExcelUnstyledCell(col.Caption);
                writer.WriteEndRow();

                //write data
                foreach (DataRow row in data.Rows)
                {
                    writer.WriteStartRow();
                    foreach (object o in row.ItemArray)
                    {
                        writer.WriteExcelAutoStyledCell(o);
                    }
                    writer.WriteEndRow();
                }

                // Close up the document
                writer.WriteEndWorksheet();
                writer.WriteEndDocument();
                writer.Close();
                if (openAfter)
                    OpenFile(fileName);
                retry = DialogResult.Cancel;
            }
        }
        catch (Exception myException)
        {
            retry = MessageBox.Show(myException.Message, "Excel Export", MessageBoxButtons.RetryCancel, MessageBoxIcon.Asterisk);
        }
    }
}

-1: не пытайтесь сгенерировать XML с помощью TextWriter таким образом. Я просто укажу на одну очевидную проблему: если ваш DataTable содержит строковое значение с угловыми скобками, приведенный выше код не сможет их правильно избежать.

Joe 17.12.2008 13:12

Хорошая точка зрения. Просто показывает, что мне следует остановиться, чтобы еще немного подумать. Я переработал его, чтобы использовать XmlWriter. Теоретически, перед выпуском в публичную библиотеку следует провести дополнительную проверку ошибок, но если вы уверены, что будете называть вещи в правильном порядке, вы «в безопасности».

lc. 17.12.2008 17:56

Ошибка во второй части кода. Вместо «foreach (объект o в dataTable.Rows)» должно быть «foreach (объект o в row.ItemArray)».

Aleris 14.01.2009 12:17

Да, да, должно - я только что исправил. Спасибо за это.

lc. 15.01.2009 11:13

lc, я добавил код, чтобы принять DataSet и выполнить foreach в таблицах, чтобы добавить рабочие листы. Я также планирую немного по-другому организовать код и полностью документировать каждый метод в формате MSDN XML. Хотите, я пришлю его вам?

Kenny Mann 12.03.2009 16:42

В случае, если кто-то еще столкнется с этим: если вы забыли присвоить значение столбцу в таблице данных, средство записи XML ПРЕКРАТИТ ЗАПИСЬ, оставив вам неверно сформированный XML. Мне потребовалась вечность, чтобы найти свою ошибку.

Kenny Mann 12.03.2009 18:02

Я могу быть идиотом, но мне пришлось добавить экземпляр OpenFileDialog к функции ExcelExport() и изменить раздел OpenFile() на openFileDialog.FileName = fileName; openFileDialog.OpenFile();

Refracted Paladin 13.01.2010 23:11

@Refracted Paladin Не идиот, я, должно быть, забыл включить эту функцию. OpenFile () на самом деле является методом экземпляра, который выполняет оболочку для имени файла. Проще, чем добавить OpenFileDialog (но делает то же самое).

lc. 27.01.2010 19:39

@lc: Понятно. В этом есть смысл. Спасибо за продолжение.

Refracted Paladin 28.01.2010 00:21

+1. Отличный код, и автор (lc) гораздо лучше меня воспринимает критику своего кода. Актив для SO.

jp2code 21.05.2012 18:18

@ jp2code Я всегда стараюсь улучшить свой код. Я буду защищать это, когда думаю, что я прав, но я всегда по крайней мере (стараюсь) сначала слушать

lc. 23.05.2012 08:00

@Ic Привет, он работает нормально, но я хочу, чтобы тип ячейки был «Текст», но всегда «Общий». Как я могу это решить.

AhmetUrkan 28.09.2016 19:46

Создание файлов Excel в приложениях .NET довольно распространено, и подобные вопросы уже задавались несколько раз. Например, здесь и здесь. Последний вопрос касается чтения файлов Excel, но большинство предлагаемых решений должны работать в обоих направлениях.

Поправьте меня, если я ошибаюсь, но mave запрашивала решение не на веб-сервере?

lc. 17.12.2008 11:20

Ах. Тогда я неправильно понял ваш вопрос. Я думал, вы просили способ создавать файлы Excel без НАПИСАНИЯ какого-либо кода. Тогда я перефразирую свой ответ.

Rune Grimstad 17.12.2008 11:40

На следующем сайте показано, как экспортировать DataSet (или DataTable или List <>) в файл Excel 2007 .xlsx «подлинный».

Он использует библиотеки OpenXML, поэтому вам не необходимо, чтобы на вашем сервере был установлен Excel.

Библиотека C# ExportToExcel

Предоставляется весь исходный код бесплатно вместе с инструкциями по его использованию с ASP.NET, ASP.NET Core 2+ или обычным C#.

очень легко добавить в ваши собственные приложения, вам просто нужно вызвать одну функцию, передав имя файла Excel и ваш источник данных:

DataSet ds = CreateSampleData();
string excelFilename = "C:\\Sample.xlsx";
CreateExcelFile.CreateExcelDocument(ds, excelFilename);

Надеюсь это поможет.

Я использую это. Я не увидел лицензионное соглашение?

Melanie 24.04.2013 11:14

Ссылка, которую вы указали, не работает.

java-love 04.11.2019 22:27

Спасибо, что дали мне знать. Я обновил ссылку. (Удивительно, что этот ответ все еще читают, 8 лет спустя ... но только 3 человека когда-либо проголосовали за него!)

Mike Gledhill 05.11.2019 21:04
using XL = Microsoft.Office.Interop.Excel;
using System.Reflection;

public static void Datasource(DataTable dt)
{
    XL.Application oXL;
    XL._Workbook oWB;
    XL._Worksheet oSheet;
    XL.Range oRng;

    try
    {
        oXL = new XL.Application();
        Application.DoEvents();
        oXL.Visible = false;

        //Get a new workbook.
        oWB = (XL._Workbook)(oXL.Workbooks.Add(Missing.Value));
        oSheet = (XL._Worksheet)oWB.ActiveSheet;

        //System.Data.DataTable dtGridData=ds.Tables[0];

        int iRow = 2;
        if (dt.Rows.Count > 0)
        {
            for (int j = 0; j < dt.Columns.Count; j++)
            {
                oSheet.Cells[1, j + 1] = dt.Columns[j].ColumnName;
            }

            // For each row, print the values of each column.
            for (int rowNo = 0; rowNo < dt.Rows.Count; rowNo++)
            {
                for (int colNo = 0; colNo < dt.Columns.Count; colNo++)
                {
                    oSheet.Cells[iRow, colNo + 1] = dt.Rows[rowNo][colNo].ToString();
                }
                iRow++;
            }
            iRow++;
        }
        oRng = oSheet.get_Range("A1", "IV1");
        oRng.EntireColumn.AutoFit();
        oXL.Visible = true;
    }
    catch (Exception theException)
    {
        throw theException;
    }
    finally
    {
        oXL = null;
        oWB = null;
        oSheet = null;
        oRng = null;
    }
}

Импорт из Excel в datatable:

 DataTable dtTable = new DataTable();
 DataColumn col = new DataColumn("Rfid");
 dtTable.Columns.Add(col);
 DataRow drRow;

 Microsoft.Office.Interop.Excel.Application ExcelObj =
        new Microsoft.Office.Interop.Excel.Application();
 Microsoft.Office.Interop.Excel.Workbook theWorkbook =
            ExcelObj.Workbooks.Open(txt_FilePath.Text, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                    Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
 Microsoft.Office.Interop.Excel.Sheets sheets = theWorkbook.Worksheets;
 try
 {
     for (int sht = 1; sht <= sheets.Count; sht++)
     {
          Microsoft.Office.Interop.Excel.Worksheet worksheet =
                    (Microsoft.Office.Interop.Excel.Worksheet)sheets.get_Item(sht);

          for (int i = 2; i <= worksheet.UsedRange.Rows.Count; i++)
          {
              Microsoft.Office.Interop.Excel.Range range = worksheet.get_Range("A" + i.ToString(), "B" + i.ToString());
              System.Array myvalues = (System.Array)range.Cells.Value2;
              String name = Convert.ToString(myvalues.GetValue(1, 1));
              if (string.IsNullOrEmpty(name) == false)
              {
                  drRow = dtTable.NewRow();
                  drRow["Rfid"] = name;
                  dtTable.Rows.Add(drRow);
              }
          }
              Marshal.ReleaseComObject(worksheet);
              worksheet = null;
        }
    return dtTable;
}
catch
{
    throw;
}
finally
{
   // Marshal.ReleaseComObject(worksheet);
    Marshal.ReleaseComObject(sheets);
    Marshal.ReleaseComObject(theWorkbook);
    Marshal.ReleaseComObject(ExcelObj);
    //worksheet = null;
    sheets = null;
    theWorkbook = null;
    ExcelObj = null;
}

Это был пост с действительно полезным верхним ответом, но я обнаружил, что его не хватает, потому что не было простого способа импортировать XML-файл обратно в таблицу данных. В итоге мне пришлось написать свой собственный, и я подумал, что поделюсь им здесь, если кто-то еще окажется в той же лодке (Google был исключительно бесполезен в этом отношении):

public static DataTable ImportExcelXML(string Filename)
    {
        //create a new dataset to load in the XML file
        DataSet DS = new DataSet();
        //Read the XML file into the dataset
        DS.ReadXml(Filename);
        //Create a new datatable to store the raw Data
        DataTable Raw = new DataTable();
        //assign the raw data from the file to the datatable
        Raw = DS.Tables["Data"];
        //count the number of columns in the XML file
        int ColumnNumber = Raw.Columns.Count;
        //create a datatable to store formatted Import Data
        DataTable ImportData = new DataTable();
        //create a string list to store the cell data of each row
        List<string> RowData = new List<string>();
        //loop through each row in the raw data table
        for (int Counter = 0; Counter < Raw.Rows.Count; Counter++)
        {
            //if the data in the row is a colum header
            if (Counter < ColumnNumber)
            {
                //add the column name to our formatted datatable
                ImportData.Columns.Add(Raw.Rows[Counter].ItemArray.GetValue(1).ToString());
            }
            else
            {
                //if the row # (1 row = 1 cell from the excel file) from the raw datatable is divisable evenly by the number of columns in the formated import datatable AND this is not the 1st row of the raw table data after the headers
                if ((Counter % ColumnNumber == 0) && (Counter != ColumnNumber))
                {
                    //add the row we just built to the formatted import datatable
                    ImportData.Rows.Add(GenerateRow(ImportData, RowData));
                    //clear rowdata list in preperation for the next row
                    RowData.Clear();
                }
                //add the current cell data value from the raw datatable to the string list of cell values for the next row to be added to the formatted input datatable
                RowData.Add(Raw.Rows[Counter].ItemArray.GetValue(1).ToString());
            }
        }
        //add the final row
        ImportData.Rows.Add(GenerateRow(ImportData, RowData));

        return ImportData;
    }

    public static DataRow GenerateRow(DataTable ImportData, List<string> RowData)
    {
        //create a counter to keep track of the column position during row composition
        int ColumnPosition = 0;
        //make a new datarow based on the schema of the formated import datatable
        DataRow NewRow = ImportData.NewRow();
        //for each string cell value collected for the RowData list for this row
        foreach (string CellData in RowData)
        {
            //add the cell value to the new datarow
            NewRow[ImportData.Columns[ColumnPosition].ColumnName] = CellData;
            //incriment column position in the new row
            ColumnPosition++;
        }
        //return the generated row
        return NewRow;
    }

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

 public void WriteExcelAutoStyledCell(object value)
    {
        //solve null values
        if (value is DBNull) return;

Я бы добавил это в комментарии, но я новичок в стеке, поэтому не могу комментировать. Используя решение lc., я добавил еще одну функцию, которая проверяет строковые символы на недопустимые символы XML. Когда я экспортировал в Excel, иногда обнаруживались символы, которые приводили к сбою экспорта.

Вам нужно будет изменить одну из функций в коде lc.

public void WriteExcelAutoStyledCell(object value)
    {
        if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
        string newValue = string.Empty;

        try
        {
            //write the <ss:Cell> and <ss:Data> tags for something
            if (value is Int16 || value is Int32 || value is Int64 || value is SByte ||
                value is UInt16 || value is UInt32 || value is UInt64 || value is Byte)
            {
                WriteExcelStyledCell(value, CellStyle.Number);
            }
            else if (value is Single || value is Double || value is Decimal) //we'll assume it's a currency
            {
                WriteExcelStyledCell(value, CellStyle.Currency);
            }
            else if (value is DateTime)
            {
                //check if there's no time information and use the appropriate style
                WriteExcelStyledCell(value, ((DateTime)value).TimeOfDay.CompareTo(new TimeSpan(0, 0, 0, 0, 0)) == 0 ? CellStyle.ShortDate : CellStyle.DateTime);
            }
            else
            {
                newValue = CheckXmlCompatibleValues(value.ToString()).ToString();
                WriteExcelStyledCell(newValue, CellStyle.General);
            }
        }
        catch (Exception thisException)
        {
            throw new InvalidOperationException(thisException.Message.ToString());
        }
    }

И добавьте эту функцию в класс ExcelWriter

public string CheckXmlCompatibleValues(string value)
    {
        string newValue = string.Empty;
        bool found = false;

        foreach (char c in value)
        {
            if (XmlConvert.IsXmlChar(c))
                newValue += c.ToString();
            else
                found = true;
        }

        return newValue.ToString();
    }

lc. Спасибо за код!

У Microsoft есть встроенное решение для импорта / экспорта файлов Excel. Это не самая простая библиотека, но в целом она работает лучше, чем другие, перечисленные выше.

Библиотека, необходимая для этого, включена в Office и может быть найдена в списке сборок Framework в Microsoft.Office.Interop.Excel.

Вот пример кода:

using Excel = Microsoft.Office.Interop.Excel;

Excel.Application app = new Excel.Application();

//Open existing workbook
//Excel.Workbook workbook = xlApp.Workbooks.Open(fileName);

//Create new workbook
Excel.Workbook workbook = app.Workbooks.Add();

Excel.Worksheet worksheet = workbook.ActiveSheet;

worksheet.Cells[1,1] = "Hello world!"; // Indexes start at 1, because Excel
workbook.SaveAs("C:\\MyWorkbook.xlsx");
workbook.Close();
app.Quit();

Другие вопросы по теме

Установка родительского элемента пользовательского элемента управления предотвращает его прозрачность
Проверьте, выполняется ли перетаскивание
Захват первого символа при входе в режим редактирования - настраиваемый элемент управления редактированием в DataGridView
Правильный способ получить пользовательский интерфейс Winforms для блокировки с помощью диалогового окна до тех пор, пока не появится какое-либо событие, не связанное с пользователем?
WinForms: как программно запустить обработчик событий?
Как выполнить привязку данных к элементу управления System.Windows.Forms.Treeview?
Отображение кнопки восстановления без кнопки развертывания
Плюсы и минусы MDI
Как заблокировать поток пользовательского интерфейса из другого потока или заставить форму запускаться в потоке пользовательского интерфейса
Ищу элемент управления "текстового" редактора .NET