Нужен код C#, преобразованный в VB.NET для Silverlight "Экспорт в CSV"

Я ищу, чтобы преобразовать следующий код в рабочий код VB.NET. Мне нужно экспортировать данные из сетки данных в формат CSV, который пользователь может сохранить, и приведенный ниже код от David в Дакоте будет работать отлично, но он находится в C#. Любая помощь будет оценена! Это для сайта Silverlight 4, над которым мы работаем.

private void exportHistoryButton_Click(object sender, RoutedEventArgs e)
{
    string data = ExportDataGrid(true, historyDataGrid);
    SaveFileDialog sfd = new SaveFileDialog()
    {
        DefaultExt = "csv",
        Filter = "CSV Files (*.csv)|*.csv|All files (*.*)|*.*",
        FilterIndex = 1
    };
    if (sfd.ShowDialog() == true)
    {
        using (Stream stream = sfd.OpenFile())
        {
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write(data);
                writer.Close();
            }
            stream.Close();
        }
    }
}

private string FormatCSVField(string data)
{
    return String.Format(
            "\"{0}\"",
            data.Replace("\"", "\"\"\"")
            .Replace("\n", "")
            .Replace("\r", "")
        );
}

public string ExportDataGrid(bool withHeaders, DataGrid grid)
{
    string colPath;
    System.Reflection.PropertyInfo propInfo;
    System.Windows.Data.Binding binding;
    System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
    System.Collections.IList source = (grid.ItemsSource as System.Collections.IList);
    if (source == null)
        return "";

    List<string> headers = new List<string>();
    grid.Columns.ToList().ForEach(col =>
    {
        if (col is DataGridBoundColumn)
        {
            headers.Add(FormatCSVField(col.Header.ToString()));
        }
    });
    strBuilder
    .Append(String.Join(",", headers.ToArray()))
    .Append("\r\n");

    foreach (Object data in source)
    {
        List<string> csvRow = new List<string>();
        foreach (DataGridColumn col in grid.Columns)
        {
            if (col is DataGridBoundColumn)
            {
                binding = (col as DataGridBoundColumn).Binding;
                colPath = binding.Path.Path;
                propInfo = data.GetType().GetProperty(colPath);
                if (propInfo != null)
                {
                    csvRow.Add(FormatCSVField(propInfo.GetValue(data, null).ToString()));
                }
            }
        }
        strBuilder.Append(String.Join(",", csvRow.ToArray())).Append("\r\n");
    }
    return strBuilder.ToString();
}

3 ответа

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

Private Sub exportHistoryButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) 
    Dim sfd As New SaveFileDialog() 
    sfd.DefaultExt = "csv"
    sfd.Filter = "CSV Files (*.csv)|*.csv|All files (*.*)|*.*"
    sfd.FilterIndex = 1 

    If sfd.ShowDialog() Then
        Using writer As New StreamWriter(sfd.OpenFile())
           writer.Write(ExportDataGrid(True, historyDataGrid))
        End Using
    End If 

End Sub

