Форум программистов, компьютерный форум, киберфорум
C#: ASP.NET Core
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.78/9: Рейтинг темы: голосов - 9, средняя оценка - 4.78
1338 / 918 / 264
Регистрация: 08.08.2014
Сообщений: 2,759

Blazor: запрет на рендеринг вложенного компонента

12.01.2023, 12:46. Показов 2009. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть три своих компонента, которые в разметке можно использовать следующим образом:
XML
1
2
3
4
5
6
<Container>
  <Items>
    <Item />
    <Item />
  </Items>
</Container>
При этом 'Items' и 'Item' хоть и реализованы как полноценные blazor-компоненты, но на деле нужны исключительно для удобного описания структуры вложенных компонентов в клиентском коде. Т.е. в них отсутствуют любые визуальные элементы.

Вопрос - можно ли как-то штатными средствами отключить для 'Items' и 'Item' процедуру рендеринга (и первую, и все последующие)?

Но не через protected override bool ShouldRender() => false;, а как-то более основательно? Т.к. если отключать через 'ShouldRender', то и первая перерисовка всё равно происходит, и при всех последующих рендерах родительского компонента, фреймворк всё равно перебирает всех потомков и для каждого делает вызов 'ShouldRender', что пусть и незначительно, но всё же повышает общее время перерисовки.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
12.01.2023, 12:46
Ответы с готовыми решениями:

