I love WPF

"jamais sans son interface"

I love WPF

"jamais sans son interface"

TextBlock with ellipsis at left or center

If you want a TextBlock with ellipsis a Left, Center or Right use this
you must use TrimmedText in place of Text for binding original text

 [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
    public enum EllipsisPosition
    {
        //
        // Résumé :
        //     Par défaut. elispsis sur la droite.
        Right = 0,
        //
        // Résumé :
        //     elispsis sur la gauche
        Left = 1,
        //
        // Résumé :
        //     elispsis an centre.
        Center = 2,
    }

    public class TextBlockTrim : TextBlock
    {
        private const string ELLIPSIS = "...";

        #region static
        static TextBlockTrim()
        {
            TextAlignmentProperty.OverrideMetadata(typeof(TextBlockTrim),
                new FrameworkPropertyMetadata(
                    TextAlignment.Left,
                    FrameworkPropertyMetadataOptions.Inherits,
                    (sender, e) => ((TextBlockTrim)sender)._Changed(e)));
            VisibilityProperty.OverrideMetadata(typeof(TextBlockTrim), 
                new FrameworkPropertyMetadata( 
                    Visibility.Visible, 
                    FrameworkPropertyMetadataOptions.Inherits, 
                   (sender, e) => ((TextBlockTrim)sender)._visibility(e)));
        }
        #endregion

        public TextBlockTrim()
        {
            this.SizeChanged += (ss, ee) => UpdateText();
            this.TextTrimming = TextTrimming.CharacterEllipsis;
        }

        #region TextAlignmentChanged
        private bool protect = false;
        private void _Changed(DependencyPropertyChangedEventArgs e)
        {
            if (protect) return;
            switch (e.NewValue)
            {
                case TextAlignment ta:
                    previousTextAligment = ta;
                    UpdateText();
                    break;
                case string s:
                    UpdateText(s);
                    break;
                case EllipsisPosition ep:
                    UpdateText();
                    break;
                default:
                    throw new Exception("Unknow type");
            }
        }
        #endregion

        #region VisibilityChanged
        private void _visibility(DependencyPropertyChangedEventArgs e)
        {
            UpdateText();
        }
        #endregion

        #region EllipsisPosition
        public EllipsisPosition EllipsisPosition
        {
            get { return (EllipsisPosition)GetValue(EllipsisPositionProperty); }
            set { SetValue(EllipsisPositionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for EllipsisPosition.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EllipsisPositionProperty =
            DependencyProperty.Register("EllipsisPosition",
                typeof(EllipsisPosition),
                typeof(TextBlockTrim),
                new FrameworkPropertyMetadata(EllipsisPosition.Right,
                     (sender, e) => ((TextBlockTrim)sender)._Changed(e)));
        #endregion

        #region TrimmedText (DP SHORT)
        public string TrimmedText { get { return (string)GetValue(TrimmedTextProperty); } set { SetValue(TrimmedTextProperty, value); } }
        public static readonly DependencyProperty TrimmedTextProperty = DependencyProperty.Register(
            "TrimmedText",
            typeof(string),
            typeof(TextBlockTrim),
            new FrameworkPropertyMetadata(null,
                (sender, e) => ((TextBlockTrim)sender)._Changed(e)));
        #endregion

        #region UpdateText

        string previousText = null;
        TextAlignment previousTextAligment = TextAlignment.Left;

        private void UpdateText(string newText = null)
        {
            if (newText != null)
                previousText = newText;
            if (previousText == null)
            {
                Text = null;
                return;
            }
            if (this.ActualWidth == 0) return;
            try
            {
                string str = previousText;
                if (!string.IsNullOrEmpty(previousText))
                {
                    double w = MeasureText(previousText, this).Width;
                    double width = ActualWidth;
                    if (w > width && width != 0)
                    {
                        ToolTip = previousText;
                        switch (EllipsisPosition)
                        {
                            case EllipsisPosition.Right:
                                {
                                    do
                                    {
                                        str = str.Substring(1);
                                        w = MeasureText(ELLIPSIS + str, this).Width;
                                    } while (w > width);
                                    str = ELLIPSIS + str;
                                    protect = true;
                                    TextAlignment = TextAlignment.Left;
                                    protect = false;                                  
                                }
                                break;
                            case EllipsisPosition.Left:
                                {
                                    int size = str.Length;
                                    do
                                    {
                                        str = str.Substring(0, size);
                                        w = MeasureText(str + ELLIPSIS, this).Width;
                                        size--;
                                    } while (w > width);
                                    str = str + ELLIPSIS;
                                    protect = true;
                                    TextAlignment = TextAlignment.Right;
                                    protect = false;
                                }
                                break;
                            case EllipsisPosition.Center:
                                {
                                    string l, r, t;
                                    {
                                        int size = str.Length / 2;
                                        int pos = size;
                                        do
                                        {
                                            l = str.Substring(0, size);
                                            r = str.Substring(pos);
                                            t = l + ELLIPSIS + r;
                                            w = MeasureText(t, this).Width;
                                            size--; pos++;
                                        } while (w > width);
                                        str = t;
                                    }
                                    protect = true;
                                    TextAlignment = TextAlignment.Center;
                                    protect = false;
                                }
                                break;
                        }
                    }
                    else
                    {
                        ToolTip = null;
                        protect = true;
                        TextAlignment = previousTextAligment;
                        protect = false;
                    }
                }
                Text = str;
            }
            catch { Text = null; }
        }

        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            base.OnRenderSizeChanged(sizeInfo);
            UpdateText();
        }

        #endregion

        #region Static functions
        public static Size MeasureText(string text, TextBlock textBlock)
        {
            return MeasureText(text, textBlock.FontFamily, 
                textBlock.FontStyle, 
                textBlock.FontWeight, 
                textBlock.FontStretch, 
                textBlock.FontSize,
                textBlock);
        }

        public static Size MeasureText(string text, 
            FontFamily fontFamily, 
            FontStyle fontStyle, 
            FontWeight fontWeight, 
            FontStretch fontStretch, 
            double fontSize,
            Visual reference)
        {
            Typeface typeface = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch);
            GlyphTypeface glyphTypeface;

            if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
            {
                return MeasureTextSize(text, fontFamily, fontStyle, fontWeight, fontStretch, fontSize, reference);
            }

            double totalWidth = 0;
            double height = 0;

            for (int n = 0; n < text.Length; n++)
            {
                ushort glyphIndex = glyphTypeface.CharacterToGlyphMap];

                double width = glyphTypeface.AdvanceWidths[glyphIndex] * fontSize;

                double glyphHeight = glyphTypeface.AdvanceHeights[glyphIndex] * fontSize;

                if (glyphHeight > height)
                {
                    height = glyphHeight;
                }

                totalWidth += width;
            }

            return new Size(totalWidth, height);
        }

        public static Size MeasureTextSize(string text, 
            FontFamily fontFamily, 
            FontStyle fontStyle, 
            FontWeight fontWeight, 
            FontStretch fontStretch, 
            double fontSize,
            Visual reference)
        {            
            FormattedText ft = new FormattedText(text,
                                    CultureInfo.CurrentCulture,
                                    FlowDirection.LeftToRight,
                                    new Typeface(fontFamily, fontStyle, fontWeight, fontStretch),
                                    fontSize,
                                    Brushes.Black,
                                    VisualTreeHelper.GetDpi(reference).PixelsPerDip);
            return new Size(ft.Width, ft.Height);
        }
        #endregion
    }

and use like this

 <Grid>
        <TextBlock HorizontalAlignment="Left"
                   Margin="10,18,0,0"
                   TextWrapping="Wrap"
                   Text="elipsis left"
                   FontWeight="Bold"
                   VerticalAlignment="Top"
                   Width="118" />
        <TextBlockTrim Background="Aqua"
                       TrimmedText="123456789 123456789 123456789 123456789"
                       Margin="10,39,9.6,0"
                       EllipsisPosition="Left"
                       TextWrapping="Wrap"
                       VerticalAlignment="Top"
                       Visibility="Visible" />
        <TextBlockTrim Background="Aqua"
                       TrimmedText="123456789 123456789 123456789 123456789"
                       TextAlignment="Center"
                       EllipsisPosition="Left"
                       Margin="10,60,9.6,0"
                       TextWrapping="Wrap"
                       VerticalAlignment="Top"
                       Visibility="Visible" />
        <TextBlockTrim Background="Aqua"
                       TrimmedText="123456789 123456789 123456789 123456789"
                       Margin="10,81,9.6,0"
                       TextAlignment="Right"
                       EllipsisPosition="Left"
                       TextWrapping="Wrap"
                       VerticalAlignment="Top"
                       Visibility="Visible" />
        <TextBlock HorizontalAlignment="Left"
                   Margin="10,108,0,0"
                   TextWrapping="Wrap"
                   Text="elipsis right"
                   FontWeight="Bold"
                   VerticalAlignment="Top"
                   Width="118" />
        <TextBlockTrim Background="Aqua"
                       TrimmedText="123456789 123456789 123456789 123456789"
                       Margin="10,130,9.6,0"
                       TextWrapping="Wrap"
                       VerticalAlignment="Top"
                       Visibility="Visible" />
        <TextBlockTrim Background="Aqua"
                       TrimmedText="123456789 123456789 123456789 123456789"
                       TextAlignment="Center"
                       Margin="10,151,9.6,0"
                       TextWrapping="Wrap"
                       VerticalAlignment="Top"
                       Visibility="Visible" />
        <TextBlockTrim Background="Aqua"
                       TrimmedText="123456789 123456789 123456789 123456789"
                       Margin="10,172,9.6,0"
                       TextAlignment="Right"
                       TextWrapping="Wrap"
                       VerticalAlignment="Top"
                       Visibility="Visible" />
        <TextBlock HorizontalAlignment="Left"
                   Margin="10,204,0,0"
                   TextWrapping="Wrap"
                   Text="elipsis center"
                   FontWeight="Bold"
                   VerticalAlignment="Top"
                   Width="118" />
        <TextBlockTrim Background="Aqua"
                       TrimmedText="123456789 123456789 123456789 123456789"
                       Margin="10,226,9.6,0"
                       EllipsisPosition="Center"
                       TextWrapping="Wrap"
                       VerticalAlignment="Top" />
        <TextBlockTrim Background="Aqua"
                       TrimmedText="123456789 123456789 123456789 123456789"
                       EllipsisPosition="Center"
                       TextAlignment="Center"
                       Margin="10,247,9.6,0"
                       TextWrapping="Wrap"
                       VerticalAlignment="Top"
                       Visibility="Visible" />
        <TextBlockTrim Background="Aqua"
                       TrimmedText="123456789 123456789 123456789 123456789"
                       Margin="10,268,9.6,0"
                       EllipsisPosition="Center"
                       TextAlignment="Right"
                       TextWrapping="Wrap"
                       VerticalAlignment="Top"
                       Visibility="Visible" />
    </Grid>

see result

   

Update to v2 : 
refresh when visibility changed
refresh when size changed

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Retour en haut