と非常によく似た行番号をLineNumberMarginと非常によく似ています。 ShowLineNumbers
が真の場合、thisのようにLineNumberMargin
が作成されます。分離されたコントロール内のリストボックス項目の行番号を描画する
とにかく、私は彼らがそれをやり遂げる方法を見て、理解しました。そして今、私はListBox(とそのアイテム)を描画のソースとして使って同様のものを適用しようとしています。
私のコントロールは次のように動作します。ListBoxの左側にドッキングされた分離されたItemsControlがあります。各ItemsControlのアイテムはUIElementです。 DesignerLineNumberMargin
はItemsControlの項目の1つであり、ListBoxのItemsSourceが設定されている場合、ListBoxをDesignerLineNumberMargin
に添付します。 DesignerLineNumberMargin
がレンダリングされると、ListBoxのアイテムを繰り返し処理し、行番号を描画します。
DesignerLineNumberMargin.cs
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();
}
}
問題私にとってy座標を考え出すされています。 OnRender
は私がListBoxItem
のHeight
を知らないと呼ばれている時:高さは、ActualHeight、DesiredSizeをは常に0
任意の洞察力のですか?