Private Function FormatCSVField(ByVal data As String) As String
    Return String.Format("""{0}""", _
         data.Replace("""", """""").Replace(vbLf, "").Replace(vbCr, ""))
End Function 

Public Function ExportDataGrid(ByVal withHeaders As Bool, ByVal grid As DataGrid) As String
    Dim source As System.Collections.IList = TryCast(grid.ItemsSource, System.Collections.IList) 
    If source Is Nothing Then Return "" 

    Dim builder As New System.Text.StringBuilder()

    If withHeaders Then
        Dim headers As new List(Of String)()
        For Each col As DataColumn In grid.Columns.Where(Function(c) TypeOf c is DataGridBoundColumn)
            headers.Add(FormatCSVField(col.Header.ToString()))
        Next col
        builder.Append(String.Join(",", headers.ToArray())).Append(vbCrLf)
    End If

    For Each row in source
        Dim csvRow As New List(Of String)()
        For Each col As DataGridBoundColumn in grid.Columns.Where(Function(c) TypeOf col Is DataGridBoundColumn) 
            Dim propInfo As System.Reflection.PropertyInfo = _ 
                  row.GetType().GetProperty(col.Binding.Path.Path)
            If propInfo IsNot Nothing Then  
                csvRow.Add(FormatCSVField(propInfo.GetValue(row, Nothing).ToString())) 
            End If 
        Next col 

        builder.Append(String.Join(",", csvRow.ToArray())).Append(vbCrLf) 
    Next row 

    Return builder.ToString()
End Function 

Большая проблема этого кода состоит в том, что когда вы помещаете всю сетку в одну строковую переменную, вы создаете объект, который, скорее всего, окажется в куче больших объектов. Это "Плохая вещь"™. Одна из вещей, которая делает его таким плохим, заключается в том, что он часто выглядит не плохо при тестировании производительности. Это проблема, которая не появится до производства. Но поверь мне, когда я скажу, что мы можем сделать лучше.

Если бы это все еще был C#, я бы реорганизовал его, используя блок итератора, чтобы получить возвращаемую строку для одной строки за раз, а затем записал бы это. Поскольку это VB, мы реорганизуем его для принятия TextWriter и напишем прямо в него:

Private Sub exportHistoryButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) 
    Dim sfd As New SaveFileDialog() 
    sfd.DefaultExt = "csv"
    sfd.Filter = "CSV Files (*.csv)|*.csv|All files (*.*)|*.*"
    sfd.FilterIndex = 1 

    If sfd.ShowDialog() Then
        Using writer As New StreamWriter(sfd.OpenFile())
            ExportDataGrid(historyDataGrid, writer) ' Notice the change here
        End Using
    End If 

End Sub

Private Function WriteCSVField(ByVal data As String, ByVal writer As TextWriter) As String
    ' This would likely do a _lot_ better with a state machine to iterate over
    '  each character rather than create 3 new strings for every field, 
    '  but we'll let it slide for now
    writer.Write(""""c)
    writer.Write(data.Replace("""", """""").Replace(vbLf, "").Replace(vbCr, ""))
    writer.Write(""""c)
End Function 

' Notice the new function signature
Public Sub ExportDataGrid(ByVal grid As DataGrid, ByVal writer As TextWriter, Optional ByVal WithHeaders As Boolean = True)
    Dim source As System.Collections.IList = TryCast(grid.ItemsSource, System.Collections.IList) 
    If source Is Nothing Then Return "" 

    Dim delimiter As String
    If WithHeaders Then
        delimiter = ""
        For Each col As DataColumn In grid.Columns.Where(Function(c) TypeOf c is DataGridBoundColumn)
            writer.Write(delimiter)
            WriteCSVField(col.Header.ToString(), writer)
            delimiter = ","
        Next col
        writer.Write(vbCrLf)
    End If

    For Each row In source
        delimiter = ""
        For Each col As DataGridBoundColumn in grid.Columns.Where(Function(c) TypeOf col Is DataGridBoundColumn) 
            writer.Write(delimiter)
            delimiter = ","

            ' I'm pretty sure this could be refactored to avoid the reflection,
            ' But I also think there's a bug in your code here, so I'll
            '  leave the direct translation for now
            Dim propInfo As System.Reflection.PropertyInfo = _ 
                  row.GetType().GetProperty(col.Binding.Path.Path)
            If propInfo IsNot Nothing Then  
                WriteCSVField(propInfo.GetValue(row, Nothing).ToString(), writer) 
            End If 
        Next col 
        writer.Write(vbCrLf)
    Next row 
End Sub

Конечно, лучший вариант здесь - вообще не писать новый код для проблемы, которая уже была решена тысячами других программистов. Вы можете просто получить существующую библиотеку, которая превращает весь этот беспорядок в две или строки, вызывающие этот API.

Это не вопрос, это запрос. Но попробуйте это:

http://www.developerfusion.com/tools/convert/csharp-to-vb/

Private Sub exportHistoryButton_Click(sender As Object, e As RoutedEventArgs)
    Dim data As String = ExportDataGrid(True, historyDataGrid)
    Dim sfd As New SaveFileDialog() With { _
        .DefaultExt = "csv", _
        .Filter = "CSV Files (.csv)|.csv|All files (.)|.", _
        .FilterIndex = 1 _
    }
    If sfd.ShowDialog() = True Then
        Using stream As Stream = sfd.OpenFile()
            Using writer As New StreamWriter(stream)
                writer.Write(data)
                writer.Close()
            End Using
            stream.Close()
        End Using
    End If
End Sub

Private Function FormatCSVField(data As String) As String
    Return [String].Format("""{0}""", data.Replace("""", """""""").Replace(vbLf, "").Replace(vbCr, ""))
End Function

Public Function ExportDataGrid(withHeaders As Boolean, grid As DataGrid) As String
    Dim colPath As String
    Dim propInfo As System.Reflection.PropertyInfo
    Dim binding As System.Windows.Data.Binding
    Dim strBuilder As New System.Text.StringBuilder()
    Dim source As System.Collections.IList = TryCast(grid.ItemsSource, System.Collections.IList)
    If source Is Nothing Then
        Return ""
    End If

    Dim headers As New List(Of String)()
    grid.Columns.ToList().ForEach(Function(col) Do
        If TypeOf col Is DataGridBoundColumn Then
            headers.Add(FormatCSVField(col.Header.ToString()))
        End If
    End Function)
    strBuilder.Append([String].Join(",", headers.ToArray())).Append(vbCr & vbLf)

    For Each data As [Object] In source
        Dim csvRow As New List(Of String)()
        For Each col As DataGridColumn In grid.Columns
            If TypeOf col Is DataGridBoundColumn Then
                binding = TryCast(col, DataGridBoundColumn).Binding
                colPath = binding.Path.Path
                propInfo = data.[GetType]().GetProperty(colPath)
                If propInfo IsNot Nothing Then
                    csvRow.Add(FormatCSVField(propInfo.GetValue(data, Nothing).ToString()))
                End If
            End If
        Next
        strBuilder.Append([String].Join(",", csvRow.ToArray())).Append(vbCr & vbLf)
    Next


    Return strBuilder.ToString()
End Function
Другие вопросы по тегам