Мой код:
Родитель:
<ChildComponent UserName = "@userName"/>
Дочерний компонент:
<button disabled = "@disableForwardToUser">OK</button>
@code {
[Parameter]
public string UserName { get; set; }
private bool disableForwardToUser = false;
}
Теперь я хотел бы, чтобы приватный файл disableForwardToUser устанавливался в зависимости от значения UserName при загрузке компонента, примерно так:
if (string.IsNullOrEmpty(UserName))
{
disableForwardToUser = true;
}
Я пытался установить его непосредственно в поле, а также установить из конструктора, но получил сообщение, что я не могу установить значение поля таким образом из параметра. Как бы я это сделал?
Вы можете сделать это с помощью метода OnInitialize дочернего компонента следующим образом:
<h3>ChildComponent</h3>
<button disabled = "@disableForwardToUser">OK</button>
@disableForwardToUser
@code {
[Parameter]
public string UserName { get; set; }
private bool disableForwardToUser = false;
protected override void OnInitialized()
{
base.OnInitialized();
if (string.IsNullOrEmpty(UserName))
{
disableForwardToUser = true;
}
}
}
Вы правы, Однако Оскар сказал, что: when the component is loaded
[Вежливый] Совершенно правильный ответ (с использованием OnParametersSet), но вам не нужно использовать какие-либо методы жизненного цикла. Компонент отображается каждый раз, когда UserName обновляется, поэтому disableForwardToUser может быть простым геттером. Смотрите мой ответ ниже.
Интересно, что можно и так сделать, спасибо!
Вам не нужно использовать какие-либо события, просто простой геттер.
<button class = "btn btn-success" disabled = "@_disableForwardToUser">OK</button>
@code {
[Parameter] public string? UserName { get; set; }
private bool _disableForwardToUser => string.IsNullOrWhiteSpace(this.UserName);
}
Компонент отображается каждый раз при изменении UserName.
Вот моя тестовая страница:
@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<div class = "m-2 p-2">
<ChildComponent UserName = "@_userName" />
</div>
<div class = "m-2 p-2">
<button class = "btn btn-primary" @onclick=this.UpdateName>Change User</button>
</div>
@code {
private string? _userName;
private void UpdateName()
=> _userName = _userName is null ? "Fred" : null;
}
Сработало отлично, спасибо! Однако теперь disableForwardToUser доступен только для чтения, как мне дать ему «сеттер»? Я пытался сделать это так, но это не сработало: private bool disableForwardToUser { get => string.IsNullOrWhiteSpace(this.UserName); set; }
Зачем тебе сеттер? Как вы его установите? Это условно на основе значения this.UserName.
На самом деле мне это не нужно в этом конкретном случае, но я использую тот же код в другом случае, где мне также нужно установить значение поля в функции в компоненте. Как мне совместить лямбда-выражение на get с «нормальным» автоустановщиком set;, чтобы поле не было только готовым?
Добавьте еще одно поле, которое устанавливает ваш процесс, а затем выполните AND или OR в disableForwardToUser, чтобы получить правильный логический ответ.
Или, если это не сработает, опубликуйте здесь еще один вопрос с минимальным воспроизводимым примером.
Я создал отдельный вопрос с примером кода stackoverflow.com/questions/75542495/…
Вы также можете полностью реализовать геттер и сеттер для общедоступного свойства и назначать частную переменную каждый раз, когда происходит набор:
private string? username;
[Parameter]
public string? Username {
get => username; set {
username = value;
disableForwardToUser = string.IsNullOrWhiteSpace(username);
}
}
[Вежливо] Это не лучший способ сделать это. Вы должны объявлять параметры только со стандартным {get; set;}. Их ни в коем случае нельзя модифицировать, а зависание процессов от них затянет процесс настройки. В этом случае вы делаете что-то довольно простое, но как только вы перейдете эту границу, другие будут думать, что это нормально делать что угодно.
Я полагаю, что влияние на производительность зависит от того, сколько раз вызывается установщик и сколько раз будет вызываться частное свойство. В любом случае, если имя пользователя изменится, свойство также необходимо будет пересчитать, поэтому я не думаю, что есть накладные расходы, в конце концов вы можете проверить, равно ли новое значение старому, и избежать выполнения исчисления. Обычно в случае компонента Blazor свойство ввода устанавливается только один раз. Я думаю, что автоматически реализуемые свойства (стандартные) — это большое улучшение, но классическая реализация геттера и сеттера может быть использована без проблем, если это необходимо.
Прошу вежливо не согласиться. Давайте посмотрим на ваш пример. Вы связываете параметр с внутренним полем. Теперь допустим, что внутренний процесс в OnParametersSet устанавливает userName другое значение. Теперь у вас есть несоответствие между тем, что визуализатор считает значением, и тем, что оно есть на самом деле. Это может вызвать проблемы с различиями и рассинхронизацию пользовательского интерфейса с RenderTree.
Совет, который я считаю, исходит от команды Blazor, хотя я не могу найти соответствующую ссылку в данный момент. Вы можете делать то, что вам нравится, и если вы знаете, что делаете, вам это сойдет с рук. Многие здесь, кто читает ответы, не имеют такого уровня знаний и, полагая, что можно добавлять вещи в геттеры и сеттеры параметров, быстро попадут в беду.
В моем коде [Параметр] связан с общедоступным свойством Username, а не с закрытым резервным полем username. Таким образом, теоретически никто не может получить доступ к резервному полю из внешнего кода (кроме случаев, когда используется Reflection). В любом случае, я понимаю ваши комментарии и опасения. Поскольку я не нашел исходного кода, чтобы увидеть, как работает ParameterAttribute под крючком, я согласен, что лучше избегать моего решения. Я буду продолжать расследование, у вас есть какие-то документы? Спасибо
OnParametersSet()
лучше, так как вы хотите, чтобы параметры были установлены первыми.