Обновление WPF PathGeometry является _SLOW_

В UI WPF мне соединили узлы пути bezier, как так:

Это мог бы быть... атомарный http://nv3wrg.blu.livefilestore.com/y1pIGBd33lCC6lF-9H0MqgnL40BdNEoEemZDENzgpEI1IL2j4B-qb3qS3WlxMSys28IjqNngR7mdfvQBnPzerf4cFJQj9VqHBh4/acurve.png?psid=1

Когда пользователь перетаскивает узел вокруг, соединяющиеся пути должны быть обновлены в режиме реального времени. Однако я заметил некоторое замедление (особенно, если один узел подключен ко многим другим, или несколько узлов перетаскиваются сразу). Я представил его, и основная проблема, кажется, здесь:

Доказательство я на самом деле использовал профилировщика, поэтому не все как "OMG, преждевременный opiumzation; Вы - ДЕМОН!!" http://nv3wrg.blu.livefilestore.com/y1pjRfQYuN57yei5qdUxW4Dlh4vVCzPy8TcfEzlw_8cUicfOR6BwHCTntcQbQUspRAgBdKcItC0ZcEJbIWMKaYrCtDMOtCBKB4g/profile.png?psid=1

Это - функция, которая вызвана каждый раз или источник или целевое свойство изменяются. Геометрия, которая составляет путь, кажется, повторно создается внутренне каждый раз любое изменение контрольных точек. Возможно, если был способ препятствовать тому, чтобы геометрия была повторно создана, пока все соответствующие свойства зависимости не были установлены?

Править: Решение рынка использовать StreamGeometry ускорило его экспоненциально; функция нигде не близко к узкому месту. Немного Отражения предполагает, что PathGeometry использует StreamGeometry внутренне, и каждый раз, когда любое из свойств зависимости изменяется, StreamGeometry повторно вычисляется. Таким образом, этот путь просто отключает посредника. Конечный результат:

private void onRouteChanged()
{
    Point src = Source;
    Point dst = Destination;
    if (!src.X.isValid() || !src.Y.isValid() || !dst.X.isValid() || !dst.Y.isValid())
    {
        _shouldDraw = false;
        return;
    }

    /*
        * The control points are all laid out along midpoint lines, something like this:
        * 
        *   -------------------------------- 
        *  |          |          |          |
        *  |   SRC    |    CP1   |          |
        *  |          |          |          |
        *   -------------------------------- 
        *  |          |          |          |
        *  |          |    MID   |          |
        *  |          |          |          |
        *   ------------------------------- 
        *  |          |          |          |
        *  |          |    CP2   |    DST   |
        *  |          |          |          |
        *   -------------------------------- 
        *   
        * This causes it to be horizontal at the endpoints and vertical
        * at the midpoint.
        */

    double mx = (src.X + dst.X) / 2;
    double my = (src.Y + dst.Y) / 2;
    Point mid = new Point(mx, my);
    Point cp1 = new Point(mx, src.Y);
    Point cp2 = new Point(mx, dst.Y);

    _geometry.Clear();
    _shouldDraw = true;
    using(StreamGeometryContext ctx = _geometry.Open())
    {
        ctx.BeginFigure(src, false, false);
        ctx.QuadraticBezierTo(cp1, mid, true, false);
        ctx.QuadraticBezierTo(cp2, dst, true, false);
    }
}

Полный исходный код проекта доступен по http://zeal.codeplex.com для любопытного.

7
задан Robert Fraser 16 July 2010 в 05:10
поделиться

3 ответа

1- Я бы попробовал использовать StreamGeometry:

        StreamGeometry streamGeo = new StreamGeometry();
        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < 10000; i++)
        {
            streamGeo.Clear();
            var ctx = streamGeo.Open();
            ctx.BeginFigure(new Point(0, 0), false, false);
            ctx.QuadraticBezierTo(new Point(10, 10), new Point(10, i), true, true);
            ctx.Close();
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds); // For 10k it took 30 ms

Она выглядит намного быстрее, чем PathGeometry+PathFigure.

Когда вы устанавливаете Point для QuadraticBezierSegment, он все пересчитывает. Вот почему это медленно. И еще медленнее, когда он уже добавлен к геометрии.

2- Попробуйте использовать только 1 элемент рамки для всех ваших кривых. Проверьте это: Написание более эффективных элементов-контролов

7
ответ дан 7 December 2019 в 07:40
поделиться

Я полагаю, что ваши проблемы с производительностью происходят от FrameworkElement и из-за того, что механизм компоновки WPF пересчитывает компоновку по мере вычисления кривой.

Вы можете смоделировать кривую, спустившись с Freezable , а затем использовать FrameworkElement (например, PathGeometry) для отображения фактической геометрии.

0
ответ дан 7 December 2019 в 07:40
поделиться

Если вам не нужны проверка нажатия, контекстные меню, всплывающие подсказки для ваших кривых, вы можете использовать простые визуальные эффекты вместо элементов каркаса.

0
ответ дан 7 December 2019 в 07:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: