网格C#WPF中的绘图几何 [英] Drawing Geometry inside Grid C# WPF

查看:99
本文介绍了网格C#WPF中的绘图几何的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建轮廓文本,我尝试在 Label 控件上使用 ShadowEffect 但它无法提供理想的结果,而且相当滞后,到目前为止,我发现的唯一解决方案是可视化 Geometry FormattedText构建对象。

I'm trying to create an outlined text, I've tried using the ShadowEffect on the Label control but it doesn't provide the desired results and it's quite laggy, the only solution I've found so far is visualizing a Geometry build from a FormattedText object.

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

But that also seems to have some problems with it, namely I need to know the Width and the Height of the Control, but for example in a Grid with RowDefinitions, where their size is set to *, I cant seem to find a way to obtain the size of the control, thus my Geometry is not being displayed.

这是我的自定义控件类:

Here is my custom control class:

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 正在被调用,但视觉上没有发生任何变化, ActualWidth ActualHeight 两者的值均为0。

When I set the Text property, OnRender is being invoked, but nothing visually happens, ActualWidth and ActualHeight both have a value of 0.

如果我创建了一个不包含在网格中的OutlinedLabel,则该类将起作用。

The class works if I create for example an OutlinedLabel not contained in a Grid.

如何在特定情况下起作用?

How can I make it work in this specific case?

推荐答案

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

This OutlinedText control works. The important part is that it overrides MeasureOverride in order to determine its ActualWidth and ActualHeight.

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;
    }
}

这篇关于网格C#WPF中的绘图几何的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