ItemsControl中的WPF自定义控件

时间:2017-02-27 19:45:16

标签: c# wpf xaml custom-controls

我有一个自定义控件,看起来大致如下:

public class MyTextBlockTest : Control
{
    static MyTextBlockTest()
    {
    }

    public static readonly DependencyProperty TextProperty =
         DependencyProperty.Register("Text", typeof(string),
         typeof(MyTextBlockTest), new FrameworkPropertyMetadata(""));

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

    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);

        FontFamily font = new FontFamily("Times New Roman");
        Typeface typeface = new Typeface(font, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
        FormattedText ft = new FormattedText(Text,
                                             System.Globalization.CultureInfo.CurrentCulture,
                                             System.Windows.FlowDirection.LeftToRight,
                                             typeface,
                                             15.0,
                                             Brushes.Black);

        var point = this.PointToScreen(new Point(0, 0));
        drawingContext.DrawText(ft, point);            
    }
}

我正在尝试在ItemsControl

中使用此控件
<ScrollViewer>
    <ItemsControl ItemsSource="{Binding BigList, ElementName=MainWindowView}" Margin="0,-1,0,1">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <!--<TextBlock Text="{Binding}"/>-->
                <controls:MyTextBlockTest Text="{Binding}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>

如果我启用了已注释掉的TextBlock,则列表显示正常;但是,使用我的自定义控件,WPF不会将文本放在正确的位置;更具体地说,它似乎只是简单地将所有元素打印在彼此之上。

this.PointToScreen调用是我最初给它提示的一个想法,但我不确定(即使这样做有效,但事实并非如此)是否会对ScrollViewer做出有利的反应。

我意识到我可以简单地将这个控件基于TextBlock控件,但我特别希望将它作为性能实验以较低级别的控件为基础。请有人指出我正确地将自定义控件放在屏幕上的方法吗?

1 个答案:

答案 0 :(得分:2)

您的最小自定义TextBlock至少应该覆盖MeasureOverride方法以返回其大小。否则,控件的宽度和高度为零,ItemsControl中的所有项目都是相互重叠的。

因此,Text属性应使用FrameworkPropertyMetadataOptions.AffectsMeasure标志注册。

public class MyTextBlock : FrameworkElement
{
    private FormattedText formattedText;

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register(
            "Text", typeof(string), typeof(MyTextBlock),
            new FrameworkPropertyMetadata(
                string.Empty,
                FrameworkPropertyMetadataOptions.AffectsMeasure,
                (o, e) => ((MyTextBlock)o).TextPropertyChanged((string)e.NewValue)));

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

    private void TextPropertyChanged(string text)
    {
        var typeface = new Typeface(
            new FontFamily("Times New Roman"),
            FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);

        formattedText = new FormattedText(
            text, CultureInfo.CurrentCulture,
            FlowDirection.LeftToRight, typeface, 15, Brushes.Black);
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        return formattedText != null
            ? new Size(formattedText.Width, formattedText.Height)
            : new Size();
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        if (formattedText != null)
        {
            drawingContext.DrawText(formattedText, new Point());
        }
    }
}