Beispiel #1
0
        /// <summary>
        /// Получает для указанного контрола full render buffer и применяет его последовательно
        /// ко всем родительским элементам управления, вплоть до изображения на экране.
        /// Возвращает прямоугольник, необходимый для ревалидации на экране (affected rect).
        /// Учитывает Z-Order контролов-соседей (если родительский контрол имеет несколько дочерних, они могут перекрывать
        /// друг друга).
        /// Первый вызов производится с affectedRect = control.RenderSize.
        /// </summary>
        /// <returns>Affected rectangle in canvas should be copyied to console screen.</returns>
        private Rect applyChangesToCanvas(Control control, Rect affectedRect)
        {
            // если системой лайаута были определены размеры дочернего контрола, превышающие размеры слота
            // (такое может произойти, если дочерний контрол игнорирует переданные аргументы в MeasureOverride
            // и ArrangeOverride), то в этом месте может прийти affectedRect, выходящий за рамки
            // текущего RenderSize контрола, и мы должны выполнить intersection для корректного наложения
            affectedRect.Intersect(new Rect(new Point(0, 0), control.RenderSize));
            RenderingBuffer fullBuffer = getOrCreateFullBufferForControl(control);

            if (control.Parent != null)
            {
                RenderingBuffer fullParentBuffer = getOrCreateFullBufferForControl(control.Parent);
                // если буфер контрола содержит opacity пиксели в affectedRect, то мы вынуждены переинициализировать
                // буфер парента целиком (не вызывая Render, конечно, но переналожением буферов дочерних элементов)
                if (fullBuffer.ContainsOpacity(affectedRect))
                {
                    fullParentBuffer.Clear();
                    fullParentBuffer.CopyFrom(getOrCreateBufferForControl(control.Parent));
                    foreach (Control child in control.Parent.Children)
                    {
                        if (child.Visibility == Visibility.Visible)
                        {
                            RenderingBuffer childBuffer = getOrCreateFullBufferForControl(child);
                            fullParentBuffer.ApplyChild(childBuffer, child.ActualOffset,
                                                        child.RenderSize, child.RenderSlotRect, child.LayoutClip);
                        }
                    }
                }

                if (control.Visibility == Visibility.Visible)
                {
                    if (affectedRect == new Rect(new Point(0, 0), control.RenderSize))
                    {
                        fullParentBuffer.ApplyChild(fullBuffer, control.ActualOffset,
                                                    control.RenderSize, control.RenderSlotRect, control.LayoutClip);
                    }
                    else
                    {
                        fullParentBuffer.ApplyChild(fullBuffer, control.ActualOffset,
                                                    control.RenderSize, control.RenderSlotRect, control.LayoutClip,
                                                    affectedRect);
                    }
                }

                // определим соседей контрола, которые могут перекрывать его
                IList <Control> neighbors = control.Parent.GetChildrenOrderedByZIndex();

                // восстанавливаем изображение поверх обновленного контрола, если
                // имеются контролы, лежащие выше по z-order
                int controlIndex = neighbors.IndexOf(control);
                // начиная с controlIndex + 1 в списке лежат контролы с z-index больше чем z-index текущего контрола
                for (int i = controlIndex + 1; i < neighbors.Count; i++)
                {
                    Control neighbor = neighbors[i];
                    fullParentBuffer.ApplyChild(getOrCreateFullBufferForControl(neighbor),
                                                neighbor.ActualOffset, neighbor.RenderSize,
                                                neighbor.RenderSlotRect, neighbor.LayoutClip);
                }
                Rect parentAffectedRect = control.RenderSlotRect;
                parentAffectedRect.Intersect(new Rect(affectedRect.x + control.ActualOffset.x,
                                                      affectedRect.y + control.ActualOffset.y,
                                                      affectedRect.width,
                                                      affectedRect.height));
                // нет смысла продолжать подъем вверх по дереву, если контрола точно уже не видно
                if (parentAffectedRect.IsEmpty)
                {
                    return(Rect.Empty);
                }
                return(applyChangesToCanvas(control.Parent, parentAffectedRect));
            }
            else
            {
                if (control != RootElement)
                {
                    throw new InvalidOperationException("Assertion failed.");
                }

                // мы добрались до экрана консоли
                fullBuffer.CopyToPhysicalCanvas(Canvas, affectedRect, RootElementRect.TopLeft);
                return(affectedRect);
            }
        }