/// <summary> /// Рендеринг компонента /// </summary> /// <param name="drawingContext">контекст рисования</param> protected override void OnRender(DrawingContext drawingContext) { #region Алгоритм подготовки к рисованию base.OnRender(drawingContext); //Текущая фактическая высота области рисования double currentHeight = this.RenderSize.Height - this.hScrollBar.RenderSize.Height; //Текущая фактическая ширина области рисования double currentWidth = this.RenderSize.Width - this.vScrollBar.RenderSize.Width; //Область рисования (вне этой области рисовать нельзя) Size clipSize = new Size(currentWidth, currentHeight); //ограничиваем drawingContext.PushClip(new RectangleGeometry(new Rect(new Point(0, 0), clipSize))); //очищаем фон drawingContext.DrawRectangle(this.ЦветФона, null, new Rect(new Point(0, 0), clipSize)); //Проверка на кол-во строк if (this.СписокСтрок.Count <= 0) { return; } //текущий индекс рисуемой строки int индекс = this.ИндексПервойВидимойСтроки; //текущая точка рисования на канвасе компонента Point текущаяТочкаРендеринга = new Point(0, 0); //учёт горизонтального скроллинга (если ползунок передвинут) (в случае когда не помещается полностью элемент) текущаяТочкаРендеринга.X = -this.hScrollBar.Value; //обнуляем вертикальный скролбар (нечего отображать) this.hScrollBar.Maximum = 0; //очистка Списка областей (прямоугольников), в которых отрисованы видымые элементы списка SourceData this.СписокПрямоугольныхОбластейВидимыхСтрок.Clear(); #endregion #region Цикл отрисовки видимых блоков (элементов) - пока они видны на экране (канвасе компонента) while (текущаяТочкаРендеринга.Y < currentHeight) { //Проверка индексов на допустимость if (индекс < 0) { return; } //Обработка ситуации превышения текущего индекса над общим кол-вом строк if (индекс >= this.СписокСтрок.Count) { break; } //преобразоваем элемент пользовательского типа в универсальный шаблон отображения BlockBase блокТекущейРисуемойСтроки = this.ConvertToBlockTemplate(this.СписокСтрок[индекс], индекс); //рендерим шаблон DrawingVisual визуальныйБуферТекущейРисуемойСтроки = блокТекущейРисуемойСтроки.Render(текущаяТочкаРендеринга); //рисуем его на канвасе компонента drawingContext.DrawDrawing(визуальныйБуферТекущейРисуемойСтроки.Drawing); //область рисования текущего шаблона Rect прямоугольнаяОбластьТекущейРисуемойСтроки = new Rect(текущаяТочкаРендеринга, блокТекущейРисуемойСтроки.RenderSize); //добавляем его в список (пригодится для реализации клика по элементу) this.СписокПрямоугольныхОбластейВидимыхСтрок.Add(прямоугольнаяОбластьТекущейРисуемойСтроки); //выбираем самую длинную ширину (самы длинный элемент) (для реализации горизонтального скроллинга) double deltaWidth = блокТекущейРисуемойСтроки.RenderSize.Width - currentWidth; if (deltaWidth > 0) { if (this.hScrollBar.Maximum <= deltaWidth) { this.hScrollBar.Maximum = deltaWidth; hScrollBar.IsEnabled = true; } } //переходим вниз, на свободное место для рисования текущаяТочкаРендеринга.Y += блокТекущейРисуемойСтроки.RenderSize.Height; //переход к следующей строке индекс++; } #endregion #region Выделение активной строки - отрисовка курсора if ((ПозицияКурсора_Строка >= ИндексПервойВидимойСтроки) && (ПозицияКурсора_Строка < (ИндексПервойВидимойСтроки + СписокПрямоугольныхОбластейВидимыхСтрок.Count))) { //отрисовка курсора - по факту это прямоугольник :))) drawingContext.DrawRectangle ( this.Foreground /*цвет курсора*/, null, new Rect ( СписокПрямоугольныхОбластейВидимыхСтрок[ПозицияКурсора_Строка - ИндексПервойВидимойСтроки].TopRight /*Положение курсора*/, new Size ( ШиринаКурсора /*установка ширины курсора*/, СписокПрямоугольныхОбластейВидимыхСтрок[ПозицияКурсора_Строка - ИндексПервойВидимойСтроки].Height /*Установка высоты курсора*/ ) ) ); } #endregion }