在Grid C#WPF中绘制几何图形

时间:2018-01-16 00:40:58

标签: c# wpf user-interface text controls

我正在尝试创建一个概述文本,我尝试在ShadowEffect控件上使用Label,但它没有提供所需的结果而且它非常滞后,唯一的解决方案我到目前为止,我发现可以从Geometry对象可视化FormattedText版本。

但是这似乎也有一些问题,即我需要知道控件的宽度和高度,但是例如在带有RowDefinitions的网格中,其大小设置为*,我似乎找不到获取控件大小的方法,因此我的Geometry没有显示。

这是我的自定义控件类:

public class OutlinedLabel : FrameworkElement
{
    private string _text;
    public string Text
    {
        get => _text;
        set
        {
            _text = value;
            UpdateLayout();
            InvalidateArrange();
            InvalidateMeasure();
            InvalidateVisual();
        }
    }

    public Brush TextColor
    {
        get => (Brush)GetValue(TextColorProperty);
        set => SetValue(TextColorProperty, value);
    }

    public static readonly DependencyProperty TextColorProperty =
        DependencyProperty.Register(nameof(TextColor), typeof(Brush), typeof(OutlinedLabel),
            new PropertyMetadata(null));

    public TextAlignment TextAlignment
    {
        get => (TextAlignment)GetValue(TextAlignmentProperty);
        set => SetValue(TextAlignmentProperty, value);
    }

    public static readonly DependencyProperty TextAlignmentProperty =
        DependencyProperty.Register(nameof(TextAlignment), typeof(TextAlignment), typeof(OutlinedLabel),
            new PropertyMetadata(null));

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

    public static readonly DependencyProperty FontWeightProperty =
        DependencyProperty.Register(nameof(FontWeight), typeof(FontWeight), typeof(OutlinedLabel),
            new PropertyMetadata(null));


    public Brush OutlineBrush
    {
        get => (Brush)GetValue(OutlineBrushProperty);
        set => SetValue(OutlineBrushProperty, value);
    }

    public static readonly DependencyProperty OutlineBrushProperty =
        DependencyProperty.Register(nameof(OutlineBrush), typeof(Brush), typeof(OutlinedLabel),
            new PropertyMetadata(null));

    public double Thickness
    {
        get => (double)GetValue(ThicknessProperty);
        set => SetValue(ThicknessProperty, value);
    }

    public static readonly DependencyProperty ThicknessProperty =
        DependencyProperty.Register(nameof(Thickness), typeof(double), typeof(OutlinedLabel),
            new PropertyMetadata(null));

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

    public static readonly DependencyProperty FontFamilyProperty =
        DependencyProperty.Register(nameof(FontFamily), typeof(FontFamily), typeof(OutlinedLabel),
            new PropertyMetadata(null));

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

    public static readonly DependencyProperty FontSizeProperty =
        DependencyProperty.Register(nameof(FontSize), typeof(double), typeof(OutlinedLabel),
            new PropertyMetadata(null));

    public OutlinedLabel()
    {
        FontSize = 12;
        Text = string.Empty;
        FontFamily = new FontFamily("Seago UI");
        TextColor = Brushes.Black;
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        var currentOutlineBrush = OutlineBrush ?? TextColor;
        var bg_rect = new Rect(0, 0, ActualWidth, ActualHeight);
        drawingContext.DrawRectangle(Brushes.White, null, bg_rect);

        var typeface = new Typeface(FontFamily.Source);
        var formatted_text = new FormattedText(Text, new CultureInfo("en-us"), FlowDirection, typeface, FontSize,
            currentOutlineBrush);
        formatted_text.SetFontWeight(FontWeight);

        formatted_text.TextAlignment = TextAlignment;

        var origin = new Point(ActualWidth / 2, (ActualHeight - formatted_text.Height) / 2);

        var geometry = formatted_text.BuildGeometry(origin);

        var pen = new Pen(currentOutlineBrush, Thickness);
        drawingContext.DrawGeometry(TextColor, pen, geometry);
    }
}

这是我的xaml:

    <Grid Name="gridSubs" Margin="0,0,0,118" Height="Auto" VerticalAlignment="Stretch" IsHitTestVisible="false">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Viewbox StretchDirection="Both" Stretch="Uniform" Grid.Row="8">
            <customControls:OutlinedLabel TextAlignment="Center" TextColor="White" OutlineBrush="Black" FontWeight="Bold" FontSize="32" Thickness="1"/>
        </Viewbox>
        <Viewbox StretchDirection="Both" Stretch="Uniform" Grid.Row="7">
            <customControls:OutlinedLabel TextAlignment="Center" TextColor="White" OutlineBrush="Black" FontWeight="Bold" FontSize="32" Thickness="1"/>
        </Viewbox>
        //...
    </Grid>

当我设置Text属性时,正在调用OnRender,但没有任何可见的情况,ActualWidthActualHeight的值都为0.

如果我创建一个未包含在网格中的OutlinedLabel,该类可以工作。

如何在这种特定情况下使其发挥作用?

2 个答案:

答案 0 :(得分:2)

此OutlinedText控件有效。重要的是,它会覆盖MeasureOverride以确定其ActualWidthActualHeight

public class OutlinedText : FrameworkElement
{
    private FormattedText text;

    public static readonly DependencyProperty TextProperty = TextBlock.TextProperty.AddOwner(
        typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).text = null) { AffectsMeasure = true });

    public static readonly DependencyProperty TextAlignmentProperty = TextBlock.TextAlignmentProperty.AddOwner(
        typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).text = null) { AffectsRender = true });

    public static readonly DependencyProperty FontSizeProperty = TextBlock.FontSizeProperty.AddOwner(
        typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).text = null) { AffectsMeasure = true });

    public static readonly DependencyProperty FontFamilyProperty = TextBlock.FontFamilyProperty.AddOwner(
        typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).text = null) { AffectsMeasure = true });

    public static readonly DependencyProperty FontStyleProperty = TextBlock.FontStyleProperty.AddOwner(
        typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).text = null) { AffectsMeasure = true });

    public static readonly DependencyProperty FontWeightProperty = TextBlock.FontWeightProperty.AddOwner(
        typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).text = null) { AffectsMeasure = true });

    public static readonly DependencyProperty FontStretchProperty = TextBlock.FontStretchProperty.AddOwner(
        typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).text = null) { AffectsMeasure = true });

    public static readonly DependencyProperty ForegroundProperty = TextBlock.ForegroundProperty.AddOwner(
        typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).text = null) { AffectsRender = true });

    public static readonly DependencyProperty BackgroundProperty = TextBlock.BackgroundProperty.AddOwner(
        typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).text = null) { AffectsRender = true });

    public static readonly DependencyProperty OutlineBrushProperty = DependencyProperty.Register(
        nameof(OutlineBrush), typeof(Brush), typeof(OutlinedText),
        new FrameworkPropertyMetadata(Brushes.White, FrameworkPropertyMetadataOptions.AffectsRender, (o, e) => ((OutlinedText)o).text = null));

    public static readonly DependencyProperty OutlineThicknessProperty = DependencyProperty.Register(
        nameof(OutlineThickness), typeof(double), typeof(OutlinedText),
        new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsMeasure, (o, e) => ((OutlinedText)o).text = null));

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

    public TextAlignment TextAlignment
    {
        get { return (TextAlignment)GetValue(TextAlignmentProperty); }
        set { SetValue(TextAlignmentProperty, value); }
    }

    [TypeConverter(typeof(FontSizeConverter))]
    public double FontSize
    {
        get { return (double)GetValue(FontSizeProperty); }
        set { SetValue(FontSizeProperty, value); }
    }

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

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

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

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

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

    public Brush Background
    {
        get { return (Brush)GetValue(BackgroundProperty); }
        set { SetValue(BackgroundProperty, value); }
    }

    public Brush OutlineBrush
    {
        get { return (Brush)GetValue(OutlineBrushProperty); }
        set { SetValue(OutlineBrushProperty, value); }
    }

    public double OutlineThickness
    {
        get { return (double)GetValue(OutlineThicknessProperty); }
        set { SetValue(OutlineThicknessProperty, value); }
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        var size = CheckText() ? new Size(text.Width, text.Height) : new Size();

        if (!double.IsNaN(Width) && size.Width < Width)
        {
            size.Width = Width;
        }

        if (!double.IsNaN(Height) && size.Height < Height)
        {
            size.Height = Height;
        }

        return size;
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        if (CheckText())
        {
            var size = DesiredSize;
            var origin = new Point();

            if (size.Width > text.Width)
            {
                if (TextAlignment == TextAlignment.Center)
                {
                    origin.X = ((size.Width - text.Width) - OutlineThickness) / 2;
                }
                else if (TextAlignment == TextAlignment.Right)
                {
                    origin.X = (size.Width - text.Width) - OutlineThickness;
                }
            }

            if (size.Height > text.Height)
            {
                origin.Y = (size.Height - text.Height) / 2;
            }

            if (Background != null)
            {
                drawingContext.DrawRectangle(Background, null, new Rect(size));
            }

            drawingContext.DrawGeometry(Foreground, new Pen(OutlineBrush, OutlineThickness), text.BuildGeometry(origin));
        }
    }

    private bool CheckText()
    {
        if (text == null)
        {
            if (string.IsNullOrEmpty(Text))
            {
                return false;
            }

            text = new FormattedText(
                Text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight,
                new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
                FontSize, Brushes.Black);
        }

        return true;
    }
}

答案 1 :(得分:0)

问题是ViewBox。您的控件需要知道/评估自己的大小才能正确地在ViewBox内工作。只需删除ViewBox进行测试,您就会看到显示的内容。当您设置Height的{​​{1}}和Width时,文字也会出现。

您可以考虑回复OutlinedLabel并返回所需的尺寸。

一般来说,我不认为使用ViewBox来克服控件的大小调整问题是最佳做法。控件应该处理所有这些。