Двоетапний процес розміщення

В об'єкті будь-якої панелі автоматично застосовується той самий двоетапний процес встановлення розмірів та розміщення дочірніх елементів. На першому етапі виконується обчислення розмірів дочірніх елементів та характерних відстаней, а на другому – власне розміщення дочірніх елементів. Два етапи необхідні тому, що панель повинна врахувати вимоги всіх дочірніх елементів перед тим, як розподілити доступний простір.

Додати код, що управляє цими двома етапами, можна, перевизначивши методи MeasureOverride() та ArrangeOverride(), визначені в класі FrameworkElement платформи Silverlight. Зазначені методи замінюють логіку методів MeasureCore() та ArrangeCore(), визначених у класі UIElement. Останні два методи для програмного коду недоступні і перевизначити їх неможливо.

Перший етап - обчислення простору, необхідного кожному дочірньому елементу за допомогою методу MeasureOverride (). Однак навіть у методі MeasureOverride () дочірнім елементам не надано безмежний простір. Як мінімум, вони обмежені простором, доступним для панелі. За потреби їх можна обмежити ще жорсткіше. Наприклад, панель Grid із двома пропорційними рядками надає дочірнім елементам половину доступної висоти. Панель StackPanel надає першому елементу весь доступний простір, другому все, що залишилося після розміщення першого, третьому все, що залишилося після розміщення перших двох, і т.д.

Кожна реалізація MeasureOverride () проходить у циклі за колекцією дочірніх елементів та викликає для кожного з них метод Measure(). Йому передається об'єкт Size, який визначає максимально доступний простір для дочірнього елемента управління. В кінці методу MeasureOverride () панель повертає простір,необхідне для відображення всіх дочірніх елементів та бажані розміри елементів.

Нижче наведено базову структуру методу MeasureOverride () без специфічних операторів установки розмірів.

protected override Size MeasureOverride(Size constraint)

// Прохід всім дочірнім елементам

foreach (UIElement element in this.Children)

// Обчислення простору, необхідного для поточного

// дочірньому елементу з урахуванням обмежень availableSize

Size availableSize = new Size (…);

// Тепер можна отримати запитаний

// Розмір з element.DesiredSize

// Обчислення простору, який буде необхідний панелі; // воно буде використано для встановлення // властивості DesiredSize панелі return new Size (…);

Метод Measure() не повертає значення. Після виклику методу Measured через дочірній елемент, запитаний розмір надається у властивості DesiredSize дочірнього елемента. Цю інформацію можна використовувати для розміщення наступних дочірніх елементів та обчислення загального простору, необхідного панелі.

Виклик методу Measure () є обов'язковим для кожного дочірнього елемента, навіть якщо ви не плануєте обмежувати його розміри або застосовувати його властивість DesiredSize. Багато елементів не відображаються на екрані, доки через них не буде викликано метод Measure (). Якщо потрібно надати дочірньому елементу можливість зайняти весь вільний простір, який він забажає, передайте як параметр об'єкт Size зі значеннями Double. Positivelnf inity для обох координат (зазвичай такий спосіб використовується для елемента прокручування ScrollViewer, оскільки він повинен охоплювати весь вміст). При значенні Positivelnfinity дочірній елемент повертає простір, необхідний його вмісту. Інакшеу разі він повертає одне з двох значень (менше з двох): або простір, необхідний для вмісту, або доступний простір.

Наприкінці процесу обчислення контейнер повинен повернути бажаний розмір. Для простої панелі її бажаний розмір обчислюється з урахуванням бажаних розмірів кожного дочірнього елемента.

Примітка. Як бажаний розмір панелі можна просто повернути обмеження, передане методу MeasureOverride (). На перший погляд це здається чудовим способом отримання всього доступного простору, проте такий спосіб призведе до серйозних проблем, якщо як одна або обидві координати передається об'єкт Size зі значеннями Double. Positivelnfinity (об'єкт Positivelnfinity в даному випадку означає "візьміть весь простір, скільки захочете"). Як обмеження допустиме нескінченне значення, проте як розмір воно неприпустиме. Надбудова Silverlight не зможе зрозуміти, якими мають бути розміри елемента. Крім того, не слід вимагати більше простору, ніж необхідно. Зайвий простір змусить наступні елементи, які розміщуються після панелі, переміститися вниз, внаслідок чого буде створено порожній простір на екрані.

Уважні читачі вже, напевно, помітили схожість між методами Measure)), що викликаються через кожен дочірній елемент, та методами MeasureOverride (), що визначають перший етап обробки панелі. Фактично метод Measure() запускає метод MeasureOverride(). Отже, якщо контейнери вкладені один в одного, то при виклику Measure () ви отримаєте загальний розмір, необхідний для зовнішнього контейнера та всіх його дочірніх елементів.

Одна з причин того, що обчислення простору має виконуватися у два етапи, полягає у необхідності враховувати зовнішні смужки. Привиклик методу Measure () він отримує загальний доступний простір, а при виклик MeasureOverride () доступний простір автоматично зменшується для обліку зовнішніх смужок (природно, якщо не передано нескінченне значення розміру).

Джерело: Мак-Дональд, Метью. Silverlight 3 із прикладами на С# для професіоналів. : Пров. з англ. - М.: ТОВ «І.Д. Вільямі», 2010. - 656 с. : іл. - Парал. тит. англ.