0

I have an application that runs with and without a GUI depending on the user. I need it to export the DataGrid as a CSV file, heres the code:

// Copy contents of datagrid to clipboard, including header.
mainDataGrid.SelectAllCells();
mainDataGrid.ClipboardCopyMode = DataGridClipboardCopyMode.IncludeHeader;
ApplicationCommands.Copy.Execute(null, mainDataGrid);

string result = (string)Clipboard.GetData(DataFormats.CommaSeparatedValue);

This works fine with the GUI. The problem happens when I don't have a GUI, I think this is because the clipboard can't copy something that isn't there. Is there a different way to export it or is there a way to set the clipboards data instead of executing a copy command?

Mike
  • 850
  • 10
  • 33
  • The Clipboard class has some `SetData` and `SetDataObject` methods that might be helpfull. [msdn Clipboard doc](https://msdn.microsoft.com/en-us/library/system.windows.forms.clipboard(v=vs.110).aspx) – Mike May 15 '18 at 10:56
  • @MikeHjortChristensen I've tried, I used SetData which gave me this back as a string "System.Windows.Controls.DataGrid Items.Count:196" and SetDataObject gave me back null – MosesTheHoly May 15 '18 at 11:05
  • Have you tried using DataGridView instead? [Link](https://stackoverflow.com/a/26259909/4270201) – Mike May 15 '18 at 11:23
  • I've decided it would just be easier to loop through all columns and rows and comma separate it that way – MosesTheHoly May 15 '18 at 12:48

2 Answers2

1

In order to "copy something that isn't there", you'll need to use the underlying data object that is your DataGrid's ItemsSource.

If your DataGrid's ItemsSource is a DataTable, this method, analogous to MosesTheHoly's, will return a CSV string, but in a simpler manner.

public string GetCSVFromDataTabe(DataTable datatable)
{
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.Append(string.Join(",", dt.Columns.ToList<DataColumn>().Select(column => column.ColumnName).ToList()) + "\n");
    dataTable.Rows.ToList<DataRow>().ForEach(row => sb.Append(string.Join(",", row.ItemArray) + "\n"));
    return stringBuilder.ToString();
}

That should do it. Fairly concise, in my opinion. Now, just write that string to whatever file you need.

BerryAllan
  • 26
  • 2
  • 4
0

Alright, the code could probably be shortened, but this is the way I did it. I created a function that takes in a datatable and returns a CSV string.

private void SaveToCSV() {
    DataTable dt = new DataTable();
    dt = ((DataView)mainDataGrid.ItemsSource).ToTable();

    string result = WriteDataTable(dt);

    // The File.Create().Close() is so it closes the filestream after it creates it.
    if (!File.Exists(CSVFilePath)) {
        File.Create(CSVFilePath).Close();
    }
    File.AppendAllText(CSVFilePath, result, UnicodeEncoding.UTF8);
}

private string WriteDataTable(DataTable dataTable) {
    string output = "";

    // Need to get the last column so I know when to add a new line instead of comma.
    string lastColumnName = dataTable.Columns[dataTable.Columns.Count - 1].ColumnName;

    // Get the headers from the datatable.
    foreach (DataColumn column in dataTable.Columns) {
        if (lastColumnName != column.ColumnName) {
            output += (column.ColumnName.ToString() + ",");
        }
        else {
            output += (column.ColumnName.ToString() + "\n");
        }
    }
    // Get the actual data from the datatable.
    foreach (DataRow row in dataTable.Rows) {
        foreach (DataColumn column in dataTable.Columns) {
            if (lastColumnName != column.ColumnName) {
                output += (row[column].ToString() + ",");
            }
            else {
                output += (row[column].ToString() + "\n");
            }
        }
    }
    return output;
}