我有一个自定义控件,它使用文本块并根据控件上的属性突出显示文本。当控件在数据网格中使用时,网格的滚动很慢。基于控件的代码,特别是OnRender方法,可以采取哪些措施来加快控制速度。您可以提供的任何帮助表示赞赏。
更新 抱歉,我不得不删除以前使用TextBlock的代码,编辑时间过长。
我已经放弃使用TextBlock来提供hilite支持。相反,我使用FrameworkElement作为控件的基类,并将文本绘制为OnRender方法。这大大提高了数据网格的滚动速度。我不确定这是否是提供任何帮助的最佳方式,我们将不胜感激。
命名空间
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
代码
public class SearchableTextControl : FrameworkElement, IDisposable
{
#region Constructors
static SearchableTextControl ()
{
try
{
DefaultStyleKeyProperty.OverrideMetadata ( typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( typeof ( SearchableTextControl ) ) );
}
catch ( Exception ex )
{
LogProvider.Logger.LogException ( "Error during static SearchableTextControl()", ex );
throw;
}
}
public SearchableTextControl ()
{
Id = Guid.NewGuid ();
}
~SearchableTextControl ()
{
Dispose ( false );
}
#endregion
#region Properties
protected string DisplayText
{
get
{
var displayText = Text;
// format if needed
if ( DataFormatString != null && !string.IsNullOrEmpty ( Text ) )
{
DateTime timeTmp;
if ( DateTime.TryParse ( Text, out timeTmp ) )
displayText = timeTmp.ToString ( DataFormatString );
else
displayText = string.Format ( DataFormatString, Text );
}
return displayText;
}
}
public Guid Id
{ get; private set; }
object _syncLock = new object ();
public object SyncLock
{
get { return _syncLock; }
}
#endregion
#region Dependency Properties
public bool IsMatch
{
get { return ( bool ) GetValue ( IsMatchProperty ); }
set
{
SetValue ( IsMatchProperty, value );
}
}
public static readonly DependencyProperty IsMatchProperty =
DependencyProperty.Register ( "IsMatch", typeof ( bool ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( null ) );
public string Text
{
get
{
string text = null;
var val = GetValue ( TextProperty );
try
{
var valStr = val as string;
if ( valStr != null )
text = valStr;
else if ( val != null )
text = val.ToString ();
}
catch
{
text = null;
}
return text;
}
set { SetValue ( TextProperty, value ); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register ( "Text", typeof ( string ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( string.Empty, FrameworkPropertyMetadataOptions.AffectsRender ) );
public FontFamily FontFamily
{
get { return ( FontFamily ) GetValue ( FontFamilyProperty ); }
set
{
SetValue ( FontFamilyProperty, value );
}
}
public static readonly DependencyProperty FontFamilyProperty =
DependencyProperty.Register ( "FontFamily", typeof ( FontFamily ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( new FontFamily ( "Segoe UI" ), FrameworkPropertyMetadataOptions.AffectsRender ) );
public FontStyle FontStyle
{
get { return ( FontStyle ) GetValue ( FontStyleProperty ); }
set
{
SetValue ( FontStyleProperty, value );
}
}
public static readonly DependencyProperty FontStyleProperty =
DependencyProperty.Register ( "FontStyle", typeof ( FontStyle ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( FontStyles.Normal, FrameworkPropertyMetadataOptions.AffectsRender ) );
public FontWeight FontWeight
{
get { return ( FontWeight ) GetValue ( FontWeightProperty ); }
set
{
SetValue ( FontWeightProperty, value );
}
}
public static readonly DependencyProperty FontWeightProperty =
DependencyProperty.Register ( "FontWeight", typeof ( FontWeight ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( FontWeights.Regular, FrameworkPropertyMetadataOptions.AffectsRender ) );
public FontStretch FontStretch
{
get { return ( FontStretch ) GetValue ( FontStretchProperty ); }
set
{
SetValue ( FontStretchProperty, value );
}
}
public static readonly DependencyProperty FontStretchProperty =
DependencyProperty.Register ( "FontStretch", typeof ( FontStretch ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( FontStretches.Normal, FrameworkPropertyMetadataOptions.AffectsRender ) );
public double FontSize
{
get { return ( double ) GetValue ( FontSizeProperty ); }
set
{
SetValue ( FontSizeProperty, value );
}
}
public static readonly DependencyProperty FontSizeProperty =
DependencyProperty.Register ( "FontSize", typeof ( double ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( 12.0, FrameworkPropertyMetadataOptions.AffectsRender ) );
public string DataFormatString
{
get { return ( string ) GetValue ( DataFormatStringProperty ); }
set { SetValue ( DataFormatStringProperty, value ); }
}
public static readonly DependencyProperty DataFormatStringProperty =
DependencyProperty.Register ( "DataFormatString", typeof ( string ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( null, FrameworkPropertyMetadataOptions.AffectsRender ) );
public Brush HiLiteBackground
{
get { return ( Brush ) GetValue ( HiLiteBackgroundProperty ); }
set { SetValue ( HiLiteBackgroundProperty, value ); }
}
public static readonly DependencyProperty HiLiteBackgroundProperty =
DependencyProperty.Register ( "HiLiteBackground", typeof ( Brush ), typeof ( SearchableTextControl ),
new UIPropertyMetadata ( Brushes.Yellow ) );
public Brush HiLiteForeground
{
get { return ( Brush ) GetValue ( HiLiteForegroundProperty ); }
set { SetValue ( HiLiteForegroundProperty, value ); }
}
public static readonly DependencyProperty HiLiteForegroundProperty =
DependencyProperty.Register ( "HiLiteForeground", typeof ( Brush ), typeof ( SearchableTextControl ),
new UIPropertyMetadata ( Brushes.Red ) );
public Brush Background
{
get { return ( Brush ) GetValue ( BackgroundProperty ); }
set { SetValue ( BackgroundProperty, value ); }
}
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.Register ( "Background", typeof ( Brush ), typeof ( SearchableTextControl ),
new UIPropertyMetadata ( Brushes.White ) );
public Brush Foreground
{
get { return ( Brush ) GetValue ( ForegroundProperty ); }
set { SetValue ( ForegroundProperty, value ); }
}
public static readonly DependencyProperty ForegroundProperty =
DependencyProperty.Register ( "Foreground", typeof ( Brush ), typeof ( SearchableTextControl ),
new UIPropertyMetadata ( Brushes.Black ) );
public bool MatchCase
{
get { return ( bool ) GetValue ( MatchCaseProperty ); }
set { SetValue ( MatchCaseProperty, value ); }
}
public static readonly DependencyProperty MatchCaseProperty =
DependencyProperty.Register ( "MatchCase", typeof ( bool ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( false, FrameworkPropertyMetadataOptions.AffectsRender ) );
public bool MatchWholeWord
{
get { return ( bool ) GetValue ( MatchWholeWordProperty ); }
set { SetValue ( MatchWholeWordProperty, value ); }
}
public static readonly DependencyProperty MatchWholeWordProperty =
DependencyProperty.Register ( "MatchWholeWord", typeof ( bool ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( false, FrameworkPropertyMetadataOptions.AffectsRender ) );
public bool HiLiteEnabled
{
get { return ( bool ) GetValue ( HiLiteEnabledProperty ); }
set { SetValue ( HiLiteEnabledProperty, value ); }
}
public static readonly DependencyProperty HiLiteEnabledProperty =
DependencyProperty.Register ( "HiLiteEnabled", typeof ( bool ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( true, FrameworkPropertyMetadataOptions.AffectsRender ) );
public string SearchText
{
get { return ( string ) GetValue ( SearchTextProperty ); }
set { SetValue ( SearchTextProperty, value ); }
}
public static readonly DependencyProperty SearchTextProperty =
DependencyProperty.Register ( "SearchText", typeof ( string ), typeof ( SearchableTextControl ),
new FrameworkPropertyMetadata ( string.Empty, FrameworkPropertyMetadataOptions.AffectsRender ) );
#region HiLiteFontWeight
public FontWeight HiLiteFontWeight
{
get { return ( FontWeight ) GetValue ( HiLiteFontWeightProperty ); }
set { SetValue ( HiLiteFontWeightProperty, value ); }
}
public static readonly DependencyProperty HiLiteFontWeightProperty =
DependencyProperty.Register (
"HiLiteFontWeight",
typeof ( FontWeight ),
typeof ( SearchableTextControl ),
new PropertyMetadata ( FontWeights.Normal ) );
#endregion
#endregion
#region Overrides
protected FormattedText FormattedText
{ get; set; }
protected override Size ArrangeOverride ( Size finalSize )
{
var ft = GenerateFormattedText ( DisplayText, false );
return new Size ( ft.Width, ft.Height );
}
protected override Size MeasureOverride ( Size availableSize )
{
var ft = GenerateFormattedText ( DisplayText, false );
return new Size ( ft.Width, ft.Height );
}
protected override void OnRender ( DrawingContext dc )
{
try
{
if ( !IsVisible )
return;
dc.DrawRectangle ( Background, null, new Rect ( 0.0, 0.0, ActualWidth, ActualHeight ) );
// if no text move on
var text = DisplayText;
if ( text == null )
return;
double x = 0;
FormattedText ft = null;
if ( !HiLiteEnabled || string.IsNullOrEmpty ( SearchText ) )
{
ft = GenerateFormattedText ( DisplayText, false );
dc.DrawText ( ft, new Point ( x, 0 ) );
return;
}
Trace ( "SearchableTextControl.Update Text: " + Text + " SearchText: " + SearchText + " HiLiteEnabled: " + HiLiteEnabled + " MatchCase: " + MatchCase );
string searchText = null, compareText = null;
if ( !MatchWholeWord )
{
searchText = MatchCase ? ( string ) SearchText : SearchText.ToLower ();
compareText = MatchCase ? Text : Text.ToLower ();
}
else
{
searchText = SearchText;
compareText = Text;
}
var displayText = text;
int pos = -1;
bool hilite = false;
if ( !string.IsNullOrEmpty ( searchText ) )
{
if ( !MatchWholeWord )
{
int searchLength = searchText.Length;
while ( ( pos = compareText.IndexOf ( searchText ) ) >= 0 )
{
ft = GenerateFormattedText( displayText.Substring ( 0, pos ), false );
if ( ft != null )
{
dc.DrawText ( ft, new Point ( x, 0 ) );
x += ft.Width;
}
ft = GenerateFormattedText ( displayText.Substring ( pos, searchLength ), true );
if ( ft != null )
{
dc.DrawRectangle ( HiLiteBackground, null, new Rect ( x, 0, ft.Width, ft.Height ) );
dc.DrawText ( ft, new Point ( x, 0 ) );
x += ft.Width;
}
compareText = compareText.Substring ( pos + searchLength );
displayText = displayText.Substring ( pos + searchLength );
}
}
else
{
if ( searchText == compareText )
hilite = true;
}
ft = GenerateFormattedText ( displayText, hilite );
if ( ft != null )
dc.DrawText ( ft, new Point ( x, 0 ) );
}
}
catch ( Exception ex )
{
LogProvider.Logger.LogException ( "Error during searchable text control onrender", ex );
}
}
#endregion
#region Event Handlers
#endregion
#region Support Methods
public virtual void Release ()
{
}
private FormattedText GenerateFormattedText ( string text, bool isHiLite )
{
var background = isHiLite ? HiLiteBackground : Background;
var foreground = isHiLite ? HiLiteForeground : Foreground;
// Set the source text with the style which is Italic.
var fontStyle = isHiLite ? FontStyles.Italic : FontStyles.Normal;
// Set the source text with the style which is Bold.
var fontWeight = isHiLite ? HiLiteFontWeight : FontWeights.Normal;
var typeface = new Typeface ( FontFamily, fontStyle, fontWeight, FontStretch );
// Create formatted text--in a particular font at a particular size
var ft = new FormattedText (
text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
typeface,
FontSize,
foreground );
ft.TextAlignment = TextAlignment.Left;
return ft;
}
private void Trace ( string msg )
{
//Debug.WriteLine( msg );
}
#endregion
#region IDisposable
public bool IsDisposed
{ get; private set; }
public void Dispose ()
{
Dispose ( true );
GC.SuppressFinalize ( this );
}
private void Dispose ( bool disposing )
{
if ( IsDisposed || !disposing )
return;
lock ( SyncLock )
{
IsDisposed = true;
Release ();
}
}
#endregion
}