如何改进自定义突出显示文本控制

时间:2016-03-03 16:55:05

标签: wpf custom-controls

我有一个自定义控件,它使用文本块并根据控件上的属性突出显示文本。当控件在数据网格中使用时,网格的滚动很慢。基于控件的代码,特别是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


}

0 个答案:

没有答案