我有一个正在使用的简单WPF应用程序,该应用程序执行SQL查询并在DataGrid中显示结果数据。
一切都按预期工作,但性能很差。从单击按钮加载数据到实际看到数据显示在DataGrid中的时间大约为3-4秒。启用行虚拟化后,它的速度要快得多,但是由于我需要能够对滚动后不再可见的单元执行操作,因此不得不将其关闭。即使启用了虚拟化,显示数据的速度也比我想要的慢。
我首先假设是SQL数据库运行缓慢,但是我进行了一些测试,发现我在不到一秒钟的时间内将所有数据从SQL服务器(几百行)读取到了DataTable中。直到我将DataTable绑定(bind)到DataGrid的DataContext时,所有内容都锁定了几秒钟。
那么为什么DataContext这么慢?我的计算机是全新的,因此我很难理解为什么首先要检索数据要花多长时间才能填写DataGrid。
(我也尝试绑定(bind)到DataGrid的ItemSource而不是DataContext,但是性能是相同的。)
是否存在将数据加载到具有更合理性能的DataGrid中的替代方法?如果需要,甚至可以替代DataGrid进行探索。
编辑:在Vlad的建议下,我尝试了另一项绕过SQL查询的测试。相反,我用1000行随机生成的数据填充了DataTable。没有变化。不到一秒钟就生成了数据并将其写入DataTable。但是,将其附加到DataGrid花费了20秒钟以上。
以下是我正在使用的DataGrid XAML。除了绑定(bind)以外,它非常简单,没有附加自定义代码。
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False" Name="dataGridWellReadings" GridLinesVisibility="None" CanUserResizeRows="False" SelectionUnit="Cell" AlternatingRowBackground="#FFE0E0E0" RowBackground="#FFF0F0F0" HorizontalScrollBarVisibility="Disabled" SelectedCellsChanged="dataGridWellReadings_SelectedCellsChanged" EnableRowVirtualization="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Date" Binding="{Binding readingDate, StringFormat=yyyy-MM-dd}" Width="3*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Pt" Binding="{Binding readingPt, StringFormat=0.#}" Width="2*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Pc" Binding="{Binding readingPc, StringFormat=0.#}" Width="2*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Ppl" Binding="{Binding readingPpl, StringFormat=0.#}" Width="2*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="MCFD" Binding="{Binding readingMCFD, StringFormat=0.#}" Width="2*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Water Produced" Binding="{Binding readingWaterProduced, StringFormat=0.#}" Width="3*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Water Hauled" Binding="{Binding readingWaterHauled, StringFormat=0.#}" Width="3*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Temperature" Binding="{Binding readingTemperature, StringFormat=0.#}" Width="3*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Hours On (actual)" Binding="{Binding readingHoursOnActual, StringFormat=0.#}" Width="3*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Hours On (planned)" Binding="{Binding readingHoursOnPlanned, StringFormat=0.#}" Width="3*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Clock Cycles" Binding="{Binding readingClockCycles, StringFormat=0.#}" Width="3*">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
最佳答案
有太多变量无法确定地回答这一问题。但是,您可以考虑以下一些事项:
同样,此问题没有100%的答案。但是这些可能会有所帮助。
还有一点要考虑的是,您的枚举可以是一个可观察的列表-这将使您可以部分加载数据。如果要加载第一页,并在异步过程中添加下一页和下一页,依此类推,则用户体验应该非常接近一次加载所有内容,除非它可以更快地进行初始渲染。这可能很复杂,但这是您的另一选择。像这样的可观察列表很漂亮。
像这样的东西:
ObservableCollection<User> Users { get; set; }
void LoadUsers()
{
int _Size = 2;
int _Page = 0;
using (System.ComponentModel.BackgroundWorker _Worker
= new System.ComponentModel.BackgroundWorker())
{
_Worker.WorkerReportsProgress = true;
_Worker.DoWork += (s, arg) =>
{
List<User> _Data = null;
while (_Data == null || _Data.Any())
{
_Data = GetData(_Size, _Page++);
_Worker.ReportProgress(_Page, _Data);
}
};
_Worker.ProgressChanged += (s, e) =>
{
List<User> _Data = null;
_Data = e.UserState as List<User>;
_Data.ForEach(x => Users.Add(x));
};
_Worker.RunWorkerAsync();
}
}
List<User> GetData(int size, int page)
{
// never return null
return m_Context.Users.Take(size).Skip(page).ToList();
}
这就是我要您摘录的内容-在WPF中绑定(bind)永远不会立即发生。您将永远不会有复杂的表单呈现和绑定(bind)而不会有些延迟。您可以使用上述某些技术来控制疼痛。但是,您永远无法将其全部删除。但是,WPF中的绑定(bind)是最强大,最强大的绑定(bind)技术。我曾经经历过。
祝你好运!