Skip to content

Instantly share code, notes, and snippets.

@kosmakoff
Last active August 29, 2015 14:08
Show Gist options
  • Save kosmakoff/04913ac80f7c29f539a0 to your computer and use it in GitHub Desktop.
Save kosmakoff/04913ac80f7c29f539a0 to your computer and use it in GitHub Desktop.
Custom TextBlock for WPF with specific measuring tweaks
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;
namespace TextBlockEx
{
[ContentProperty("Text")]
public class TextBlockExt : FrameworkElement
{
private string _stringToRender = string.Empty;
private bool _useEllipsis = false;
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text", typeof (string), typeof (TextBlockExt), new PropertyMetadata(default(string)));
public string Text
{
get { return (string) GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register(
"Background", typeof (Brush), typeof (TextBlockExt), new PropertyMetadata(Brushes.Transparent));
public Brush Background
{
get { return (Brush) GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
"Foreground", typeof (Brush), typeof (TextBlockExt), new PropertyMetadata(Brushes.Black));
public Brush Foreground
{
get { return (Brush) GetValue(ForegroundProperty); }
set { SetValue(ForegroundProperty, value); }
}
/// <summary>
/// When overridden in a derived class, participates in rendering operations that are directed by the layout system. The rendering instructions for this element are not used directly when this method is invoked, and are instead preserved for later asynchronous use by layout and drawing.
/// </summary>
/// <param name="drawingContext">The drawing instructions for a specific element. This context is provided to the layout system.</param>
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
var textToRender = _stringToRender + (_useEllipsis ? "..." : string.Empty);
var ft = new FormattedText(textToRender, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
new Typeface(SystemFonts.CaptionFontFamily, SystemFonts.CaptionFontStyle, SystemFonts.CaptionFontWeight,
FontStretches.Normal), SystemFonts.CaptionFontSize, Foreground);
drawingContext.DrawRectangle(Background, null, new Rect(new Size(ActualWidth, ActualHeight)));
drawingContext.DrawText(ft, new Point(0, 0));
}
/// <summary>
/// When overridden in a derived class, measures the size in layout required for child elements and determines a size for the <see cref="T:System.Windows.FrameworkElement"/>-derived class.
/// </summary>
/// <returns>
/// The size that this element determines it needs during layout, based on its calculations of child element sizes.
/// </returns>
/// <param name="availableSize">The available size that this element can give to child elements. Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param>
protected override Size MeasureOverride(Size availableSize)
{
_stringToRender = Text;
_useEllipsis = false;
var ft = new FormattedText(_stringToRender, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
new Typeface(SystemFonts.CaptionFontFamily, SystemFonts.CaptionFontStyle, SystemFonts.CaptionFontWeight,
FontStretches.Normal), SystemFonts.CaptionFontSize, Foreground);
ft.Trimming = TextTrimming.None;
while (ft.Width > availableSize.Width)
{
_stringToRender = _stringToRender.Substring(0, _stringToRender.Length - 1);
_useEllipsis = true;
ft = new FormattedText(_stringToRender + "...", CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
new Typeface(SystemFonts.CaptionFontFamily, SystemFonts.CaptionFontStyle, SystemFonts.CaptionFontWeight,
FontStretches.Normal), SystemFonts.CaptionFontSize, Foreground);
}
var size = new Size(
_useEllipsis ? availableSize.Width : ft.Width,
Math.Min(availableSize.Height, ft.Height));
return size;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment