У меня есть приложение Blazor Wasm с двумя компонентами:
Базовая комп.бритва:
<h1>I'm base - @Text</h1>
@code{
protected string Text {get; set;} = "Default";
}
ChildComponent.razor
@inherits BaseComp
<BaseComp/>
<h1>Hello, only child text!</h1>
@code {
protected override void OnInitialized()
{
Text = "new";
}
}
и на странице будет отображаться следующее:
I'm base - Default
Hello, only child text!
Как я могу обновить свойство Text
базового компонента из дочернего компонента?
Вам нужно будет объявить его как параметр и передать значение вниз.
Базовая комп.бритва:
<h1>I'm base - @Text</h1>
@code{
[Parameter] public string Text {get; set;} = "Default";
}
ChildComponent.razor
<BaseComp Text = "Text"/>
<h1>Hello, only child text!</h1>
@code {
protected override void OnInitialized()
{
Text = "new";
}
}
К сожалению нет. Обычный способ сделать это — создать собственный класс, который содержит ваши свойства и передать этот экземпляр вниз.
@HenkHolterman да, ты прав. Я удалил его.
С этим фрагментом кода
@inherits BaseComp
<BaseComp/> @* a new instance, not inheritance *@
Вы наследуете и сочиняете с помощью BaseComp. Вы не используете часть наследования.
Поэтому используйте только композицию и следуйте ответу @MarvinKlein, но удалите строку @inherits
.
Или изменить код на:
@inherits BaseComp
@*<BaseComp />*@
@{ base.BuildRenderTree(__builder); }
<h1>Hello, only child text!</h1>
Я хочу использовать базовый компонент для отображения одной и той же сетки на всех страницах, но с некоторой дополнительной логикой. Решение @MarvinKlein и ваша работа, есть ли какие-либо недостатки при использовании метода BuildRenderTree?
Я хочу использовать базовый компонент для отображения одной и той же сетки на всех страницах, но с некоторой дополнительной логикой.
Тип шаблона, для которого текущий ComponentBase
не предназначен.
Вы также можете:
ComponentBase
.Вот как заставить его работать с ComponentBase, поскольку описание того, как создать другой компонент, выходит за рамки ответа SO.
Наш компонент-обертка:
<h3 class = "text-primary m-2 p-2">Wrapper</h3>
<div class = "bg-primary text-white m-2 p-2">
@this.Body
</div>
@code {
protected abstract RenderFragment? Body { get; }
}
И файл кода программной части, чтобы сделать его абстрактным.
public abstract partial class Wrapper { }
Наш новый Index
. Ключевым моментом здесь является то, что наш контент больше не находится в верхнем блоке — разделе, которому соответствует компилятор Razor BuildRenderTree
. Вместо этого мы определяем его в отдельном RenderFragment
.
Теперь наш верхний блок содержит свойство RenderFragment
, которому мы присвоили метод this.Body
базового класса, содержащий скомпилированный код из шаблона.
@page "/"
@inherits Wrapper
@this.Content
@code {
// Where we put the base Template class Render Fragment
private RenderFragment Content;
// Ctor - must call base and then we load the base Template class content
public Index() : base()
=> this.Content = (builder) => base.BuildRenderTree(builder);
// Our content that the Razor compiler will build in Body
// __builder is the built in Razor compiler RenderTreeBuilder
protected override RenderFragment Body => (__builder) =>
{
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
<div>Welcome to your new app.</div>
<SurveyPrompt Title = "How is Blazor working for you?" />
};
}
Вот как это выглядит:
Чтобы не было путаницы, я переименовал его в Wrapper
. Это просто демонстрация, чтобы показать, как вы можете сделать это с небольшими хитростями кода. Это определенно не защита от дурака. Я использую эту технику, но с совершенно другим компонентом Wrapper.
Это работает, когда я определяю свойство дочернего компонента, которое будет передано базовому компоненту, но есть ли другой способ добиться этого? Для нескольких параметров это может стать довольно подробным, потому что мне нужно определить одни и те же свойства как для базы, так и для дочернего элемента.