Blazor: нюансы реализации компонента
Пытаюсь сделать простейший вариант typeahead-компонента, есть некоторые вопросы. Функционал, который требуется получить (вроде...

Blazor @onclick срабатывает и для вложенного тега, и для родительского
&lt;div style=&quot;background:red&quot; class=&quot;company-element&quot; @onclick=&quot;@(e=&gt;selectCompanyElement(company.Id))&quot;&gt; &lt;a...

Как вызвать POST запрос из компонента Blazor?
Здравствуйте, Есть Web MVC приложение на ASP.NET Core. На некоторых страницах есть Blazor компонеты. Как вызвать POST запрос допустим...

12
628 / 392 / 135
Регистрация: 06.03.2017
Сообщений: 1,469
14.01.2023, 12:07
можно использовать директиву @code, в которой можно указать, что компонент не должен быть отрисован. Например, для компонента 'Items':

C#
1
2
3
@code {
protected override bool ShouldRender() => false;
}
Также можно использовать директиву @if для отключения рендеринга компонента в зависимости от некоторого условия

C#
1
2
3
4
5
6
7
@if(condition)
{
<Items>
<Item />
<Item />
</Items>
}
1
1338 / 918 / 264
Регистрация: 08.08.2014
Сообщений: 2,759
15.01.2023, 01:44  [ТС]
Pilarentes,
Спасибо, но это не то (я там выше про это написал):
1. Если использовать '@if', то запускается и весь цикл рендеринга (ShouldRender, AfterRender), и сам процесс рендеринга шаблона.
2. Если использовать 'ShouldRender', который возвращает 'false', то рендеринг не выполняется, но фреймворк всё равно опрашивает компонент и вызывает для него 'ShouldRender' (каждый раз, хотя в этом нет никакой надобности, т.к. компонент не содержит никаких визуальных элементов).
0
1152 / 860 / 263
Регистрация: 30.04.2009
Сообщений: 3,603
15.01.2023, 13:03
kotelok, сколько времени занимает этот опрос например для миллиона компонентов?
1
1338 / 918 / 264
Регистрация: 08.08.2014
Сообщений: 2,759
17.01.2023, 07:56  [ТС]
Цитата Сообщение от nicolas2008 Посмотреть сообщение
сколько времени занимает этот опрос например для миллиона компонентов
Это не важно. Опрос происходит, когда он совершенно точно никогда не нужен.

В итоге есть два решения:
1. У компонента 'Container' при первом рендеринге установить в 'null' RenderFragment вложенного контента. Первый рендеринг для него всё равно отрабатывает, но последующие уже нет.

2. Вместо тех вложенных компонентов, которые нужны исключительно для предоставления данных родительскому компоненту, использовать обычные классы и коллекции их экземпляров. Однако, в разметке это выглядит не очень красиво и удобно.
0
1338 / 918 / 264
Регистрация: 08.08.2014
Сообщений: 2,759
17.01.2023, 19:55  [ТС]
В общем, первый способ работает даже лучше, чем ожидалось. Если занулить делегат 'RenderFragment', в котором "лежат" все вложенные компоненты, то при следующем рендеринге контейнера верхнего уровня, движок blazor это понимает, корректно диспозит экземпляры всех вложенных компонентов (с учётом всех уровней вложенности), более не пытается их рендерить и они становятся доступны для сборщика мусора.

В итоге и инициализирвоать компонент можно удобным способом прямо через разметку, и память/процессор не расходуются на мусорные экземпляры псевдо-компонентов на протяжении всего времени работы приложения.
0
30.01.2023, 20:45

Не по теме:

Я могу ошибаться, но использовать компоненты для хранения данных — так себе практика.

Если не сложно, можете описать кейс, где такой подход оправдан?

0
1338 / 918 / 264
Регистрация: 08.08.2014
Сообщений: 2,759
30.01.2023, 23:34  [ТС]
Цитата Сообщение от big1991 Посмотреть сообщение
Я могу ошибаться, но использовать компоненты для хранения данных — так себе практика.
Это для удобного описания многоуровневых компонентов в разметке:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<MainMenu Mode=MenuModes.Left>
  <MenuItem Title="File">
    <MenuItem Title="New" Icon="/images/new.png" />
    <MenuItem Title="Load" />
    <MenuItem Title="Exit" />
  </MenuItem>
  <MenuItem Title="Settings">
    <MenuItem Title="Theme">
      <MenuItem Title="Dark" />
      <MenuItem Title="Light" />
      <MenuItem Title="Contrast" />
    </MenuItem>
  </MenuItem>
</MainMenu>
При этом 'MenuItem' сами ничего не рендерят и используются исключительно для описания меню в клиентском коде. Полная отрисовка всего меню выполняется в компоненте 'MainMenu'.

Да, один из вариантов - сделать каждый 'MenuItem' полноценным маленьким компонентом, который отрисовывает себя в родительском контейнере. Однако, в этом случае сложнее управлять состоянием меню в целом, сложнее реализовывать навигацию при помощи клавиатуры.

Ну и ещё это порождает существенное повышение затрат на рендеринг меню в целом, т.к. если весь рендеринг только в компоннете 'MainMenu', то это один цикл отрисовки (ShouldRender -> Render -> AfterRender) и обработка всего одного шаблона, внутри которого пара циклов и всё. А если каждый 'MenuItem' является полноценным компонентом, то при каждой перерисовке меню, blazor вынужден выполнять полный цикл перерисовки для всех MenuItem, входящих в меню.

Кстати, то решение, которое я выше обозначил, на самом деле не рабтает, т.к. если занулить 'ChildContent', то движок фреймворка начинает вести себя странно. Например, после сборки мусора начинает с нуля пересоздавать экземпляры всех вложенных компонентов и снова инициализирует 'ChildContent' новым экземляром 'RenderFragment'.

Так что единственно решение, которое на данный момент доступно, хоть и не очень удобно, но даёт именно нужный результат:
XML
1
<MainMenu Items=@_items />
Где '_items' - многоуровневая коллекция обычных (не blazor-компонентов) экземпляров класса 'Item', описывающего пункт меню. В клиентском коде это не очень удобно, но по сути это единственный правильный подход, т.к. 'RenderFragment' нужен именно для описания каких-то шаблонов компонентов, т.е. того, что реально рендерится внутри родительского копонента.
0
Уважайте чужое время
75 / 23 / 8
Регистрация: 01.02.2013
Сообщений: 191
30.01.2023, 23:46
Цитата Сообщение от kotelok Посмотреть сообщение
для описания меню в клиентском коде
У Вас меню скорее всего опирается на какую-то модель или вроде того. Вы можете объединить эти сущности каким-то интерфейсом и строить меню динамически.

Можно даже без DI: немножко рефлексии и в клиентском коде абсолютно чисто, всего лишь интерфейс/атрибут на нужных элементах =)
0
1338 / 918 / 264
Регистрация: 08.08.2014
Сообщений: 2,759
31.01.2023, 14:35  [ТС]
Цитата Сообщение от big1991 Посмотреть сообщение
в клиентском коде абсолютно чисто
Самый удобный и интуиитивно понятный для клиентского кода вариант - тот, что показан в первом примере в предыдущем сообщении.

Однако, в силу особенностей Blazor, использовать его возможности нет. А потому остаётся лишь один вариант - описывать меню через какую-то модель и передавать в коллекцию 'Items' (второй пример в предыдущем сообщении).
0
Уважайте чужое время
75 / 23 / 8
Регистрация: 01.02.2013
Сообщений: 191
31.01.2023, 17:23
Цитата Сообщение от kotelok Посмотреть сообщение
остаётся лишь один вариант
Это ложное утверждение. Пример ещё одного подхода я Вам выше описал, причём без явного описания меню как отдельной сущности. Также понятный и тем паче удобный, разве что немного более трудоёмкий с Вашей стороны.
1
1338 / 918 / 264
Регистрация: 08.08.2014
Сообщений: 2,759
31.01.2023, 17:35  [ТС]
big1991,
Я даже отдалённо не понял, что именно вы предлагаете.

