Переместить UIElement в Visual Tree без пересчета макета - PullRequest
2 голосов
/ 19 октября 2010

У нас есть приложение WPF (.Net 4.0), использующее Docking Control (Actipro).Мы можем закрепить окна стыковки.В этом случае создается «реальное» окно, и контент назначается этому окну.

Конечно, перемещение материала в дереве визуалов будет повторно запускать полный макет .Это проблематично, потому что в одном из этих стыковочных окон у нас есть элемент управления диаграммами (Mindfusion Diagramming, WPF control), который может занять до 10 секунд для полной компоновки (очень большие диаграммы).Не думаю, что есть прямое решение этой проблемы.Однако мне интересно, как другие программисты с подобными проблемами подошли к этой проблеме.Есть ли какой-нибудь умный способ избежать пересчета макета?

Теоретически ничего не меняется на самом деле , поскольку диаграмма находится внутри ScrollViewer, поэтому при каждом размещении объем доступного пространства остается неизменным (бесконечным).

Редактировать: Также обратите внимание, что элемент управления диаграммы внутри является интерактивным.Нам нужен Drag & Drop.

Ответы [ 3 ]

4 голосов
/ 28 октября 2010

Вот идея.

  1. Создание собственного класса, наследуемого от Decorator.
  2. Оберните ваш элемент управления диаграммами внутри декоратора.
  3. Переопределите MeasureOverride и просто вызовите base.Measure, но перед возвратом сохраните результат в поле.
  4. Добавить свойство, которое позволяет отключить вызов меры. Если свойство имеет значение true, просто верните предыдущий размер в MeasureOverride вместо вызова base.Measure.
  5. Установить свойство при изменении визуальной иерархии.

Сверху головы я не могу придумать ни одной причины, почему это не должно работать.

Я действительно сделал нечто очень похожее не так давно. При реализации анимации скольжения для боковых панелей в NovaMind я использовал декоратор, чтобы запретить контенту выполнять макет, пока панель анимирует свою ширину. Я рассчитал размер с окончательной шириной, сохранил его и затем использовал MeasureOverride для подделки текущего размера ... Это предотвратило проблемы с производительностью, возникающие при попытке анимировать ширину сложного элемента управления. :)

1 голос
/ 28 января 2013

Другая возможность заключается в том, что проблема связана не с макетом, а с «разрывом» визуального дерева при перемещении контента из одного окна в другое.Похоже, это вызывает массу пересчетов для свойств зависимостей, которые, если ваше визуальное дерево для контента было похоже на мое, превышало 2000 элементов управления, это было бы очень медленно.

Я не мог найти элегантное решение для этого, используяСама библиотека стыковки Actipro, поэтому я подумал, как можно отвести WPF от такого поведения.Решение, которое я придумал, состояло в том, чтобы создать свой контент в виде единого элемента управления WinFormsHost с одним дочерним элементом WinForms UserControl.Затем я сделал так, чтобы в WinForms UserControl его содержимое было содержимым на основе WPF, которое должно отображаться как содержимое окна стыковки.Я полагал, что когда WPF начнет обходить визуальное дерево сверху, чтобы переоценить все свойства зависимостей, когда дерево было «обрезано», оно попадет в элемент управления WinForms и остановится.

Используются окна инструментов закрепления Actiproзаймет около 6 секунд, чтобы просто переключать вкладки или плавать.Теперь они по сути инстинктивны.Вы должны убедиться, что любые обработчики команд находятся не на уровне приложения, а на уровне содержимого WPF, и вам, возможно, придется определить местоположение некоторых файлов стилей, но это работало фантастически.

0 голосов
/ 19 октября 2010

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

примерно так:

// image is the Image from the visual tree
int h = image.ActualHeight;
int w = image.ActualWidth;

// layout the diagram to the size of the image
diagram.Measure(new Size(w, h));
diagram.Arrange(new Rect(newSize(w,h)));
diagram.UpdateLayout();

// render the diagram to a bitmap
RenderTargetBitmap bmp = new RenderTargetBitmap((int)w, (int)h, 96, 96, PixelFormats.Default);
bmp.Render(diagram);

// set the source of your image to the bitmap
image.Source = bmp;

в примере, если PixelFormats.Default не работает, вы можете попробовать PixelFormats.Pbgra32, который, я думаю, является более распространенным форматом для использованияв этом типе вещей.

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

...