在@mason-wheeler 和@rich-bryant 提供了他们的答案之后,我进一步思考了这个问题并找到了我的解决方案,我将其发布在这里:
https://github.com/Mike-E-angelo/Blazor.ViewProperties
我称之为a ViewProperty
,如下所示:
public interface IViewProperty
{
ValueTask Get();
}
public sealed class ViewProperty<T> : IViewProperty
{
public static implicit operator ViewProperty<T>(ValueTask<T> instance) => new ViewProperty<T>(instance);
readonly ValueTask<T> _source;
public ViewProperty(ValueTask<T> source) => _source = source;
public T Value { get; private set; }
public bool HasValue { get; private set; }
public async ValueTask Get()
{
Value = await _source;
HasValue = true;
}
public override string ToString() => Value.ToString();
}
然后将它与组件基类型配对,然后迭代组件的视图属性并调用它们各自的异步操作:
public abstract class ViewPropertyComponentBase : ComponentBase
{
protected override async Task OnParametersSetAsync()
{
var properties = GetType().GetRuntimeProperties();
foreach (var metadata in properties.Where(x => x.GetCustomAttributes<ParameterAttribute>().Any() &&
typeof(IViewProperty).IsAssignableFrom(x.PropertyType)))
{
if (metadata.GetValue(this) is IViewProperty property)
{
await property.Get().ConfigureAwait(false);
}
}
}
}
使用上述内容的示例剃须刀组件:
MyComponent.razor
@inherits ViewPropertyComponentBase
@if (Count.HasValue)
{
<p>Your magic number is @Count.</p>
}
else
{
<p>Loading, please wait...</p>
}
@code {
[Parameter]
public ViewProperty<int> Count { get; set; }
}
由此产生的使用是具有直接绑定的干净视图,不需要覆盖或其他额外的仪式:
@page "/"
@inject ICounter Count
<h1>Hello, world!</h1>
Welcome to your new app.
<MyComponent Count="@Count.Count()" />
(请注意,我发布的示例及以上使用反射,这很慢。在我使用的解决方案的实际版本中,我将成员访问编译为 lambda 表达式并缓存结果。如果你是,你可以从这里开始找到勇敢地四处寻找。)