Подтвердить что ты не робот

Участник WPF с элементами управления внутри

Я пытаюсь добиться необычного использования Adorner. Когда вы нажмете над RichTextBox, над ним появится Adorner (см. Диаграмму ниже), что позволит вам добавить список строк в ListBox, содержащийся в Adorner. Это используется для добавления "тегов" (à la Flickr) к проходу, содержащемуся в украшенном элементе.

adorner diagram

Во-первых,: возможно ли это?

В большинстве примеров Adorners показано, как переопределить метод Adorner OnRender, чтобы делать тривиальные вещи, такие как рисование фигур. Я смог использовать это, чтобы отобразить набор прямоугольников, которые создают серая граница Adorner, которая также автоматически изменяет размер, если высота RichTextBox увеличивается из-за добавления дополнительных строк текста, пока отображается Adorner.

protected override void OnRender(DrawingContext drawingContext)
{
    SolidColorBrush grayBrush = new SolidColorBrush();
    grayBrush.Color = Color.FromRgb(153, 153, 153);

    // left
    drawingContext.DrawRectangle(grayBrush, null, new System.Windows.Rect(1, 1, 5, ActualHeight));
    // right
    drawingContext.DrawRectangle(grayBrush, null, new System.Windows.Rect(ActualWidth - 6, 1, 5, ActualHeight));
    //bottom
    drawingContext.DrawRectangle(grayBrush, null, new System.Windows.Rect(1, ActualHeight, ActualWidth - 2, 5));

    // for reasons unimportant to this example the top gray bar is rendered as part of the RichTextBox

}

Однако добавление элементов управления несколько более проблематично. Вообще говоря, поклонник WPF требует добавления дочерних элементов управления в код, а не XAML. Используя метод, описанный в DrawingContext adorner - можно нарисовать stackpanel?, я узнал, как добавлять дочерние элементы управления (например, TextBox) к Adorner без каких-либо проблем в Adorner инициализатор.

Однако проблема заключается в размещении этих элементов управления в Adorner.

Если бы я мог создать сетку с серым фоном и поместить ее в нижней части Adorner, я должен хорошо идти. Я бы предположил (надеюсь), что такие вещи, как автоматическое изменение размера Adorner на основе изменения размера этой метки в виде таблицы, будут автоматически выполняться.

Короче говоря, если предположить, что это возможно, может ли кто-нибудь рекомендовать способ создания этой более низкой области управления тегами в Adorner и позиционирования ее относительно дна Adorner (который, возможно, придется изменять размер как содержимое RichTextBox изменяется)?

4b9b3361

Ответ 1

Huzah! С помощью Геннадий Танасиев, у меня есть ответ.

В отличие от большинства элементов управления в WPF, у adorners нет никакого готового способа назначения дочерних элементов (таких как элементы управления, которые я хотел добавить). Не добавляя ничего в adorners, вы можете только переопределить их метод OnRender и нарисовать материал в DrawingContext, который будет передан в него. Честно говоря, это подходит, вероятно, для 99% случаев использования для adorners (например, для создания элементов управления движением вокруг объекта), но мне нужно было добавить некоторые правильные элементы управления моему Adorner.

Трюк для этого заключается в создании VisualCollection и установки вашего adorner в качестве его владельца, передав его в конструктор коллекции.

Все это описано довольно подробно в в этой статье в блоге. К сожалению, мои повторные поисковые запросы Google не превращали эту статью, пока я не знал, что нужно искать VisualCollection, благодаря руководству Генади.

Это не упоминается в статье, но обратите внимание, что можно комбинировать технику VisualCollection вместе с рисованием в методе OnRender у adorner. Я использую OnRender для достижения боковых и верхних границ, описанных в диаграмме выше, и используя VisualCollection для размещения и создания элементов управления.

Изменить: вот исходный код из упомянутого сообщения в блоге, поскольку он больше не доступен:

public class AdornerContentPresenter : Adorner
{
  private VisualCollection _Visuals;
  private ContentPresenter _ContentPresenter;

  public AdornerContentPresenter(UIElement adornedElement)
    : base(adornedElement)
  {
    _Visuals = new VisualCollection(this);
    _ContentPresenter = new ContentPresenter();
    _Visuals.Add(_ContentPresenter);
  }

  public AdornerContentPresenter(UIElement adornedElement, Visual content)
    : this(adornedElement)
  { Content = content; }

  protected override Size MeasureOverride(Size constraint)
  {
    _ContentPresenter.Measure(constraint);
    return _ContentPresenter.DesiredSize;
  }

  protected override Size ArrangeOverride(Size finalSize)
  {
    _ContentPresenter.Arrange(new Rect(0, 0,
         finalSize.Width, finalSize.Height));
    return _ContentPresenter.RenderSize;
  }

  protected override Visual GetVisualChild(int index)
  { return _Visuals[index]; }

  protected override int VisualChildrenCount
  { get { return _Visuals.Count; } }

  public object Content
  {
    get { return _ContentPresenter.Content; }
    set { _ContentPresenter.Content = value; }
  }
}

Ответ 2

Вам не нужно замарать руки, посмотрите эту статью CodeProject, которую я использовал в прошлом.

Он позволяет вам определять символы в XAML, делать привязки и т.д.