我想在ListBox的左侧绘制行号,与AvalonEdit与LineNumberMargin的行号非常相似。如果ShowLineNumbers
为真,则会LineNumberMargin
创建DesignerLineNumberMargin
。
无论如何,我看看他们是如何做到这一点并理解的,现在我正在尝试应用类似的东西,但使用ListBox(及其项目)作为绘图的来源。
我的控件的工作原理如下:我有一个独立的ItemsControl停靠在ListBox的左侧。每个ItemsControl的项目都是UIElement。 DesignerLineNumberMargin
是ItemsControl的项目之一,当ListBox的ItemsSource设置时,我将ListBox附加到DesignerLineNumberMargin
。当呈现public interface IMetadataAware
{
void Attach(ItemsControl control);
void Detach(ItemsControl control);
}
public class DesignerLineNumberMargin : FrameworkElement, IMetadataAware
{
private ItemsControl control;
private Typeface typeface;
private double emSize;
private int maxLineNumberLength = 2;
static DesignerLineNumberMargin()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DesignerLineNumberMargin),
new FrameworkPropertyMetadata(typeof(DesignerLineNumberMargin)));
}
protected override Size MeasureOverride(Size availableSize)
{
typeface = CreateTypeface();
emSize = (double)GetValue(TextBlock.FontSizeProperty);
var text = CreateText(new string('9', maxLineNumberLength));
return new Size(text.Width, 0);
}
private FormattedText CreateText(string text)
{
return
new FormattedText(
text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
typeface,
emSize,
(Brush)GetValue(Control.ForegroundProperty));
}
protected override void OnRender(DrawingContext drawingContext)
{
if (control == null)
return;
var renderSize = RenderSize;
var foreground = (Brush)GetValue(Control.ForegroundProperty);
for (int index = 0; index < control.Items.Count; index++)
{
var item = control.Items[index];
var container = (FrameworkElement)control.ItemContainerGenerator.ContainerFromItem(item);
var text = CreateText((index + 1).ToString(CultureInfo.CurrentCulture));
//var y = container.Height;
var y = RenderSize.Height / (double)control.Items.Count;
drawingContext.DrawText(text, new Point(renderSize.Width - text.Width, y + index));
}
}
private Typeface CreateTypeface()
{
var element = this;
return new Typeface(
(FontFamily)element.GetValue(TextBlock.FontFamilyProperty),
(FontStyle)element.GetValue(TextBlock.FontStyleProperty),
(FontWeight)element.GetValue(TextBlock.FontWeightProperty),
(FontStretch)element.GetValue(TextBlock.FontStretchProperty));
}
public void Attach(ItemsControl control)
{
this.control = control;
var descriptor = TypeDescriptor.GetProperties(control)["ItemsSource"];
descriptor.AddValueChanged(control, OnItemsSourceChanged);
}
private void OnItemsSourceChanged(object sender, EventArgs e)
{
if (this.control.ItemsSource is INotifyCollectionChanged)
(this.control.ItemsSource as INotifyCollectionChanged).CollectionChanged += CollectionChanged;
}
private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
InvalidateVisual();
}
public void Detach(ItemsControl control)
{
if (this.control == control)
{
var descriptor = TypeDescriptor.GetProperties(control)["ItemsSource"];
descriptor.RemoveValueChanged(control, OnItemsSourceChanged);
if (this.control.ItemsSource is INotifyCollectionChanged)
(this.control.ItemsSource as INotifyCollectionChanged).CollectionChanged -= CollectionChanged;
this.control = null;
}
InvalidateVisual();
}
}
时,我迭代ListBox的项目并绘制行号。
DesignerLineNumberMargin.cs
OnRender
我的问题是找出 y坐标。调用Height
时,我不知道ListBoxItem
的{{1}}:高度,ActualHeight,DesiredSize始终为0.
任何见解?
答案 0 :(得分:1)
我想是的,因为您的MeasureOverride()
只返回Size
而Width
,但Height
设为零。
尝试将return
语句更改为:
return new Size(text.Width, text.Height);