4 using System.Collections.Generic;
5 using System.ComponentModel;
6 using System.Globalization;
9 using System.Threading;
11 using System.Windows.Controls;
12 using System.Windows.Input;
13 using System.Windows.Media;
15 namespace SiliconStudio.Presentation.Controls
28 [TemplatePart(Name =
"PART_TrimmedText", Type = typeof(TextBlock))]
31 private TextBlock trimmedTextBlock;
32 private readonly Timer validationTimer;
37 public static readonly DependencyProperty UseTimedValidationProperty = DependencyProperty.Register(
"UseTimedValidation", typeof(
bool), typeof(
TextBox),
new PropertyMetadata(
false, OnUseTimedValidationPropertyChanged));
42 public static readonly DependencyProperty ValidationDelayProperty = DependencyProperty.Register(
"ValidationDelay", typeof(
int), typeof(
TextBox),
new PropertyMetadata(500));
47 public static readonly DependencyPropertyKey TrimmedTextPropertyKey = DependencyProperty.RegisterReadOnly(
"TrimmedText", typeof(
string), typeof(
TextBox),
new PropertyMetadata(
""));
52 public static readonly DependencyProperty WatermarkContentProperty = DependencyProperty.Register(
"WatermarkContent", typeof(
object), typeof(
TextBox),
new PropertyMetadata(null));
57 public static readonly DependencyProperty WatermarkContentTemplateProperty = DependencyProperty.Register(
"WatermarkContentTemplate", typeof(DataTemplate), typeof(
TextBox),
new PropertyMetadata(null));
62 public static readonly DependencyProperty TextTrimmingProperty = DependencyProperty.Register(
"TextTrimming", typeof(TextTrimming), typeof(
TextBox),
new PropertyMetadata(TextTrimming.None));
67 public static readonly DependencyProperty TrimmingSourceProperty = DependencyProperty.Register(
"TrimmingSource", typeof(
TrimmingSource), typeof(
TextBox),
new PropertyMetadata(
TrimmingSource.End));
72 public static readonly DependencyProperty TrimmedTextProperty = TrimmedTextPropertyKey.DependencyProperty;
77 public static RoutedCommand ClearTextCommand {
get;
private set; }
81 DefaultStyleKeyProperty.OverrideMetadata(typeof(
TextBox),
new FrameworkPropertyMetadata(typeof(
TextBox)));
82 ClearTextCommand =
new RoutedCommand(
"ClearTextCommand", typeof(System.Windows.Controls.TextBox));
83 CommandManager.RegisterClassCommandBinding(typeof(System.Windows.Controls.TextBox),
new CommandBinding(ClearTextCommand, OnClearTextCommand));
88 WordSeparators =
" \t";
89 if (DesignerProperties.GetIsInDesignMode(
this) ==
false)
90 validationTimer =
new Timer(x => Dispatcher.InvokeAsync(Validate), null, Timeout.Infinite, Timeout.Infinite);
96 public bool UseTimedValidation {
get {
return (
bool)GetValue(UseTimedValidationProperty); } set { SetValue(UseTimedValidationProperty, value); } }
103 public int ValidationDelay {
get {
return (
int)GetValue(ValidationDelayProperty); } set { SetValue(ValidationDelayProperty, value); } }
108 public string TrimmedText {
get {
return (
string)GetValue(TrimmedTextPropertyKey.DependencyProperty); }
private set { SetValue(TrimmedTextPropertyKey, value); } }
113 public object WatermarkContent {
get {
return GetValue(WatermarkContentProperty); } set { SetValue(WatermarkContentProperty, value); } }
118 public DataTemplate WatermarkContentTemplate {
get {
return (DataTemplate)GetValue(WatermarkContentTemplateProperty); } set { SetValue(WatermarkContentTemplateProperty, value); } }
123 public TextTrimming TextTrimming {
get {
return (TextTrimming)GetValue(TextTrimmingProperty); } set { SetValue(TextTrimmingProperty, value); } }
133 public string WordSeparators {
get; set; }
138 base.OnApplyTemplate();
140 trimmedTextBlock = GetTemplateChild(
"PART_TrimmedText") as TextBlock;
141 if (trimmedTextBlock == null)
142 throw new InvalidOperationException(
"A part named 'PART_TrimmedText' must be present in the ControlTemplate, and must be of type 'TextBlock'.");
152 if (UseTimedValidation)
154 if (ValidationDelay > 0.0)
156 if (validationTimer != null)
157 validationTimer.Change(ValidationDelay, Timeout.Infinite);
165 var availableWidth = ActualWidth;
166 if (trimmedTextBlock != null)
167 availableWidth -= trimmedTextBlock.Margin.Left + trimmedTextBlock.Margin.Right;
169 PerformEllipsis(availableWidth);
174 var arrangedSize = base.ArrangeOverride(arrangeBounds);
175 var availableWidth = arrangeBounds.Width;
176 if (trimmedTextBlock != null)
177 availableWidth -= trimmedTextBlock.Margin.Left + trimmedTextBlock.Margin.Right;
179 PerformEllipsis(availableWidth);
183 private void PerformEllipsis(
double availableWidth)
185 if (TextTrimming == TextTrimming.None)
197 var textWidth = GetTextWidth(Text, out sizes);
198 if (availableWidth >= textWidth)
206 switch (TextTrimming)
208 case TextTrimming.CharacterEllipsis:
209 text = Text.ToCharArray().Select(c => c.ToString(CultureInfo.InvariantCulture)).ToArray();
211 case TextTrimming.WordEllipsis:
212 text = SplitWords(Text);
215 throw new ArgumentException(
"Invalid 'TextTrimming' argument.");
218 const string Ellipsis =
"...";
221 var n = text.Length - 1;
222 var sb =
new StringBuilder();
228 var starting = sb.ToString();
230 var currentWidth = GetTextWidth(starting);
234 var test = currentWidth + sizes[n];
236 if (test > availableWidth)
239 sb.Insert(0, text[n--]);
243 TrimmedText = string.Format(
"{0}{1}", starting, sb);
247 var currentWidth = GetTextWidth(Ellipsis);
249 var n2 = text.Length - 1;
251 var begin =
new StringBuilder();
252 var end =
new StringBuilder();
256 var test = currentWidth + sizes[n1] + sizes[n2];
258 if (test > availableWidth)
261 begin.Append(text[n1++]);
262 end.Insert(0, text[n2--]);
267 TrimmedText = string.Format(
"{0}{2}{1}", begin, end, Ellipsis);
272 var sb =
new StringBuilder();
276 sb.Insert(0, Ellipsis);
277 var ending = sb.ToString();
279 var currentWidth = GetTextWidth(ending);
283 var test = currentWidth + sizes[n];
285 if (test > availableWidth)
288 sb.Append(text[n++]);
292 TrimmedText = string.Format(
"{0}{1}", sb, ending);
296 private double GetTextWidth(
string text)
299 return GetTextWidth(text, out dummy);
302 private double GetTextWidth(
string text, out
double[] sizes)
304 var typeface =
new Typeface(FontFamily,
FontStyle, FontWeight, FontStretch);
305 var totalWidth = 0.0;
307 var period =
new FormattedText(
".", CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, FontSize, Brushes.Black);
308 double periodWidth = period.Width;
310 if (TextTrimming == TextTrimming.CharacterEllipsis)
312 sizes =
new double[text.Length];
314 for (var i = 0; i < text.Length; i++)
316 string token = text[i].ToString(CultureInfo.CurrentUICulture) +
".";
317 var formattedText =
new FormattedText(token, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, FontSize, Brushes.Black);
318 double width = formattedText.Width - periodWidth;
324 else if (TextTrimming == TextTrimming.WordEllipsis)
326 var words = SplitWords(text);
327 sizes =
new double[words.Length];
329 for (var i = 0; i < words.Length; i++)
331 string token = words[i] +
".";
332 var formattedText =
new FormattedText(token, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeface, FontSize, Brushes.Black);
333 double width = formattedText.Width - periodWidth;
339 throw new ArgumentException(
"Invalid 'TextTrimming' argument.");
344 private string[] SplitWords(
string text)
346 var words =
new List<string>();
348 var sb =
new StringBuilder();
349 foreach (
char c
in text)
351 if (WordSeparators.Contains(c))
354 words.Add(sb.ToString());
358 words.Add(c.ToString(CultureInfo.InvariantCulture));
366 words.Add(sb.ToString());
368 return words.ToArray();
371 private static void OnUseTimedValidationPropertyChanged(
DependencyObject sender, DependencyPropertyChangedEventArgs e)
373 var txt = (TextBox)sender;
374 if ((
bool)e.NewValue)
380 private static void OnClearTextCommand(
object sender, ExecutedRoutedEventArgs e)
382 var textBox = sender as TextBox;
An implementation of the TextBoxBase control that provides additional features such as a proper valid...
override void OnTextChanged(string oldValue, string newValue)
Raised when the text of the TextBox changes.
override void OnApplyTemplate()
An implementation of the System.Windows.Controls.TextBox control that provides additional features su...
SiliconStudio.Paradox.Graphics.Font.FontStyle FontStyle
override Size ArrangeOverride(Size arrangeBounds)