添加到面板的文本块会自动调整大小

发布于 2024-09-19 04:14:59 字数 11235 浏览 8 评论 0原文

我有一个用于布局文本的自定义面板。有一个名为“Text”的 DependencyProperty,当该值更改时,这段代码将运行:

if( !string.IsNullOrEmpty(Text))
{
    Children.Clear();

    foreach (char ch in Text)
    {
        TextBlock textBlock = new TextBlock();
        textBlock.Text = ch.ToString();
        textBlcok.Foreground = Foreground;

        //The rest of these are DPs in the panel
        textBlock.FontFamily = FontFamily;
        textBlock.FontStyle = FontStyle;     
        textBlock.FontWeight = FontWeight;
        textBlock.FontStretch = FontStretch;
        textBlock.FontSize = FontSize;

        Children.Add(textBlock);
        }
    }
}

现在,字体大小为 15,字体为 Arial,这些应该为我提供大约 8 宽度和 10 高度的所需大小。然而,当我执行 Measure() 并检查所需的大小时,我每次都会得到 40,18!

因此,在试图找出可能改变大小的内容时,我将此代码放在 Children.Add 上面的代码之前和之后:

textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
Console.WriteLine(ch.ToString() + ": " + textBlock.DesiredSize);

Children.Add(textBlock);

textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
Console.WriteLine(ch.ToString() + ": " + textBlock.DesiredSize);

这给了我什么,是在将其添加到孩子集合之前的正确所需大小,并且添加到集合后的大小为 40,18(无论字母)。

是什么原因导致这种情况发生?

编辑:您可以在此处找到该控件的完整源代码:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using IQ.Touch.Resources.Classes.Helpers;

/* TextOnAPath.cs
 * 
 * A slightly modified version of the control found at
 * http://www.codeproject.com/KB/WPF/TextOnAPath.aspx
 */

namespace IQ.Touch.Resources.Controls
{
    public class TextOnAPath : Panel
    {
        // Fields
        PathFigureHelper pathFigureHelper = new PathFigureHelper();
        Size totalSize;

        // Dependency properties
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text",
                typeof(string),
                typeof(TextOnAPath),
                new PropertyMetadata(OnFontPropertyChanged));

        public static readonly DependencyProperty FontFamilyProperty =
            DependencyProperty.Register("FontFamily",
                typeof(FontFamily),
                typeof(TextOnAPath),
                new PropertyMetadata(new FontFamily("Portable User Interface"), OnFontPropertyChanged));

        public static readonly DependencyProperty FontStyleProperty =
            DependencyProperty.Register("FontStyle",
                typeof(FontStyle),
                typeof(TextOnAPath),
                new PropertyMetadata(FontStyles.Normal, OnFontPropertyChanged));

        public static readonly DependencyProperty FontSizeProperty =
            DependencyProperty.Register("FontSize",
                typeof(double),
                typeof(TextOnAPath),
                new PropertyMetadata(12.0, OnFontPropertyChanged));

        public static readonly DependencyProperty FontWeightProperty =
            DependencyProperty.Register("FontWeight",
                typeof(FontWeight),
                typeof(TextOnAPath),
                new PropertyMetadata(FontWeights.Normal, OnFontPropertyChanged));

        public static readonly DependencyProperty FontStretchProperty =
            DependencyProperty.Register("FontStretch",
                typeof(FontStretch),
                typeof(TextOnAPath),
                new PropertyMetadata(FontStretches.Normal, OnFontPropertyChanged));

        public static readonly DependencyProperty ForegroundProperty =
            DependencyProperty.Register("Foreground",
                typeof(Brush),
                typeof(TextOnAPath),
                new PropertyMetadata(new SolidColorBrush(Colors.Black), OnFontPropertyChanged));

        public static readonly DependencyProperty PathFigureProperty =
            DependencyProperty.Register("PathFigure",
                typeof(PathFigure),
                typeof(TextOnAPath),
                new PropertyMetadata(OnPathFigureChanged));

        // Properties
        public string Text
        {
            set { SetValue(TextProperty, value); }
            get { return (string)GetValue(TextProperty); }
        }

        public FontFamily FontFamily
        {
            set { SetValue(FontFamilyProperty, value); }
            get { return (FontFamily)GetValue(FontFamilyProperty); }
        }

        public FontStyle FontStyle
        {
            set { SetValue(FontStyleProperty, value); }
            get { return (FontStyle)GetValue(FontStyleProperty); }
        }

        public double FontSize
        {
            set { SetValue(FontSizeProperty, value); }
            get { return (double)GetValue(FontSizeProperty); }
        }

        public FontWeight FontWeight
        {
            set { SetValue(FontWeightProperty, value); }
            get { return (FontWeight)GetValue(FontWeightProperty); }
        }

        public FontStretch FontStretch
        {
            set { SetValue(FontStretchProperty, value); }
            get { return (FontStretch)GetValue(FontStretchProperty); }
        }

        public Brush Foreground
        {
            set { SetValue(ForegroundProperty, value); }
            get { return (Brush)GetValue(ForegroundProperty); }
        }

        public PathFigure PathFigure
        {
            set { SetValue(PathFigureProperty, value); }
            get { return (PathFigure)GetValue(PathFigureProperty); }
        }

        // Property-changed handlers
        static void OnFontPropertyChanged(DependencyObject obj,
                                          DependencyPropertyChangedEventArgs args)
        {
            (obj as TextOnAPath).OnFontPropertyChanged(args);
        }

        void OnFontPropertyChanged(DependencyPropertyChangedEventArgs args)
        {
            Children.Clear();

            if (String.IsNullOrEmpty(Text))
                return;

            foreach (char ch in Text)
            {
                TextBlock textBlock = new TextBlock();
                textBlock.Text = ch.ToString();
                textBlock.FontFamily = FontFamily;
                textBlock.FontStyle = FontStyle;
                textBlock.FontWeight = FontWeight;
                textBlock.FontStretch = FontStretch;
                textBlock.FontSize = FontSize;
                textBlock.Foreground = Foreground;
                textBlock.HorizontalAlignment = HorizontalAlignment.Center;
                textBlock.VerticalAlignment = VerticalAlignment.Bottom;
                textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                Console.WriteLine(ch.ToString() + ": " + textBlock.DesiredSize);
                Children.Add(textBlock);
                textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                Console.WriteLine(ch.ToString() + ": " + textBlock.DesiredSize);
            }
            CalculateTransforms();
            InvalidateMeasure();
        }

        static void OnPathFigureChanged(DependencyObject obj,
                                        DependencyPropertyChangedEventArgs args)
        {
            (obj as TextOnAPath).OnPathFigureChanged(args);
        }

        void OnPathFigureChanged(DependencyPropertyChangedEventArgs args)
        {
            pathFigureHelper.SetPathFigure(args.NewValue as PathFigure);
            CalculateTransforms();
            InvalidateMeasure();
        }

        void CalculateTransforms()
        {
            double pathLength = pathFigureHelper.Length;
            double textLength = 0;
            double textDesiredWidth = 9;
            totalSize = new Size();

            foreach (UIElement child in Children)
            {
                child.Measure(new Size(Double.PositiveInfinity,
                                       Double.PositiveInfinity));
                textLength += child.DesiredSize.Width;
            }
            //textLength = Children.Count * textDesiredWidth;

            if (pathLength == 0 || textLength == 0)
                return;

            //double scalingFactor = pathLength / textLength;
            double baseline = FontSize;     // * FontFamily.Baseline;
            double progress = 0;

            if (textLength <= pathLength)
            {
                progress = ((pathLength - textLength) / 2) / pathLength;
            }

            foreach (UIElement child in Children)
            {
                double width = child.DesiredSize.Width;
                //double width = textDesiredWidth;
                progress += width / 2 / pathLength;
                Point point, tangent;

                pathFigureHelper.GetPointAtFractionLength(progress,
                                                out point, out tangent);

                TransformGroup transformGroup = new TransformGroup();

                //ScaleTransform scaleTransform = new ScaleTransform();
                //scaleTransform.ScaleX = scalingFactor;
                //scaleTransform.ScaleY = scalingFactor;
                //transformGroup.Children.Add(scaleTransform);

                RotateTransform rotateTransform = new RotateTransform();
                rotateTransform.Angle = Math.Atan2(tangent.Y, tangent.X) * 180 / Math.PI;
                rotateTransform.CenterX = width / 2;
                rotateTransform.CenterY = baseline;
                transformGroup.Children.Add(rotateTransform);

                TranslateTransform translateTransform = new TranslateTransform();
                translateTransform.X = point.X - width / 2;
                translateTransform.Y = point.Y - baseline;
                transformGroup.Children.Add(translateTransform);

                child.RenderTransform = transformGroup;

                BumpUpTotalSize(transformGroup.Value, new Point(0, 0));
                BumpUpTotalSize(transformGroup.Value, new Point(0, child.DesiredSize.Height));
                BumpUpTotalSize(transformGroup.Value, new Point(child.DesiredSize.Width, 0));
                BumpUpTotalSize(transformGroup.Value, new Point(child.DesiredSize.Width, child.DesiredSize.Height));

                progress += width / 2 / pathLength;
            }

            Point endPoint, endTangent;
            pathFigureHelper.GetPointAtFractionLength(1, out endPoint, out endTangent);
            totalSize.Width = Math.Max(totalSize.Width, endPoint.X);
        }

        void BumpUpTotalSize(Matrix matrix, Point point)
        {
            point = matrix.Transform(point);
            totalSize.Width = Math.Max(totalSize.Width, point.X);
            totalSize.Height = Math.Max(totalSize.Height, point.Y);
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            foreach (UIElement child in Children)
                child.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

            // return the size calculated during CalculateTransforms
            return totalSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            foreach (UIElement child in Children)
                child.Arrange(new Rect(new Point(0, 0), child.DesiredSize));

            return finalSize;
        }
    }
}

I have a custom Panel for laying out text. There is a DependancyProperty called "Text" and when that value changes, this piece of code runs:

if( !string.IsNullOrEmpty(Text))
{
    Children.Clear();

    foreach (char ch in Text)
    {
        TextBlock textBlock = new TextBlock();
        textBlock.Text = ch.ToString();
        textBlcok.Foreground = Foreground;

        //The rest of these are DPs in the panel
        textBlock.FontFamily = FontFamily;
        textBlock.FontStyle = FontStyle;     
        textBlock.FontWeight = FontWeight;
        textBlock.FontStretch = FontStretch;
        textBlock.FontSize = FontSize;

        Children.Add(textBlock);
        }
    }
}

Now, with font size of 15 and font Arial, these should be giving me a desired size of around 8 width and 10 height. However, when I do a Measure() and check the desired size, I get 40,18 every time!

So in trying to figure out what could've possibly changed the size, I put this code before and after the Children.Add in the code above:

textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
Console.WriteLine(ch.ToString() + ": " + textBlock.DesiredSize);

Children.Add(textBlock);

textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
Console.WriteLine(ch.ToString() + ": " + textBlock.DesiredSize);

What this gave me, was the proper desired size before it's added to the children collection, and a size of 40,18 (regardless of letter) after it's added to the collection.

What is causing this to happen?

Edit: You can find the full source for the control here:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using IQ.Touch.Resources.Classes.Helpers;

/* TextOnAPath.cs
 * 
 * A slightly modified version of the control found at
 * http://www.codeproject.com/KB/WPF/TextOnAPath.aspx
 */

namespace IQ.Touch.Resources.Controls
{
    public class TextOnAPath : Panel
    {
        // Fields
        PathFigureHelper pathFigureHelper = new PathFigureHelper();
        Size totalSize;

        // Dependency properties
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text",
                typeof(string),
                typeof(TextOnAPath),
                new PropertyMetadata(OnFontPropertyChanged));

        public static readonly DependencyProperty FontFamilyProperty =
            DependencyProperty.Register("FontFamily",
                typeof(FontFamily),
                typeof(TextOnAPath),
                new PropertyMetadata(new FontFamily("Portable User Interface"), OnFontPropertyChanged));

        public static readonly DependencyProperty FontStyleProperty =
            DependencyProperty.Register("FontStyle",
                typeof(FontStyle),
                typeof(TextOnAPath),
                new PropertyMetadata(FontStyles.Normal, OnFontPropertyChanged));

        public static readonly DependencyProperty FontSizeProperty =
            DependencyProperty.Register("FontSize",
                typeof(double),
                typeof(TextOnAPath),
                new PropertyMetadata(12.0, OnFontPropertyChanged));

        public static readonly DependencyProperty FontWeightProperty =
            DependencyProperty.Register("FontWeight",
                typeof(FontWeight),
                typeof(TextOnAPath),
                new PropertyMetadata(FontWeights.Normal, OnFontPropertyChanged));

        public static readonly DependencyProperty FontStretchProperty =
            DependencyProperty.Register("FontStretch",
                typeof(FontStretch),
                typeof(TextOnAPath),
                new PropertyMetadata(FontStretches.Normal, OnFontPropertyChanged));

        public static readonly DependencyProperty ForegroundProperty =
            DependencyProperty.Register("Foreground",
                typeof(Brush),
                typeof(TextOnAPath),
                new PropertyMetadata(new SolidColorBrush(Colors.Black), OnFontPropertyChanged));

        public static readonly DependencyProperty PathFigureProperty =
            DependencyProperty.Register("PathFigure",
                typeof(PathFigure),
                typeof(TextOnAPath),
                new PropertyMetadata(OnPathFigureChanged));

        // Properties
        public string Text
        {
            set { SetValue(TextProperty, value); }
            get { return (string)GetValue(TextProperty); }
        }

        public FontFamily FontFamily
        {
            set { SetValue(FontFamilyProperty, value); }
            get { return (FontFamily)GetValue(FontFamilyProperty); }
        }

        public FontStyle FontStyle
        {
            set { SetValue(FontStyleProperty, value); }
            get { return (FontStyle)GetValue(FontStyleProperty); }
        }

        public double FontSize
        {
            set { SetValue(FontSizeProperty, value); }
            get { return (double)GetValue(FontSizeProperty); }
        }

        public FontWeight FontWeight
        {
            set { SetValue(FontWeightProperty, value); }
            get { return (FontWeight)GetValue(FontWeightProperty); }
        }

        public FontStretch FontStretch
        {
            set { SetValue(FontStretchProperty, value); }
            get { return (FontStretch)GetValue(FontStretchProperty); }
        }

        public Brush Foreground
        {
            set { SetValue(ForegroundProperty, value); }
            get { return (Brush)GetValue(ForegroundProperty); }
        }

        public PathFigure PathFigure
        {
            set { SetValue(PathFigureProperty, value); }
            get { return (PathFigure)GetValue(PathFigureProperty); }
        }

        // Property-changed handlers
        static void OnFontPropertyChanged(DependencyObject obj,
                                          DependencyPropertyChangedEventArgs args)
        {
            (obj as TextOnAPath).OnFontPropertyChanged(args);
        }

        void OnFontPropertyChanged(DependencyPropertyChangedEventArgs args)
        {
            Children.Clear();

            if (String.IsNullOrEmpty(Text))
                return;

            foreach (char ch in Text)
            {
                TextBlock textBlock = new TextBlock();
                textBlock.Text = ch.ToString();
                textBlock.FontFamily = FontFamily;
                textBlock.FontStyle = FontStyle;
                textBlock.FontWeight = FontWeight;
                textBlock.FontStretch = FontStretch;
                textBlock.FontSize = FontSize;
                textBlock.Foreground = Foreground;
                textBlock.HorizontalAlignment = HorizontalAlignment.Center;
                textBlock.VerticalAlignment = VerticalAlignment.Bottom;
                textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                Console.WriteLine(ch.ToString() + ": " + textBlock.DesiredSize);
                Children.Add(textBlock);
                textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                Console.WriteLine(ch.ToString() + ": " + textBlock.DesiredSize);
            }
            CalculateTransforms();
            InvalidateMeasure();
        }

        static void OnPathFigureChanged(DependencyObject obj,
                                        DependencyPropertyChangedEventArgs args)
        {
            (obj as TextOnAPath).OnPathFigureChanged(args);
        }

        void OnPathFigureChanged(DependencyPropertyChangedEventArgs args)
        {
            pathFigureHelper.SetPathFigure(args.NewValue as PathFigure);
            CalculateTransforms();
            InvalidateMeasure();
        }

