Анимация внутри рекламодателя (звонит OnRender) - PullRequest
6 голосов
/ 25 февраля 2009

Я использую Adorner в .NET 3.5, и я могу рисовать, переопределив OnRender, но мне нужна возможность перерисовать Adorner, чтобы изменить его внешний вид.

По сути, я ищу способ очистить контекст рисования и снова вызвать OnRender. Какой лучший способ сделать это, или есть лучший подход?

public class MyAdorner : Adorner
{
    private Brush brush = Brushes.Red;

    public DragArrowAdorner(UIElement adornedElement) : base(adornedElement)
    {}

    public void RedrawWithBrush(Brush newBrush)
    {
        brush = newBrush;

        // redraw..?
    }

    protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
    {
        // some drawing code...
        drawingContext.DrawRectangle(
            brush, 
            null, 
            new Rect(AdornedElement.DesiredSize));
    }
}

Ответы [ 2 ]

10 голосов
/ 25 февраля 2009

Для ответа на ваш вопрос используйте InvalidateVisual, чтобы снова вызвать OnRender

Тем не менее, я бы предложил вместо самостоятельного рисования на OnRender самостоятельно использовать стандартные стили и шаблоны визуальных деревьев для создания фактического визуального оформления рекламодателя. Это также означает, что вы можете запускать стандартные анимации XAML внутри него с раскадровками.

Если вы хотите использовать этот подход, в вашем классе для поклонников вам необходимо:

  • в конструкторе либо вызовите base.AddVisualChild(), либо создайте свою собственную коллекцию визуалов с визуалами, которые вы хотите показать в рекламодателе
  • переопределить ArrangeOverride(Size size), чтобы правильно расположить детей;
  • переопределить VisualChildrenCount, чтобы вернуть количество детей в визуальном дереве рекламодателя;
  • переопределить GetCisualChild(int index), чтобы вернуть конкретного ребенка.

Для получения дополнительной информации см. ResizingAdorner Образец MSDN.

2 голосов
/ 10 июня 2017

Очень важно понимать, что WPF не похож на Windows.Forms. OnRender() действительно нужно назвать AccumulateDrawingObjects(), потому что это то, что он делает. WPF накапливает кучу объектов рисования, которые он сохраняет, чтобы иметь возможность рисовать пользовательский интерфейс, когда это необходимо. Магия эффективного обновления пользовательского интерфейса заключается в том, что вы можете изменять объекты в этом визуальном дереве после OnRender().

Например, вы можете создать DrawingGroup «backingStore» и поместить его в DrawingContext во время OnRender. Затем в любое время, когда вы захотите изменить визуальный элемент, вы можете DrawingGroup.Open(), добавить в него новые команды рисования, и WPF будет эффективно повторно визуализировать эту часть интерфейса.

Это выглядит так:

DrawingGroup backingStore = new DrawingGroup();

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

    Render(); // put content into our backingStore
    drawingContext.DrawDrawing(backingStore);
}

// I can call this anytime, and it'll update my visual drawing
// without ever triggering layout or OnRender()
private void Render() {            
    var drawingContext = backingStore.Open();
    Render(drawingContext);
    drawingContext.Close();            
}
...