There was already a question about filling the text and it was answered.
In short, the essence of the solution is to create a FormattedText from the contents of a hidden TextBlock , and then create a geometry from FormattedText , which is displayed using the Path , which in turn is filled with animation on it.
And everything works fine as long as the text takes one line, but when there are several lines, it turns out not what we would like.
XAML I will not repeat, because it fully coincides with that in the above answer. My code is also not much different, but I will give it for clarity.
private List<Rect> _RectsForFill; // ΠΏΡΡΠΌΠΎΡΠ³ΠΎΠ»ΡΠ½ΠΈΠΊΠΈ Ρ ΠΊΠ°ΠΆΠ΄ΡΠΌ ΡΠΈΠΌΠ²ΠΎΠ»ΠΎΠΌ private double _LengthFillText; // ΠΎΠ±ΡΠ°Ρ ΡΠΈΡΠΈΠ½Π° ΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ° //Π°Π½ΠΈΠΌΠ°ΡΠΈΡ Storyboard _Storyboard; DoubleAnimation _FromAnimation; DoubleAnimation _ToAnimation; private void CreateFillText() { //ΠΏΠΎΠ»ΡΡΠ°Π΅ΠΌ ΡΠ΅ΠΊΡΡΠΎΠ²ΠΎΠ΅ ΡΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅ TextBlock tb = this.textBlockHidden; var text = tb.Text; //ΡΠΎΠ·Π΄Π°Π΅ΠΌ ΡΠΊΠ·Π΅ΠΌΠΏΠ»ΡΡ ΡΠΎΡΠΌΠ°ΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ° FormattedText formattedText = new FormattedText( text, CultureInfo.GetCultureInfo("en-US"), FlowDirection.LeftToRight, new Typeface( tb.FontFamily, tb.FontStyle, tb.FontWeight, tb.FontStretch), tb.FontSize, Brushes.Black // ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½Π°Ρ ΠΊΠΈΡΡΡ Π½Π°ΠΌ Π½Π΅ Π²Π°ΠΆΠ½Π°, ΠΌΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ ΡΠΎΠ»ΡΠΊΠΎ Π³Π΅ΠΎΠΌΠ΅ΡΡΠΈΡ ); //Π±Π΅ΡΠ΅ΠΌ ΠΏΠ΅ΡΠ΅Π½ΠΎΡΡ ΡΡΡΠΎΠΊ Ρ ΡΡΠ°Π»ΠΎΠ½Π½ΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ±Π»ΠΎΠΊΠ° formattedText.MaxTextWidth = this.textBlockHidden.Width; formattedText.MaxTextHeight = this.textBlockHidden.Height; // ΡΡΠ°ΡΠΈΠ»ΠΈ Π³Π΅ΠΎΠΌΠ΅ΡΡΠΈΡ Ρ ΡΠ΅ΠΊΡΡΠ°... var geo = formattedText.BuildGeometry(new Point()); // ...ΠΈ ΠΎΡΠ΄Π°Π»ΠΈ Π΅Ρ Path'Ρ Target.Data = geo; //Π²ΡΡΠΈΡΠ»ΠΈΠΌ ΠΏΡΡΠΌΠΎΡΠ³ΠΎΠ»ΡΠ½ΠΈΠΊΠΈ Π΄Π»Ρ Π·Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ GetRectsForFill(text, formattedText); } private void GetRectsForFill(string text, FormattedText formattedText) { var bb = formattedText.BuildHighlightGeometry(new Point()); _LengthFillText = bb.Bounds.Width; // ΠΎΠ±ΡΠ°Ρ ΡΠΈΡΠΈΠ½Π° //Π·Π°ΠΏΠΎΠ»Π½ΡΠ΅ΠΌ ΠΊΠΎΠ»Π»Π΅ΠΊΡΠΈΡ ΠΏΠΎΠ±ΡΠΊΠ²Π΅Π½Π½ΡΡ
Π±ΠΎΠΊΡΠΎΠ² _RectsForFill = Enumerable.Range(0, text.Length) .Select(k => formattedText.BuildHighlightGeometry(new Point(), k, 1) .Bounds) .ToList(); //ΡΡΡΠ»ΠΊΠΈ Π½Π° Π°Π½ΠΈΠΌΠ°ΡΠΈΡ Π΄Π»Ρ Π΄Π°Π»ΡΠ½Π΅ΠΉΡΠ΅ΠΉ ΡΠ°Π±ΠΎΡΡ Ρ Π½Π΅ΠΉ _Storyboard = (Storyboard)Target.Resources["AnimationStoryboard"]; _FromAnimation = (DoubleAnimation)_Storyboard.Children[0]; _ToAnimation = (DoubleAnimation)_Storyboard.Children[1]; } Here is the method that fills the black text with black.
/// <summary> /// ΠΠ°ΠΊΡΠ°ΡΠΈΠ²Π°Π½ΠΈΠ΅ ΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ° /// </summary> /// <param name="startPos">Π½Π°ΡΠ°Π»ΡΠ½Π°Ρ ΠΏΠΎΠ·ΠΈΡΠΈΡ ΡΠ»ΠΎΠ²Π°</param> /// <param name="count">ΡΠΈΡΠ»ΠΎ Π·Π°ΠΊΡΠ°ΡΠΈΠ²Π°Π΅ΠΌΡΡ
Π±ΡΠΊΠ² Π² ΡΠ»ΠΎΠ²Π΅</param> public void FillTextPath(int startPos, int count) { if (count == 0) throw new ArgumentException(nameof(count)); //Π²ΡΡΠΈΡΠ»ΡΠ΅ΠΌ ΠΈΠ½Π΄Π΅ΠΊΡ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΠ³ΠΎ ΠΏΡΡΠΌΠΎΡΠ³ΠΎΠ»ΡΠ½ΠΈΠΊΠ° int index = startPos + count; if (index >= _RectsForFill.Count) index = _RectsForFill.Count - 1; //Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΡΠΉ ΠΏΡΡΠΌΠΎΡΠ³ΠΎΠ»ΡΠ½ΠΈΠΊ Rect box = _RectsForFill[index]; //Π·Π°ΠΊΡΠ°ΡΠΈΠ²Π°Π΅ΠΌ _FromAnimation.From = box.Left / _LengthFillText; _FromAnimation.To = box.Right / _LengthFillText; _ToAnimation.From = box.Left / _LengthFillText; _ToAnimation.To = box.Right / _LengthFillText; _Storyboard.Begin(); } 

Pathfor each necessary line, but I havenβt yet decided how to determine when the text inTextBlockgot a transfer to another line. - Bulson