Можете показать на примере, как это будет выглядеть в разметке?
0
Уважайте чужое время
75 / 23 / 8
Регистрация: 01.02.2013
Сообщений: 191
31.01.2023, 18:00
Ну образно вроде такого:

C#
1
2
3
4
5
6
7
8
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
        <li class="nav-item px-3 collapse">
            <span class="oi oi-grid-two-up" aria-hidden="true"></span> Entities
            <GeneratedNavigation CategoryKey="Entities"/>
        </li>
    </ul>
</div>
И компонент GeneratedNavigation вроде

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<ul class="nav flex-column">
@foreach(var item in Items)
{
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="@item.Link">
            <span class="oi @item.AdditionalStyle" aria-hidden="true"></span> @item.Caption
        </NavLink>
    </li>
}
</ul>
@code {
    [Parameter]
    public string CategoryKey { get; set; }
 
    /// Элементы
    public List<NavigationMenuItemAttribute> Items => YourAssemblyTypes.Select(it => it.GetAttribute<NavigationMenuItemAttribute>()).Where(it => it != null).ToList(); // понятное дело, можете это получать из контроллера
}
Добавлено через 3 минуты
А в клиентском коде:

C#
1
2
3
4
5
    [NavigationMenuItem(typeof(Entity), "Entities")]
    [Id("EE2C591C-A391-4690-A9AA-C8D105A3BBF1")]
    public class Entity
        : IEntity
    {}

В апи собсна атрибут вроде такого:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    /// <summary>
    /// Пункт меню навигации
    /// </summary>
    public class NavigationMenuItemAttribute : Attribute
    {
        public NavigationMenuItemAttribute(Type type, string categoryKey)
        {
            Type = type;
            Caption = XmlDocHelper.GetXmlTitle(type);
            CategoryKey = categoryKey;
        }
 
        /// <summary>
        /// Ссылка
        /// </summary>
        public Type Type { get; }
 
        /// <summary>
        /// Ссылка
        /// TODO Можно префикс сделать в классах-потомках, а этот атрибут сделать базовым-абстрактным, либо запечатать атрибут и опираться на FullName типа для определения хлебных крошек
        /// </summary>
        public string Link => $"Entity/{Type.FullName}";
 
        /// <summary>
        /// Отображаемое название ссылки
        /// </summary>
        public string Caption { get; }
 
        /// <summary>
        /// Дополнительный стиль иконки можете сделать сущностью, чтобы поменьше выстрелов в ноги
        /// </summary>
        public string AdditionalStyle { get; }
 
        /// <summary>
        /// Ключ раздела
        /// Подобие группировки пунктов меню
        /// </summary>
        public string CategoryKey { get; }
 
        public bool IsCompatibleWithKey(string key) => CategoryKey == key;
    }
Добавлено через 1 минуту
Разумеется, это сырая имплементация, можно сделать красивее и гибче, при желании.
И вешать атрибут можно не на сущности, а на что угодно, для чего сможете имплементировать View.

Добавлено через 4 минуты
Чтобы избежать отстрела ног с категориями, их имена могут быть либо константами (не интуитивно), либо nameof() от доп.абстракций (громоздко).
А атрибутом можно очень много вертеть и кастомизировать: например добавить признак того, что сущность является не только пунктом (или не пунктом) меню, но и категорией.

Ну, я пользуюсь таким велосипедом для этих целей (очень лень описывать меню руками), мб Вам не зайдёт)
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
31.01.2023, 18:00
Помогаю со студенческими работами здесь

QML. Не вызываются функции из вложенного компонента
Всем привет! Изучаю недавно QML не могу разобраться Есть главный компонент MainForm.ui.qml и в нём вложенный MainForm.ui.qml ...

3д моделирование и рендеринг одно и тоже?Что такое рендеринг?
3д моделирование и рендеринг одно и тоже?Что такое рендеринг?

Запрет добавления компонента на форму в дизайнере
Как правильно запретить добавление компонента на форму в дизайнере по определенному условию (условие, допустим, в конструкторе компонента)?...

Запрет изменения состояния индикации компонента CheckListBox
Собственно, сама суть проблемы находится в названии темы. Возможно ли это вообще? Или стоит использовать какой-нибудь другой компонент? ...

Запрет ручного ввода для компонента DateTimeEdit
Добрый день, уважаемые. Подскажите пожалуйста, каким образом можно запретить ввод с клавиатуры всякого бреда в DateTimeEdit? Т.е. нужно...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru