Blazor中如何为EditForm传递Tuple等非对象类型作为Model?
Great question! Let's break down how this works in Blazor's EditForm and what your options are.
First, a quick note: By design, EditForm's Model property expects a reference type object. This is because Blazor's form binding and validation systems rely on .NET reflection to track property changes, apply validation attributes, and sync values between the form and your data source. Value types like ValueTuple (C# 7+) or primitive types (int, string) work differently here, so using them directly comes with limitations.
Option 1: Wrap the Tuple/Value Type in a Class (Recommended)
The most reliable and clean approach is to create a simple wrapper class that holds your tuple values or primitive type. This lets you use all of Blazor's form features (like data annotations validation) without workarounds.
Example for a Tuple:
If you wanted to use (int Id, string Name) as your form data, create a class:
public class UserFormModel { [Required(ErrorMessage = "ID is required")] public int Id { get; set; } [Required(ErrorMessage = "Name is required")] [StringLength(50)] public string Name { get; set; } = string.Empty; }
Then use it in your EditForm:
@code { private UserFormModel _model = new(); private void HandleValidSubmit() { // Use _model.Id and _model.Name here } } <EditForm Model="@_model" OnValidSubmit="HandleValidSubmit"> <DataAnnotationsValidator /> <ValidationSummary /> <InputNumber @bind-Value="_model.Id" /> <ValidationMessage For="@(() => _model.Id)" /> <InputText @bind-Value="_model.Name" /> <ValidationMessage For="@(() => _model.Name)" /> <button type="submit">Submit</button> </EditForm>
Example for a Primitive Type (e.g., int):
If you just need to bind a single integer, wrap it in a class:
public class IntFormModel { [Range(1, 100, ErrorMessage = "Value must be between 1 and 100")] public int Value { get; set; } }
Option 2: Use a Tuple Directly (With Caveats)
If you really need to use a ValueTuple directly, it's possible—but you'll lose some key features and need manual workarounds.
Key Limitations:
- No validation attributes: You can't apply
[Required]or other validation attributes to tuple members. - Value type copying: Since
ValueTupleis a value type, theEditFormreceives a copy of your tuple. Changes to the form won't automatically sync back to your original variable.
How to Make It Work:
@code { private (int Id, string Name) _originalTuple = (1, "Test"); private EditForm? _editForm; private void HandleSubmit() { // Manually sync the modified tuple back to your original variable if (_editForm?.Model is (int Id, string Name) modifiedTuple) { _originalTuple = modifiedTuple; } } } <EditForm @ref="_editForm" Model="@_originalTuple" OnSubmit="HandleSubmit"> <InputNumber @bind-Value="_originalTuple.Id" /> <InputText @bind-Value="_originalTuple.Name" /> <button type="submit">Submit</button> </EditForm>
This works, but it's not ideal—you miss out on validation and have to handle sync manually. Stick with the wrapper class unless you have a specific reason not to.
Final Takeaway
Blazor's EditForm is designed around reference type models, so wrapping your tuple or value type in a class is the best way to get full functionality (validation, automatic binding sync). Using tuples directly is possible but comes with tradeoffs that make it less maintainable.
内容的提问来源于stack exchange,提问作者StefanoDAngola

