2016-08-14 1 views
0

Je veux dessiner des numéros de ligne dans la gauche d'un ListBox, très similaire à ce que AvalonEdit fait avec LineNumberMargin. Lorsque ShowLineNumbers est vrai, il crée LineNumberMargin comme this.Dessinez le numéro de ligne des éléments ListBox dans un contrôle séparé

De toute façon, j'ai jeté un oeil à la façon dont ils le font, et compris, et maintenant j'essaie d'appliquer quelque chose de similaire, mais en utilisant un ListBox (et ses éléments) comme source pour le dessin.

Mon contrôle fonctionne comme ceci: J'ai un ItemsControl séparé ancré à gauche de ListBox. Chaque élément ItemsControl est un UIElement. DesignerLineNumberMargin est l'un des éléments ItemsControl et lorsque la ItemsSource de la ListBox est définie, j'attache le ListBox au DesignerLineNumberMargin. Lorsque DesignerLineNumberMargin est affiché, je parcourt les éléments de ListBox et dessine les numéros de ligne.

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

Le problème pour moi est de trouver la coordonnée y. Lorsque OnRender est appelé, je ne connais pas le Height du ListBoxItem: Hauteur, ActualHeight, DesiredSize est toujours 0.

enter image description here

Toute autre idée?

Répondre

0

Je suppose que c'est parce que votre MeasureOverride() renvoie un Size avec seulement un Width, mais Height mis à zéro.

Essayez de changer la déclaration return à:

return new Size(text.Width, text.Height);