我正在努力为 WPF 中合理大小的 DataGrid 提供合理的加载时间。
我的例子非常简单,粘贴在下面。它只是在按下按钮时加载 40x40 数字的网格,并且 UI 冻结 1 秒。我已经运行了 VS 分析器,加载布局需要 1.16 秒,该布局是由可视化树中的 4147 个元素构建的。
我对 DataGrid 需要时间加载没有任何问题,但我确实认为窗口在加载时完全冻结是一个问题。有人可以帮助我加载 DataGrid 同时保持我的窗口响应吗?
非常感谢!
主窗口.xaml
<Window x:Class="Coliru.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:c="clr-namespace:flap_ui_core.Components;assembly=flap_ui_core"
xmlns:local="clr-namespace:Coliru"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button Content="Create DataGrid" Padding="5,2" Click="Button_Click" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<ContentControl x:Name="myContentControl"/>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Collections.ObjectModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Coliru
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public class ViewModel
{
public class RowType
{
public ObservableCollection<double> Columns
{
get => _Columns;
}
private ObservableCollection<double> _Columns;
public RowType(ObservableCollection<double> columns)
{
_Columns = columns;
}
}
public static readonly int numcol = 40;
public static readonly int numrow = 40;
public ObservableCollection<RowType> Rows { get => _Rows; }
private ObservableCollection<RowType> _Rows;
public ViewModel()
{
Random autoRand = new Random();
_Rows = new ObservableCollection<RowType>();
for (int icol = 0; icol < numcol;++icol)
{
var rows = new ObservableCollection<double>();
for (int irow = 0; irow < numrow; ++irow)
{
rows.Add(autoRand.NextDouble());
}
_Rows.Add(new(rows));
}
}
}
DataGrid? dataGrid;
ViewModel viewModel;
public MainWindow()
{
InitializeComponent();
viewModel = new ViewModel();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
dataGrid = new DataGrid();
dataGrid.Initialized += DataGrid_Initialized;
myContentControl.Content = dataGrid;
}
private void DataGrid_Initialized(object? sender, EventArgs e)
{
dataGrid.ItemsSource = viewModel.Rows;
dataGrid.AutoGenerateColumns = false;
for (int i = 0; i < ViewModel.numcol; ++i)
{
var col = new DataGridTextColumn();
var binding = new Binding();
binding.Path = new PropertyPath("Columns[" + i + "]");
col.Binding = binding;
col.Header = "Column " + i;
col.Width = 80;
dataGrid.Columns.Add(col);
}
}
}
}
我尝试了很多方法,这只是问题的简化版本。我也尝试过 MVVM。
我尝试运行您发布的代码,但我无法能够重现 1 秒的长延迟。
我发现的唯一真正的问题不会真正上升到“问题”的水平,除非涉及多次按钮单击:就目前情况而言,每次单击按钮时,您都会再次订阅dataGrid.Initialized
事件,而这
不是“超出范围”的事情。如果是第二次单击按钮,则
DataGrid_Initialized
将运行两次。如果这是第 100 次按钮单击,DataGrid_Initialized
现在将运行 100 次。这是一个更清晰的点击处理程序,可以断开事件连接,以确保您只拥有所需的事件。
private void Button_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
if (myContentControl.Content is DataGrid existing)
{
existing.ItemsSource = null;
}
dataGrid = new DataGrid();
dataGrid.Initialized += DataGrid_Initialized;
myContentControl.Content = dataGrid;
}
finally
{
dataGrid.Initialized -= DataGrid_Initialized;
}
stopwatch.Stop();
MessageBox.Show($@"Initialization took {stopwatch.Elapsed:ss\:ffff}");
}
Button_Click
Debug
日志记录或类似的东西吗?这是我尝试优化任何可能需要时间的代码。不过,我想澄清的是,我没有发现任何确凿证据。
<Window x:Class="Coliru.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Coliru"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Width="500" Height="300">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Grid>
<Button Content="Create DataGrid" Padding="5,2" Click="Button_Click" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<ContentControl x:Name="myContentControl"/>
</Grid>
</Window>