У меня есть довольно простой компонент, который выглядит следующим образом:
<form>
<div class="form-group">
<label for="sampleText">Sample Text</label>
<input type="text"
class="form-control"
id="sampleText"
aria-describedby="sampleTextHelp"
placeholder="Enter a text"
@bind="@Value" />
<small id="sampleTextHelp" class="form-text text-muted">Enter a text to test the databinding</small>
</div>
</form>
<p>You entered here: @Value</p>
@code {
[Parameter]
public string Value { get; set; }
}
Теперь я добавляю это на страницу примерно так:
<MVVMTest Value="@_value" />
<p>
You entered in MVVMTest:
@_value
</p>
@functions {
private string _value;
}
Когда я ввожу текст в поле вводаполе, оно корректно обновляется на Вы ввели здесь: , но не передали * Вы ввели в MVVMTest ":
Чтомне нужно сделать, чтобы это правильно распространялось?
Я мог бы подумать о подключении Action<string>
в качестве второго [Parameter]
, который я запускаю внутри компонента, когда текст изменяется, но это похоже нахакский и окольный путь. Это как это нужно сделать, или есть лучший способ?
Followup 1
Ответ от Иссака не работает, потому что он спотыкается о @bind-value:oninput="@((e) => ValueChanged.Invoke(e.Value))"
сCannot convert lambda expression to type 'object' because it is not a delegate type
.
Я должен был сделать это окольным путем:
<form>
<div class="form-group">
<label for="sampleText">Sample Text</label>
<input type="text"
class="form-control"
id="sampleText"
aria-describedby="sampleTextHelp"
placeholder="Enter a text"
@bind="@Value" />
<small id="sampleTextHelp" class="form-text text-muted">Enter a text to test the databinding</small>
</div>
</form>
<p>You entered here: @Value</p>
@code {
private string _value;
[Parameter]
public string Value {
get => _value;
set {
if(Equals(value, _value)) {
return;
}
_value = value;
OnValueChanged.InvokeAsync(value).GetAwaiter().GetResult();
}
}
[Parameter]
public EventCallback<string> OnValueChanged { get; set; }
}
И использовать это как:
@inject HttpClient http
@page "/test"
<div class="top-row px-4">
Test Page
</div>
<div class="content px-4">
<MVVMTest Value="@_value" OnValueChanged="@(v => _value = v)" />
<p>
You entered in MVVMTest:
@_value
</p>
</div>
@functions {
private string _value;
}
Не красиво, но это работает.Мой «настоящий» компонент более сложен, так как измененное значение вызывает вызовы к базовой службе ASP.net Core, поэтому я должен сделать детальнуюобнаружение, кто меняет то, что нужно избегать бесконечных циклов.
Конечно, было бы лучше, если бы Blazor поддерживал XAML / WPF-подобный MVVM, хотя ...
Followup 2
Я вернулсяк решению Иссака и с дополнительным приведением, я заставил его работать:
<form>
<div class="form-group">
<label for="sampleText">Sample Text</label>
<input type="text"
class="form-control"
id="sampleText"
aria-describedby="sampleTextHelp"
placeholder="Enter a text"
value="@Value"
oninput="@((Func<ChangeEventArgs, Task>)(async e => await OnValueChanged.InvokeAsync(e.Value as string)))" />
<small id="sampleTextHelp" class="form-text text-muted">Enter a text to test the databinding</small>
</div>
</form>
<p>You entered here: @Value</p>
@code {
private string _value;
[Parameter]
public string Value { get; set; }
[Parameter]
public EventCallback<string> OnValueChanged { get; set; }
}
Использование:
<MVVMTest Value="@_value" OnValueChanged="@(v => _value = v)" />
<p>
You entered in MVVMTest:
@_value
</p>
@functions {
private string _value;
}
Это уже известная проблема в Blazor.Я споткнулся об этом уже на прошлой неделе и опубликовал обходной путь на форуме разработчиков VS .