数据网格速度较慢 - 提高性能
本文关键字:高性能 数据网 网格 速度 数据 | 更新日期: 2023-09-27 18:37:08
我有一个相当大的数据网格。
下面是只有一列的数据网格:
<DataGrid x:Name="dgVarConfig"
ItemsSource="{Binding VarConfigList, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Path=SelectedVarConfig, Mode=TwoWay}"
Margin="8,56,557,80"
AutoGenerateColumns="False"
CanUserDeleteRows="False"
CanUserResizeRows="False"
HeadersVisibility="Column"
CanUserAddRows="False"
HorizontalScrollBarVisibility="Auto"
PreviewKeyDown="dgVarConfig_PreviewKeyDown"
BeginningEdit="dgVarConfig_BeginningEdit"
CellEditEnding="dgVarConfig_CellEditEnding"
SelectionChanged="dgVarConfig_SelectionChanged"
EnableRowVirtualization="True"
EnableColumnVirtualization="False"
VerticalGridLinesBrush="Black"
VirtualizingStackPanel.VirtualizationMode ="Standard"
VirtualizingStackPanel.IsVirtualizing="true">
<DataGrid.Columns>
<DataGridTemplateColumn Width="auto" MinWidth="150" SortMemberPath="Match_expression">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ContentControl>
<MultiBinding Converter="{StaticResource highlightConverter}" ConverterParameter="MATCHEXPRESSION">
<Binding Path="Match_expression"></Binding>
</MultiBinding>
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate >
<DataTemplate>
<TextBox Text="{Binding Match_expression}" FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}" Style="{StaticResource GridTextBox}"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridColumnHeader">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Padding="5 0" Content="Auswahlformel" VerticalAlignment="Center" Cursor="Hand" Foreground="White"/>
<TextBox x:Name="txtMatchExpressionFilter" Margin="0 5" Grid.Column="2" Width="150" Visibility="Collapsed"></TextBox>
<Button Grid.Column="3" Margin="5 0" x:Name="btnFilterMatchExpresion" Style="{StaticResource MyButton}" Width="16" Height="16" VerticalAlignment="Center" HorizontalAlignment="Right" Click="btnFilterMatchExpresion_Click">
<Button.Background>
<ImageBrush ImageSource="Resources/filter.png"/>
</Button.Background>
</Button>
<Path x:Name="SortArrow"
Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Width="8" Height="6" Margin="2,0,5,0"
Stretch="Fill" Opacity="0.5" Fill="White"
RenderTransformOrigin="0.5,0.4"
Visibility="Collapsed"
Data="M0,0 L1,0 0.5,1 z" />
<Thumb x:Name="PART_RightHeaderGripper" Grid.Column="4" HorizontalAlignment="Right" Width="1" BorderThickness="1"
BorderBrush="{Binding VerticalGridLinesBrush, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" Cursor="SizeWE"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="SortDirection" Value="Ascending">
<Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
<Setter TargetName="SortArrow" Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="180" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="SortDirection" Value="Descending">
<Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGridTemplateColumn.HeaderStyle>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<StackPanel Background="Gray" Margin="-5 0 0 0">
<TextBlock Foreground="White" FontWeight="Bold" Text="{Binding Path=Name, StringFormat=Gruppe: {0}}" Margin="10 5 0 5"/>
<ItemsPresenter />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<DockPanel Background="LightGray">
<TextBlock Text="{Binding Path=Name}" Foreground="Black" Margin="10 2 0 2"/>
<ItemsPresenter></ItemsPresenter>
</DockPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem x:Name="cmAddGroup" Header="Gruppe zuweisen" Click="cmAddGroup_Click" ></MenuItem>
<MenuItem x:Name="cmRemoveDeleteFlag" Header="Löschvermerk entfernen" Click="cmRemoveDeleteFlag_Click"></MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
让我解释一下:
"highlightConverter"检查单元格的值,并进行某种语法突出显示,语法检查并返回彩色TextBlock
如果我想编辑该TextBlock
我必须将其转换为TextBox
网格有两个组(我没有发布所有列,所以组不在这里,而是GroupStyle
)
两个有排序箭头,我也在这里添加了它们。在每一列标题上都有一个过滤器按钮来过滤行。
这让我想到了我的问题:网格在过滤、排序、调整行/列大小、重新排序列、滚动等方面变得非常慢。我认为这是因为TextBlock
和TextBox
项目。有没有更好的解决方案来提高性能?
这是亮点转换器.cs
public class HighlightConverter : IMultiValueConverter
{
public static Dictionary<String, SyntaxResult> calcFormulaCache;
public static Dictionary<String, SyntaxResult> matchExpressionCache;
public HighlightConverter()
{
calcFormulaCache = new Dictionary<string, SyntaxResult>();
matchExpressionCache = new Dictionary<string, SyntaxResult>();
}
ClientSettings clientSettings = new ClientSettings();
Brush[] colorArray;
Regex subFormula = new Regex(@"'w+'(')");
Regex sapFormula = new Regex(@"'w+'(([^)]+)')");
Regex strings = new Regex(@"''[^']+''");
Regex numerals = new Regex(@"'b[0-9'.]+'b");
Regex characteristic = new Regex(@"(?:)?'w+(?:)?");
Regex andOr = new Regex(@"( and )|( AND )|( or )|( OR )");
Regex not = new Regex(@"(not )|(NOT )");
VariantConfigurationTestDAO variantConfigurationTestDAO = new VariantConfigurationTestDAO();
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (!clientSettings.SyntaxCheck && !clientSettings.SyntaxCheck)
return values[0];
TextBlock textBlock = new TextBlock();
string input = values[0] as String;
if (!String.IsNullOrEmpty(input))
{
if (clientSettings.SyntaxHighlighting)
{
colorArray = new Brush[input.Length];
for (int i = 0; i < input.Length; i++)
colorArray[i] = Brushes.Black;
//Reihenfolge beibehalten!!
assignColor(Brushes.Blue, characteristic.Matches(input));
assignColor(Brushes.Black, andOr.Matches(input));
assignColor(Brushes.Black, numerals.Matches(input));
assignColor(Brushes.Orange, strings.Matches(input));
assignColor(Brushes.DeepPink, subFormula.Matches(input));
assignColor(Brushes.Green, sapFormula.Matches(input));
assignColor(Brushes.Green, not.Matches(input));
List<Char> splittedInput = input.ToCharArray().ToList();
int index = 0;
foreach (Char character in splittedInput)
{
textBlock.Inlines.Add(new Run(character.ToString()) { Foreground = colorArray[index] });
index++;
}
colorArray = null;
}
else
{
colorArray = null;
textBlock.Text = input;
}
if (clientSettings.SyntaxCheck)
{
Pen pen = new Pen(Brushes.Red, 3);
TextDecoration textDec = new TextDecoration(TextDecorationLocation.Underline, pen, 4, TextDecorationUnit.Pixel, TextDecorationUnit.FontRecommended);
if (!String.IsNullOrEmpty((String)parameter))
{
String para = (String)parameter;
SyntaxResult syntaxResult = null;
switch (para)
{
case "VARIANT":
if (para == "VARIANT")
{
if (characteristic.IsMatch(input) || subFormula.IsMatch(input))
{
if (andOr.IsMatch(input) || numerals.IsMatch(input) || strings.IsMatch(input) || sapFormula.IsMatch(input) || not.IsMatch(input))
{
textBlock.TextDecorations.Add(textDec);
textBlock.ToolTip = "Hier darf nur ein Merkmal oder eine Subformel stehen";
}
}
}
break;
case "CALCFORMULA":
if (!calcFormulaCache.ContainsKey(input))
calcFormulaCache.Add(input, variantConfigurationTestDAO.vcCalculateFormula3(input, true));
syntaxResult = calcFormulaCache[input];
break;
case "MATCHEXPRESSION":
if (!matchExpressionCache.ContainsKey(input))
matchExpressionCache.Add(input, variantConfigurationTestDAO.vcEvalMatchEx(input, true));
syntaxResult = matchExpressionCache[input];;
break;
default:
break;
}
if (syntaxResult != null)
{
if (syntaxResult.syntax > 0)
{
textBlock.TextDecorations.Add(textDec);
if (syntaxResult.errors.Count == 0)
textBlock.ToolTip = "Allgemeiner Syntaxfehler";
else
textBlock.ToolTip = String.Join(",", syntaxResult.errors);
}
}
}
if (values.Count() == 2)
{
string input2 = values[1] as String;
if (String.IsNullOrEmpty(input2))
{
textBlock.TextDecorations.Add(textDec);
textBlock.ToolTip = "Es müssen Variante und Kalkulationsformel gefüllt sein";
}
}
}
}
return textBlock;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private void assignColor(Brush brush, MatchCollection matchCollection)
{
foreach (Match match in matchCollection)
{
int start = match.Index;
int end = start + match.Length;
for (int i = start; i < end; i++)
{
colorArray[i] = brush;
}
}
}
}
,这不是使用IMultiConverter
的问题,而是Virtualization
和Column Rendering
的问题。
尝试对数据网格使用这些属性:
- 为网格启用 VirtualizingStackPanel.VirtualizationMode
- Set VirtualizingStackPanel.IsVirtualizing="true" for DataGrid
- 最大宽度="2560" 最大高度="1600"
切勿将 DataGrid 放在 ScrollViewer 中,因为您基本上会失去虚拟化。
例如:
<DataGrid ItemsSource="{Binding EmployeeDataTable, IsAsync=True}"
VirtualizingStackPanel.IsVirtualizing="true" EnableRowVirtualization="True"
EnableColumnVirtualization="True" MaxWidth="2560" MaxHeight="1600"
VirtualizingStackPanel.VirtualizationMode="Recycling"
VirtualizingPanel.IsVirtualizingWhenGrouping="True"/>
你有相当大的Convert
方法。假设它为 DataGrid 中的每个单元格调用。
-
尝试将语法分析带到另一个线程。对于用户来说,它看起来像 - 输入的文本并在几秒钟内检查和/或突出显示语法。
-
Regex.Matches
使用延迟初始化,因此当您遍历匹配项时 - 它实际上每次都基于正则表达式在字符串中执行搜索。尝试排除assignColor
Convert()
方法组并检查执行时间。如果有帮助 - 尝试编写自己的字符串解析器,不使用正则表达式。 -
在这一行中
List<Char> splittedInput = input.ToCharArray().ToList();
您将遍历input
字符两次。第一次 - 从字符串字符创建数组时,第二次 - 从数组项创建列表时。然后你在foreach (Char character in splittedInput)
中再次迭代这个字符串。您实际上可以遍历input
本身:foreach (var character in input)
。 -
在这一行中:
if (values.Count() == 2)
使用.Length
(数组的属性)而不是.Count()
(扩展 LINQ 方法),因为在每个时刻数组都知道它的长度,并且调用扩展 linq 方法会导致处理数组,就像处理IEnumerable
一样延迟初始化。
但在我看来,主要问题在于连续的文本分析。常见的解决方案是在并行线程中执行字符串分析 - 用于非暂停用户输入(或对此执行任何操作)。