WPF自定义控件绘图避免无限测量/排列循环



我正在构建一个自定义控件,根据一些数据进行一些自定义绘图。我想更新图纸时,安排被称为(即大小改变)。但是当我在ArrangeOverride()中改变我的Children时,我当然会得到一个无限循环。我怎样才能避免这种情况呢?

为了简单起见,对我来说重建整个视觉树更容易,而不是一次创建子节点并单独调整它们的大小。

有更好的方法吗?我也可以只使用DrawingContext对象并在那里调用我的绘图逻辑。

public class MyCanvas : Canvas
{
    private static int _drawCounter = 0;
    private System.Windows.Size _arrangeSize;
    private MyData _data;
    protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
    {
        _arrangeSize = arrangeSize;
        Draw();
        return base.ArrangeOverride(arrangeSize);
    }
    public void SetData(MyData data)
    {
        _data = data;
        Draw();
    }
    private void Draw()
    {
        Children.Clear();
        if (_data == null || _arrangeSize.IsEmpty)
        {
            return;
        }
        Children.Add(new TextBlock() {Text = (++_drawCounter).ToString()});
    }
}

我是这样解决的:

public class MyCanvas : Canvas
{
private readonly DispatcherTimer _dispatcherTimer;
private Size _arrangeSize;
private Size _drawnSize;
public MyCanvas()
{
    _dispatcherTimer = new DispatcherTimer(DispatcherPriority.Render)
        {
            Interval = TimeSpan.FromMilliseconds(500)
        };
    _dispatcherTimer.Tick += (sender, args) =>
        {
            var dispatcherTimer = (DispatcherTimer)sender;
            dispatcherTimer.Stop();
            Debug.WriteLine("Draw call from DispatcherTimer");
            Draw();
        };
}
protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
{
     _arrangeSize = arrangeSize;
    if (_drawnSize != _arrangeSize)
    {
        QueueDrawCall();
    }
    return base.ArrangeOverride(arrangeSize);
}
private void QueueDrawCall()
    {
        if (_dispatcherTimer.IsEnabled)
        {
            _dispatcherTimer.Stop();
        }
        _dispatcherTimer.Start();
    }
public void SetData(MyData data)
{
    _data = data;
    Console.WriteLine("Direct Draw Call " + data);
    Draw();
}
private void Draw()
{
    if (Children.Count > 0)
    {
        Children.Clear();
    }
    if (_data == null || _arrangeSize.IsEmpty)
    {
        return;
    }
    InternalDraw(); // Drawing logic goes in this function
    _drawnSize = _arrangeSize;
}
}

最新更新