我有一个简单的类InputLength.razor。它包含一个Length和Length Type。我想从父级InputLength组件中检索这些属性。我知道我可以绑定到单个属性,但想象一下我有10个属性。那太乏味了。
我只想创建InputLength组件的一个实例,然后将该模型作为绑定参数传递给InputLength子级,当任何属性更新时,我希望在父级上更新绑定模型。
参见以下组件代码:
@code {
[Parameter]
public InputLength m { get; set; }
[Parameter]
public EventCallback<InputLength> mChanged { get; set; }
public double _Length;
public double Length { get { return _Length; } set { _Length = value; m.Length = value; mChanged.InvokeAsync(m); } }
public LengthType _SelectedLengthType;
public LengthType SelectedLengthType { get { return _SelectedLengthType; } set { _SelectedLengthType = value; mChanged.InvokeAsync(m); } }
public enum LengthType
{
Inches,
Centimeters,
};
}
正如您所看到的,为了便于实现这一点,我尝试在InputLength组件上创建一个InputLength类型的m属性,这是唯一的属性。在父母身上,我绑定到它
<InputLength bind-m=inputLengthInstance></InputLength>
出于某种原因,当它更新m.Length值时(在我调用mChanged之前(,它似乎在创建一个新组件,但从未真正达到调用mChanged.InvokeAsync的地步。如果我手动进入,移动断点并调整对象上的值,然后调用Async,它完全可以工作,所以它有点正确。
编辑:它失败的原因是模型存在于类中,当更新它时,它会触发模型的更新
我做错了什么。我似乎写了很多代码来尝试执行一个非常简单的任务。微软网站上的所有指南都假设你只能绑定到你想要的所有基本属性,这同样有效,但似乎没有必要。这就是类存在的原因。只需绑定整个臭班。
有人建议让这项工作发挥作用,希望能以一种更清洁、有意义的方式进行?
如果我正确理解了这一点,那么您需要为名为Length的类构建一个编辑器,并在不同的地方使用它。
定义一个数据类——我称之为Length
。
public class Length
{
public double LengthValue { get; set; }
public UnitType Units { get; set; }
public string DisplayValue => $"{this.LengthValue} {this.Units}";
public enum UnitType
{
Inches,
Centimeters,
};
}
定义和编辑组件-我称之为InputLength。
<div class="m-2 p-2">
<InputNumber @bind-Value=LengthValue></InputNumber>
<InputSelect @bind-Value=UnitsValue>
@foreach (var lt in Enum.GetValues(typeof(Length.UnitType)))
{
<option>@lt</option>
}
</InputSelect>
</div>
<div class="m-2 p-2">
<br />Component Value: @Value.DisplayValue
</div>
@code {
[Parameter] public Length Value { get; set; }
[Parameter] public EventCallback<Length> ValueChanged { get; set; }
private Length _length;
private double LengthValue
{
get => _length.LengthValue;
set
{
if (value != _length.LengthValue)
{
_length.LengthValue = value;
this.InvokeModelChanged();
}
}
}
private Length.UnitType UnitsValue
{
get => _length.Units;
set
{
if (value != _length.Units)
{
_length.Units = value;
this.InvokeModelChanged();
}
}
}
protected override void OnInitialized()
{
_length = new Length() { LengthValue = this.Value.LengthValue, Units = this.Value.Units };
}
private void InvokeModelChanged()
{
if (ValueChanged.HasDelegate)
ValueChanged.InvokeAsync(_length);
}
}
这是一个演示的编辑表单。
@page "/NewEditor1"
@page "/"
<h3>EditForm</h3>
<EditForm EditContext="this._editContext" OnValidSubmit="SubmitForm">
<div class="p-2">
Long Side: <InputLength @bind-Value="_model.LongSide" />
</div>
<div class="p-2">
Short Side: <InputLength @bind-Value="_model.ShortSide" />
</div>
<div class="m-2 p-2">
<button class="btn btn-success" type="submit">Submit</button>
</div>
</EditForm>
<div class="m-2 p-2">Form Long Side Value: @_model.LongSide.DisplayValue </div>
<div class="m-2 p-2">Form Short Side Value: @_model.ShortSide.DisplayValue </div>
@code {
public class Model
{
public Length LongSide { get; set; } = new Length() { Units = Length.UnitType.Centimeters, LengthValue = 0 };
public Length ShortSide { get; set; } = new Length() { Units = Length.UnitType.Centimeters, LengthValue = 0 };
}
private string message;
Model _model = new Model();
EditContext _editContext;
protected override void OnInitialized()
{
_editContext = new EditContext(_model);
}
void SubmitForm()
{
message = $"Form Submitted at :{DateTime.Now.ToLongTimeString()}";
var x = true;
}
}
请注意,这是一个非常简单的输入控件。它不处理将编辑更改传递到编辑上下文或与验证交互。
以迄今为止最有意义的方式实现这一点的诀窍是颠倒您对属性的公共和私有版本应该如何工作的想法。您的公共属性将是您希望模型表示的内容(通过这种方式,它可以通过模型实例进行设置(。相应的私有属性应该是您绑定到输入字段的属性。在Set上,可以更新模型的公共属性,然后触发changeEvent。这将随后更新父对象上的模型对象,并将更新后的值向下传递给子对象,以便在两个位置进行视觉更新。
同样,这样做的目的是不必将模型同时表示为单独的类和razorComponent类。通过这个设计,我创建了一个剃刀组件,可以用作代码其余部分的输入。
<InputNumber @bind-Value=_Length></InputNumber>
<InputSelect @bind-Value=_SelectedLengthType>
@foreach (var lt in Enum.GetValues(typeof(LengthType)))
{
<option>@lt</option>
}
</InputSelect>
<br />On Child: @Model.Length ; @Model.SelectedLengthType
@code {
[Parameter]
public InputLength Model { get; set; }
[Parameter]
public EventCallback<InputLength> ModelChanged { get; set; }
public double Length;
private double _Length
{
get { return Model.Length; }
set { Model.Length = value; ModelChanged.InvokeAsync(Model); }
}
public LengthType SelectedLengthType;
private LengthType _SelectedLengthType
{
get { return Model.SelectedLengthType; }
set { Model.SelectedLengthType = value; ModelChanged.InvokeAsync(Model); }
}
public enum LengthType
{
Inches,
Centimeters,
};
}