我为我的datagrid开发了一些syntaxhighlighting和syntaxchecking:
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 = ClientSettings.getInstance();
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 )");
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (!clientSettings.SyntaxCheck && !clientSettings.SyntaxHighlighting || String.IsNullOrEmpty(values[0] as String))
return values[0];
SAPConnector sapConnector = SAPConnector.getInstance();
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.Brown, strings.Matches(input));
assignColor(Brushes.DeepPink, subFormula.Matches(input));
assignColor(Brushes.Green, sapFormula.Matches(input));
assignColor(Brushes.Green, not.Matches(input));
int index = 0;
foreach (Char character in input)
{
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":
try
{
if (!calcFormulaCache.ContainsKey(input))
calcFormulaCache.Add(input, sapConnector.variantConfigurationTestDAO.vcCalculateFormula3(input, true));
syntaxResult = calcFormulaCache[input];
}
catch (Exception ex)
{
textBlock.TextDecorations.Add(textDec);
textBlock.ToolTip = "Syntaxüberprüfung fehlgeschlagen: " + ex.Message;
Logger.getInstance().writeLogEntry(Logger.LogLevel.ERROR, String.Format("Syntaxcheckfehler: Die Kalkulationsformel '{0}' konnte nicht überprüft werden --> {1}", input, ex.Message), ex.StackTrace);
}
break;
case "MATCHEXPRESSION":
try
{
if (!matchExpressionCache.ContainsKey(input))
matchExpressionCache.Add(input, sapConnector.variantConfigurationTestDAO.vcEvalMatchEx(input, true));
syntaxResult = matchExpressionCache[input];
}
catch (Exception ex)
{
textBlock.TextDecorations.Add(textDec);
textBlock.ToolTip = "Syntaxüberprüfung fehlgeschlagen: " + ex.Message;
Logger.getInstance().writeLogEntry(Logger.LogLevel.ERROR, String.Format("Syntaxcheckfehler: Die Ausdrucksformel '{0}' konnte nicht überprüft werden --> {1}", input, ex.Message), ex.StackTrace);
}
break;
default:
break;
}
if (syntaxResult != null)
{
if (syntaxResult.syntax > 0)
{
textBlock.TextDecorations.Add(textDec);
if (syntaxResult.errors.Count == 0)
textBlock.ToolTip = "Allgemeiner Syntaxfehler";
else
{
List<String> groupedErrors = new List<String>();
foreach (String error in syntaxResult.errors)
{
if (groupedErrors.FirstOrDefault(x => x == error) == null)
groupedErrors.Add(error);
}
textBlock.ToolTip = String.Join(Environment.NewLine, groupedErrors);
}
}
}
}
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";
}
}
}
}
ToolTipService.SetShowDuration(textBlock, 999999);
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;
}
}
}
}
它基本上有效。问题是它变得非常缓慢,因为在我看来有两个原因:每一行都需要一个转换器调用,我将每一个字符串分开,然后将一个文本块内联到它(很多垃圾?)
这是我的xaml datagrid的一列:
<DataGridTextColumn Binding="{Binding TopLevelGroup, IsAsync=False}" x:Name="cTopLevelGroup" MinWidth="150" Visibility="Visible">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Padding="5 0" Content="Gruppe" FontWeight="Bold" VerticalAlignment="Center" Cursor="Hand" Foreground="White"/>
<TextBox x:Name="txtTopGroupFilter" Margin="0 5" Grid.Column="2" Width="150" Visibility="Collapsed"/>
<Button Grid.Column="3" Margin="5 0" x:Name="btnFilterTopGroup" Style="{StaticResource MyButton}" Width="16" Height="16" VerticalAlignment="Center" HorizontalAlignment="Right" Click="btnFilterTopGroup_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="3"
HorizontalAlignment="Right"
Width="2" 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>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
和datagrid本身:
<DataGrid x:Name="dgVarConfig"
ItemsSource="{Binding VarConfigList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedVarConfig, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="10,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"
VirtualizingPanel.IsVirtualizing="true"
EnableRowVirtualization="True"
EnableColumnVirtualization="false"
VirtualizingPanel.VirtualizationMode="Recycling"
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
ScrollViewer.CanContentScroll="False"
>
是否有任何变化可以让它更快一点?越多,我得到的越慢。此刻大约有500行,但这种增长非常非常快。