        void CalculateTransforms()
        {
            double pathLength = pathFigureHelper.Length;
            double textLength = 0;
            double textDesiredWidth = 9;
            totalSize = new Size();

            foreach (UIElement child in Children)
            {
                child.Measure(new Size(Double.PositiveInfinity,
                                       Double.PositiveInfinity));
                textLength += child.DesiredSize.Width;
            }
            //textLength = Children.Count * textDesiredWidth;

            if (pathLength == 0 || textLength == 0)
                return;

            //double scalingFactor = pathLength / textLength;
            double baseline = FontSize;     // * FontFamily.Baseline;
            double progress = 0;

            if (textLength <= pathLength)
            {
                progress = ((pathLength - textLength) / 2) / pathLength;
            }

            foreach (UIElement child in Children)
            {
                double width = child.DesiredSize.Width;
                //double width = textDesiredWidth;
                progress += width / 2 / pathLength;
                Point point, tangent;

                pathFigureHelper.GetPointAtFractionLength(progress,
                                                out point, out tangent);

                TransformGroup transformGroup = new TransformGroup();

                //ScaleTransform scaleTransform = new ScaleTransform();
                //scaleTransform.ScaleX = scalingFactor;
                //scaleTransform.ScaleY = scalingFactor;
                //transformGroup.Children.Add(scaleTransform);

                RotateTransform rotateTransform = new RotateTransform();
                rotateTransform.Angle = Math.Atan2(tangent.Y, tangent.X) * 180 / Math.PI;
                rotateTransform.CenterX = width / 2;
                rotateTransform.CenterY = baseline;
                transformGroup.Children.Add(rotateTransform);

                TranslateTransform translateTransform = new TranslateTransform();
                translateTransform.X = point.X - width / 2;
                translateTransform.Y = point.Y - baseline;
                transformGroup.Children.Add(translateTransform);

                child.RenderTransform = transformGroup;

                BumpUpTotalSize(transformGroup.Value, new Point(0, 0));
                BumpUpTotalSize(transformGroup.Value, new Point(0, child.DesiredSize.Height));
                BumpUpTotalSize(transformGroup.Value, new Point(child.DesiredSize.Width, 0));
                BumpUpTotalSize(transformGroup.Value, new Point(child.DesiredSize.Width, child.DesiredSize.Height));

                progress += width / 2 / pathLength;
            }

            Point endPoint, endTangent;
            pathFigureHelper.GetPointAtFractionLength(1, out endPoint, out endTangent);
            totalSize.Width = Math.Max(totalSize.Width, endPoint.X);
        }

        void BumpUpTotalSize(Matrix matrix, Point point)
        {
            point = matrix.Transform(point);
            totalSize.Width = Math.Max(totalSize.Width, point.X);
            totalSize.Height = Math.Max(totalSize.Height, point.Y);
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            foreach (UIElement child in Children)
                child.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));

            // return the size calculated during CalculateTransforms
            return totalSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            foreach (UIElement child in Children)
                child.Arrange(new Rect(new Point(0, 0), child.DesiredSize));

            return finalSize;
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一抹淡然 2024-09-26 04:15:01

您应该将 TextBox 水平对齐到中心。它默认对齐为 strech,从而将其扩展到可用区域。

编辑

只需用一个小类对其进行测试:

public class TextOnAPath : Panel
{
    public TextOnAPath() {
        var textBlock = new TextBlock();
        textBlock.Text = "Test";
        textBlock.Background = Brushes.Blue;
        textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Top;
        textBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
        this.Children.Add(textBlock);

        this.Background = Brushes.Gray;
    }

    protected override Size MeasureOverride(Size availableSize) {
        return availableSize;
    }

    protected override Size ArrangeOverride(Size finalSize) {
        foreach (UIElement child in this.Children)
            child.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height));
        return finalSize;
    }
}

删除对齐会占用所有可用空间...是否是您的 CalculateTransforms 方法导致了这种效果?特别是,因为结果将在 MeasureOverride 方法中使用。

You should horizontally align you TextBox to the left, right, or center. It is aligned as strech per default, thus expandig it to the available area.

Edit

Just testet it with a little class:

public class TextOnAPath : Panel
{
    public TextOnAPath() {
        var textBlock = new TextBlock();
        textBlock.Text = "Test";
        textBlock.Background = Brushes.Blue;
        textBlock.VerticalAlignment = System.Windows.VerticalAlignment.Top;
        textBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
        this.Children.Add(textBlock);

        this.Background = Brushes.Gray;
    }

    protected override Size MeasureOverride(Size availableSize) {
        return availableSize;
    }

    protected override Size ArrangeOverride(Size finalSize) {
        foreach (UIElement child in this.Children)
            child.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height));
        return finalSize;
    }
}

Removing the alignments takes up all available space ... could it be that your CalculateTransforms method causes the effect? Especially, as the outcome is then used in the MeasureOverride method.

月依秋水 2024-09-26 04:15:01

我发现了问题,事实证明问题根本与控件无关,但是代码中的某个地方文本块的默认模板发生了更改,并且 MinWidth 和 MinHeight 由于某种原因设置为 40,18 。现在要找到嫌疑人并对他们大喊大叫。

谢谢大家

I figured out the problem, it turns out that the problem was not related to the control at all, but somewhere in the code the default template for a textblock got changed, and MinWidth and MinHeight got set to 40,18 for some reason... Now to find the suspect and to yell at them.

Thanks guys

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文