Firehawk
Firehawk
CC#
Created by Firehawk on 12/26/2022 in #help
❔ Poor DataGrid performance when using DataTable
I'm writing a program that can take any number of different tab delimited csv files, load them into a DataGrid for various modifications, and then export them back out. Currently this is done by parsing the data into list<list<string>>, and then converting that into a DataTable and then to a DataView. The problem is that for a csv with 255 columns and 2000 rows, the performance is rather poor. It's visibly quite bad on even smaller sized files (31 columns, 186 rows). I'm wondering if there's any obvious errors I'm making in either the xaml, or if the DataTable is the problem. I'm not experienced enough with the performance of WPF DataGrids to really know. Edit: The poor performance I'm speaking of is specifically when scrolling/interacting with the DataGrid
<Window.DataContext>
<viewModels:MainViewModel />
</Window.DataContext>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>

<Menu Grid.Row="0">
<MenuItem Header="File">
<MenuItem Header="Save" Command="{Binding SaveCurrentFileCommand}" />
<MenuItem Header="Load " Command="{Binding LoadNewFileCommand}" />
<MenuItem Header="Workspace">
<MenuItem Header="Save" Command="{Binding SaveWorkspaceCommand}"/>
<MenuItem Header="Load" Command="{Binding LoadWorkspaceCommand}"/>
</MenuItem>
</MenuItem>

</Menu>

<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<ListBox Grid.Column="0" DisplayMemberPath="FileName" ItemsSource="{Binding OpenedFiles}" SelectedItem="{Binding CurrentFile}" />

<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch"/>

<DataGrid Grid.Column="2"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Pixel"
VirtualizingPanel.IsContainerVirtualizable="True"
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
VirtualizingStackPanel.VirtualizationMode = "Recycling"
EnableColumnVirtualization="True"
EnableRowVirtualization="True"
ColumnWidth="100"
SelectionUnit="Cell"
CanUserAddRows="False"
CanUserResizeColumns="True"
CanUserSortColumns="False">
<DataGrid.ItemsSource>
<Binding Path="CurrentFile.DataView" IsAsync="True" />
</DataGrid.ItemsSource>
</DataGrid>
</Grid>
</Grid>
<Window.DataContext>
<viewModels:MainViewModel />
</Window.DataContext>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>

<Menu Grid.Row="0">
<MenuItem Header="File">
<MenuItem Header="Save" Command="{Binding SaveCurrentFileCommand}" />
<MenuItem Header="Load " Command="{Binding LoadNewFileCommand}" />
<MenuItem Header="Workspace">
<MenuItem Header="Save" Command="{Binding SaveWorkspaceCommand}"/>
<MenuItem Header="Load" Command="{Binding LoadWorkspaceCommand}"/>
</MenuItem>
</MenuItem>

</Menu>

<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<ListBox Grid.Column="0" DisplayMemberPath="FileName" ItemsSource="{Binding OpenedFiles}" SelectedItem="{Binding CurrentFile}" />

<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch"/>

<DataGrid Grid.Column="2"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Pixel"
VirtualizingPanel.IsContainerVirtualizable="True"
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
VirtualizingStackPanel.VirtualizationMode = "Recycling"
EnableColumnVirtualization="True"
EnableRowVirtualization="True"
ColumnWidth="100"
SelectionUnit="Cell"
CanUserAddRows="False"
CanUserResizeColumns="True"
CanUserSortColumns="False">
<DataGrid.ItemsSource>
<Binding Path="CurrentFile.DataView" IsAsync="True" />
</DataGrid.ItemsSource>
</DataGrid>
</Grid>
</Grid>
[AddINotifyPropertyChangedInterface]
public class TabbedCsvModel
{
public DataTable DataTable { get; set; }
public string FilePath { get; set; }
public Dictionary<int, double> ColumnWidths { get; set; }
public DataView DataView { get; set; }

public string FileName => Path.GetFileName(FilePath);
}
[AddINotifyPropertyChangedInterface]
public class TabbedCsvModel
{
public DataTable DataTable { get; set; }
public string FilePath { get; set; }
public Dictionary<int, double> ColumnWidths { get; set; }
public DataView DataView { get; set; }

public string FileName => Path.GetFileName(FilePath);
}
private static TabbedCsvModel? LoadFile(string filePath)
{
var rows = File.ReadAllLines(filePath)
.Select(line => line.Split('\t').ToList())
.ToList();

if (rows.Count == 0 ||
rows.Any(x => x.Count != rows[0].Count))
return null;

TabbedCsvModel txtFile = new()
{
DataTable = new DataTable()
};

txtFile.DataView = new DataView(txtFile.DataTable);

for (var i = 0; i < rows[0].Count; i++)
txtFile.DataTable.Columns.Add(new DataColumn());

foreach (var row in rows)
{
var dataRow = txtFile.DataTable.NewRow();

for (var i = 0; i < row.Count; i++)
dataRow[i] = row[i];

txtFile.DataTable.Rows.Add(dataRow);
}

txtFile.FilePath = filePath;
return txtFile;
}
private static TabbedCsvModel? LoadFile(string filePath)
{
var rows = File.ReadAllLines(filePath)
.Select(line => line.Split('\t').ToList())
.ToList();

if (rows.Count == 0 ||
rows.Any(x => x.Count != rows[0].Count))
return null;

TabbedCsvModel txtFile = new()
{
DataTable = new DataTable()
};

txtFile.DataView = new DataView(txtFile.DataTable);

for (var i = 0; i < rows[0].Count; i++)
txtFile.DataTable.Columns.Add(new DataColumn());

foreach (var row in rows)
{
var dataRow = txtFile.DataTable.NewRow();

for (var i = 0; i < row.Count; i++)
dataRow[i] = row[i];

txtFile.DataTable.Rows.Add(dataRow);
}

txtFile.FilePath = filePath;
return txtFile;
}
2 replies