WPF, Viewbox

Єдине обмеження використання Canvas полягає в тому, що графіка не зможе самостійно підганяти свої розміри до більшого або меншого вікна. Це має сенс для кнопок (які не змінюють свого розміру у будь-яких ситуаціях), але не обов'язково для графічного вмісту інших типів.

Наприклад, можна створити складну графіку, яка повинна змінювати розміри, щоб отримати перевагу від доступного простору. Для таких ситуацій у WPF передбачено просте рішення. Щоб поєднувати тонкий контроль Canvas із простою зміною розмірів, слід використовувати елемент Viewbox.

Viewbox - це простий клас, успадкований від Decorator (який дуже схожий на клас Border). Він приймає єдиний дочірній елемент, який розтягує чи стискає для заповнення доступного простору. Природно, цим дочірнім елементом може бути контейнер компонування, що утримує безліч фігур (або інших елементів), які можуть змінювати синхронно свої розміри. Однак найчастіше Viewbox застосовують для векторної графіки, а не для звичайних елементів керування.

Хоча в елемент Viewbox можна помістити одиночну фігуру, це не дає реальних переваг. Навпаки, Viewbox виявляє себе у всій красі, коли необхідно обернути групу фігур, що утворюють загальний малюнок. Зазвичай всередину Viewbox міститься контейнер Canvas, а вже в нього - необхідні фігури.

У наступному прикладі у другому рядку Grid міститься Viewbox з контейнером Canvas. Елемент Viewbox займає повну висоту та ширину рядка. Рядок займає весь вільний простір, що залишився після візуалізації першого рядка з автоматичним розміром. Нижче наведено розмітку:

На малюнку показано, як Viewbox підлаштовується при зміні розмірів вікна. Перший рядокзалишається незмінною. Однак другий рядок розширюється для заповнення вільного простору. Як бачите, фігура в Viewbox змінюється пропорційно зі збільшенням вікна.

Viewbox

вміст

Масштабування, що здійснюється Viewbox, подібно до масштабування, яке ви бачили в WPF, збільшуючи значення DPI. Воно пропорційно змінює кожен екранний елемент, включаючи зображення, текст, лінії та фігури. Наприклад, якщо помістити всередину Viewbox звичайну кнопку, масштабування торкнеться її загального розміру, тексту всередині неї і товщини лінії кордону. У разі приміщення всередину Viewbox фігури пропорційно змінюється внутрішня область і рамка, тому чим більше зростає фігура, тим товщі стає її межа.

За промовчанням Viewbox виконує пропорційне масштабування, яке зберігає пропорції вмісту. У поточному прикладі це означає, що навіть якщо фігура містить рядки зміниться (ставши ширшими або довшими), фігури всередині не будуть спотворені.

Натомість Viewbox використовує найбільший масштабний множник, який дозволяє вміститися всередині доступного простору. Однак цю поведінку можна змінити за допомогою властивостіViewbox.Stretch. За замовчуванням воно встановлено Uniform, але допускається будь-яке значення. Змініть Viewbox.Stretch на Fill, і вміст Viewbox буде розтягуватися в обох напрямках, щоб зайняти повністю весь доступний простір, навіть якщо при цьому вихідний малюнок виявиться спотвореним.

За допомогою властивостіStretchDirection можна досягти більшого контролю. За замовчуванням ця властивість отримує значення Both, але можна встановити його в UpOnly, щоб створити вміст, який зможе зростати, але не більше за свій вихідний розмір, і DownOnly, щоб створити вміст, який може стискатися,але не рости.

Для того, щоб Viewbox продемонстрував свою "магію" масштабування, він повинен отримати дві одиниці інформації: звичайний розмір, який повинен мати вміст (якби він не знаходився всередині Viewbox), і новий розмір, який має бути для нього встановлений.

Друга деталь – новий розмір – досить проста. Viewbox відводить внутрішньому вмісту весь доступний простір, ґрунтуючись на значенні своєї властивості Stretch. Це означає, що чим більше Viewbox, тим більший вміст.

Перша деталь - звичайний розмір (без втручання Viewbox) - обчислюється за способом визначення вкладеного вмісту. У попередньому прикладі Canvas визначається явний розмір 200x150 одиниць. Таким чином, Viewbox масштабує зображення від початкового розміру. Наприклад, якщо еліпс спочатку має ширину 100 одиниць, тобто. заповнює половину виділеного Canvas простору, то зі зростанням Canvas елемент Viewbox зберігає ці пропорції і еліпс продовжує займати половину відведеного простору.

Однак подивимося, що трапиться, якщо видалити властивості Width та Height із Canvas. Тепер Canvas заданий розмір 0x0 одиниць, тому Viewbox не може змінити розмір, і вкладений вміст не з'являється. (Зовсім інакше справи при роботі тільки з Canvas без Viewbox. Незважаючи на те що Canvas також має розміри 0x0. фігурам, що містяться в ньому, дозволено малювати себе за його межами, доки властивість Canvas.ClipToBounds не встановлено в true. Елемент viewbox не настільки терпимий до подібної помилки.)

Тепер подивимося, що станеться, якщо помістити Canvas всередину комірки Grid, що пропорційно змінює розмір, і не вказати розміри Canvas. Без використання Viewbox такий підхід відмінно працює – контейнер Canvas стискається, щобуміститися в осередку, і його вміст залишається видимим. Але якщо помістити весь цей вміст у Viewbox, така стратегія не працює. Елемент Viewbox не може визначити початковий розмір, тому не може відповідно масштабувати Grid.

Цю проблему можна обійти, помістивши певні фігури (на кшталт Rectangle і Ellipse) безпосередньо у контейнер, що автоматично змінює розмір (такі як Grid). Viewbox може обчислити мінімальний розмір, необхідний Grid для приміщення свого вмісту, і потім масштабує його відповідним чином.

Однак найпростіший спосіб отримати потрібний розмір Viewbox - це помістити вміст в елемент фіксованого розміру, чи то Canvas, кнопка або щось інше. Цей фіксований розмір стає початковим розміром, який Viewbox використовує для своїх обчислень. Таке жорстке кодування розміру не обмежить гнучкості компонування, оскільки Viewbox змінює розмір пропорційно на основі доступного простору свого контейнера компонування.