【问题标题】:Building custom TextBlock control in WPF在 WPF 中构建自定义 TextBlock 控件
【发布时间】:2011-11-04 02:00:59
【问题描述】:

我已经构建了自定义 WPF 控件,该控件具有显示文本的独特功能。
我尝试使用来自System.Windows.Controls 命名空间的TextBlock,但它对我不起作用(我有大约10000 个位置不同且内存丢失过多的字符串)。
所以我尝试通过继承 FrameworkElement 来制作自己的控件,覆盖现在包含单行的 OnRender 方法:

drawingContext.DrawText(...);

但是…… 我得到一个有点混乱的结果。 在比较了 10000 个对象的性能后,我意识到创建和添加到 Canvas 所需的时间仍然是 ~10 秒,并且我的应用程序的内存使用量从 ~32MB 增加到 ~60MB !!!
所以根本没有任何好处。

谁能解释为什么会发生这种情况,以及用两个函数创建简单(简单 = 分配更少的内存,花费更少的时间来创建)视觉的另一种方法是什么:

  1. 显示文字
  2. 设置位置(使用粗细或TranslateTransform

谢谢。

【问题讨论】:

  • 你能发布你正在做什么的代码吗?也不清楚为什么TextBlock 没有帮助你?你有没有探索只读RichTextBoxFlowDocument 用于复杂的布局文本?我同意@John 关于 StringBuilder 的看法。
  • TextBlock 正在帮助我,但由于将近 10000 个 TextBlock 占用了太多内存,我需要这么多,因为它们每个都有不同的位置。
  • 别误会,也许所有控件的外观都可以使用样式进行修改,但我从未尝试过。所以我想问另一个问题:如果我将样式应用于 Button,我可以获得这种外观吗? Media Player Controlsps。图片上的按钮是由几个椭圆和路径组合而成的。

标签: wpf render textblock


【解决方案1】:

查看AvalonEdit

也不确定你是如何存储字符串的,但你以前用过StringBuilder吗?

【讨论】:

  • 检查我发布的代码。我不确定 StringBuilder 会有什么帮助?
【解决方案2】:

这是我的代码(稍作修改):

public class SimpleTextBlock : FrameworkElement
{
    #region Static

    private const double _fontSize = 12;
    private static Point _emptyPoint;
    private static Typeface _typeface;
    private static LinearGradientBrush _textBrush;

    public readonly static DependencyProperty TextWidthProperty;

    static SimpleTextBlock()
    {
        _emptyPoint = new Point();
        _typeface = new Typeface(new FontFamily("Sergoe UI"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);

        GradientStopCollection GSC = new GradientStopCollection(2);
        GSC.Add(new GradientStop(Color.FromArgb(160, 255, 255, 255), 0.0));
        GSC.Add(new GradientStop(Color.FromArgb(160, 180, 200, 255), 0.7));
        _textBrush = new LinearGradientBrush(GSC, 90);
        _textBrush.Freeze();


        SimpleTextBlock.TextWidthProperty = DependencyProperty.Register(
            "TextWidth",
            typeof(double),
            typeof(SimpleTextBlock),
            new FrameworkPropertyMetadata(0.0d, FrameworkPropertyMetadataOptions.AffectsRender));
    }

    #endregion

    FormattedText _formattedText;

    public SimpleTextBlock(string text)
    {
        _formattedText = new FormattedText(text, System.Globalization.CultureInfo.InvariantCulture, FlowDirection.LeftToRight, _typeface, _fontSize, _textBrush);
    }

    public SimpleTextBlock(string text, FlowDirection FlowDirection)
    {
        _formattedText = new FormattedText(text, System.Globalization.CultureInfo.InvariantCulture, FlowDirection, _typeface, _fontSize, _textBrush);
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        _formattedText.MaxTextWidth = (double)GetValue(TextWidthProperty);
        drawingContext.DrawText(_formattedText, _emptyPoint);
    }

    public double TextWidth
    {
        get { return (double)base.GetValue(TextWidthProperty); }
        set { base.SetValue(TextWidthProperty, value); }
    }

    public double ActualTextWidth
    {
        get { return _formattedText.Width; }
    }

    public double ActualTextHeight
    {
        get { return _formattedText.Height; }
    }
}

【讨论】:

  • 虽然拥有这段代码很不错,但我认为人们(包括我自己)想知道为什么您需要在一个视图中包含 10,000 个文本块。页面的布局方式似乎存在根本问题。你看过FlowDocuments吗?您能否附上程序外观的屏幕截图或绘图,以便我们帮助您找出最佳行动方案
  • 我还没有 SS,但我想制作带有搜索功能的媒体库,类似于 WindowsMediaPlayer 中的库。我对FlowDocuments一无所知,但我打算看看它。
  • 为什么不使用风格化的ListBoxDataGrid
  • 我使用了 ListBox,但它看起来很差,而且我不熟悉任何组件的样式化,所以我自己构建了一个。我认为制作自己可以随时修改的控件比学习如何使用已经存在的控件更容易。你能给我发一些解释如何使用样式的代码吗?风格化的 ListBox 会很好。
【解决方案3】:

因为听起来我们确定您应该对列表框之类的控件进行样式化,所以这里有一些您可以做的不同事情的示例:

Use Images as Items

Stylized and Binding

老实说,这一切都取决于您希望它是什么样子。 WPF 非常棒,它可以让您对事物的外观进行多少控制。

Crazy example using a listbox to make the planet's orbits

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    • 2012-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多