Ниже приведены выдержки из примера проекта Visual Studio 2022 Blazor, специально созданного для демонстрации проблемы.
Будем признательны за любые советы по исправлению ошибок, перечисленных внизу. Однако изменение типов данных MSSQL, к сожалению, невозможно. Заранее спасибо!
документ: BlazorApp1.proj
<Project Sdk = "Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include = "Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter" Version = "8.0.3" />
<PackageReference Include = "Microsoft.EntityFrameworkCore" Version = "8.0.3" />
<PackageReference Include = "Microsoft.EntityFrameworkCore.Design" Version = "8.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include = "Microsoft.EntityFrameworkCore.SqlServer" Version = "8.0.3" />
<PackageReference Include = "Microsoft.EntityFrameworkCore.Tools" Version = "8.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include = "Microsoft.VisualStudio.Web.CodeGeneration.Design" Version = "8.0.2" />
</ItemGroup>
</Project>
документ: appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"connectionstring": "Server=(localdb)\\MSSQLLocalDB;Database=Test;Trusted_Connection=True"
}
}
документ: Program.cs
using BlazorApp1.Components;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
база данных:
CREATE DATABASE Test
CREATE TABLE [dbo].[Sample] (
[Id] INT NOT NULL,
[NCharRequired] NCHAR (10) NOT NULL,
[NCharNullable] NCHAR (10) NULL,
[IntRequired] INT NOT NULL,
[IntNullable] INT NULL,
[TinyIntRequired] TINYINT NOT NULL,
[TinyIntNullable] TINYINT NULL,
[BitRequired] BIT NOT NULL,
[BitNullable] BIT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
окно: Консоль управления пакетами
Scaffold-DbContext "Server=(localdb)\MSSQLLocalDB;Database=Test;Trusted_Connection=True" Microsoft.EntityFrameworkCore.SqlServer
документ: Sample.cs
namespace BlazorApp1.Models;
public partial class Sample
{
public int Id { get; set; }
public string NcharRequired { get; set; } = null!;
public string? NcharNullable { get; set; }
public int IntRequired { get; set; }
public int? IntNullable { get; set; }
public byte TinyIntRequired { get; set; }
public byte? TinyIntNullable { get; set; }
public bool BitRequired { get; set; }
public bool? BitNullable { get; set; }
}
документ: TestContext.cs
using Microsoft.EntityFrameworkCore;
namespace BlazorApp1.Models;
public partial class TestContext : DbContext
{
public TestContext()
{
}
public TestContext(DbContextOptions<TestContext> options)
: base(options)
{
}
public virtual DbSet<Sample> Samples { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263.
=> optionsBuilder.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Database=Test;Trusted_Connection=True");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Sample>(entity =>
{
entity.HasKey(e => e.Id).HasName("PK__Table__3214EC07F913B460");
entity.ToTable("Sample");
entity.Property(e => e.Id).ValueGeneratedNever();
entity.Property(e => e.NcharNullable)
.HasMaxLength(10)
.IsFixedLength()
.HasColumnName("NCharNullable");
entity.Property(e => e.NcharRequired)
.HasMaxLength(10)
.IsFixedLength()
.HasColumnName("NCharRequired");
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
контекстное меню: BlazorApp1
Add->
New Scaffolded Item->
Razor Components using Entity Framework (CRUD)->
Template:CRUD
Model class:Sample (BlazorApp1.Models)
DbContext class:TestContext (BlazorApp1.Models)
документ: Create.razor
@page "/samples/create"
@inject BlazorApp1.Models.TestContext DB
@using BlazorApp1.Models
@inject NavigationManager NavigationManager
<PageTitle>Create</PageTitle>
<h1>Create</h1>
<h4>Sample</h4>
<hr />
<div class = "row">
<div class = "col-md-4">
<EditForm method = "post" Model = "Sample" OnValidSubmit = "AddSample" FormName = "create" Enhance>
<DataAnnotationsValidator />
<ValidationSummary class = "text-danger" />
<div class = "mb-3">
<label for = "ncharrequired" class = "form-label">NcharRequired:</label>
<InputText id = "ncharrequired" @bind-Value = "Sample.NcharRequired" class = "form-control" />
<ValidationMessage For = "() => Sample.NcharRequired" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "ncharnullable" class = "form-label">NcharNullable:</label>
<InputText id = "ncharnullable" @bind-Value = "Sample.NcharNullable" class = "form-control" />
<ValidationMessage For = "() => Sample.NcharNullable" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "intrequired" class = "form-label">IntRequired:</label>
<InputNumber id = "intrequired" @bind-Value = "Sample.IntRequired" class = "form-control" />
<ValidationMessage For = "() => Sample.IntRequired" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "intnullable" class = "form-label">IntNullable:</label>
<InputNumber id = "intnullable" @bind-Value = "Sample.IntNullable" class = "form-control" />
<ValidationMessage For = "() => Sample.IntNullable" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "tinyintrequired" class = "form-label">TinyIntRequired:</label>
<InputText id = "tinyintrequired" @bind-Value = "Sample.TinyIntRequired" class = "form-control" />
<ValidationMessage For = "() => Sample.TinyIntRequired" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "tinyintnullable" class = "form-label">TinyIntNullable:</label>
<InputText id = "tinyintnullable" @bind-Value = "Sample.TinyIntNullable" class = "form-control" />
<ValidationMessage For = "() => Sample.TinyIntNullable" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "bitrequired" class = "form-label">BitRequired:</label>
<InputCheckbox id = "bitrequired" @bind-Value = "Sample.BitRequired" class = "form-check-input" />
<ValidationMessage For = "() => Sample.BitRequired" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "bitnullable" class = "form-label">BitNullable:</label>
<InputCheckbox id = "bitnullable" @bind-Value = "Sample.BitNullable" class = "form-check-input" />
<ValidationMessage For = "() => Sample.BitNullable" class = "text-danger" />
</div>
<button type = "submit" class = "btn btn-primary">Create</button>
</EditForm>
</div>
</div>
<div>
<a href = "/samples">Back to List</a>
</div>
@code {
[SupplyParameterFromForm]
public Sample Sample { get; set; } = new();
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task AddSample()
{
DB.Samples.Add(Sample);
await DB.SaveChangesAsync();
NavigationManager.NavigateTo("/samples");
}
}
документ: Edit.razor
@page "/Samples/edit"
@inject BlazorApp1.Models.TestContext DB
@using BlazorApp1.Models
@inject NavigationManager NavigationManager
@using Microsoft.EntityFrameworkCore
<PageTitle>Edit</PageTitle>
<h1>Edit</h1>
<h4>Sample</h4>
<hr />
@if (Sample is null)
{
<p><em>Loading...</em></p>
}
else
{
<div class = "row">
<div class = "col-md-4">
<EditForm method = "post" Model = "Sample" OnValidSubmit = "UpdateSample" FormName = "edit" Enhance>
<DataAnnotationsValidator />
<ValidationSummary />
<input type = "hidden" name = "Sample.Id" value = "@Sample.Id" />
<div class = "mb-3">
<label for = "ncharrequired" class = "form-label">NcharRequired:</label>
<InputText id = "ncharrequired" @bind-Value = "Sample.NcharRequired" class = "form-control" />
<ValidationMessage For = "() => Sample.NcharRequired" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "ncharnullable" class = "form-label">NcharNullable:</label>
<InputText id = "ncharnullable" @bind-Value = "Sample.NcharNullable" class = "form-control" />
<ValidationMessage For = "() => Sample.NcharNullable" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "intrequired" class = "form-label">IntRequired:</label>
<InputNumber id = "intrequired" @bind-Value = "Sample.IntRequired" class = "form-control" />
<ValidationMessage For = "() => Sample.IntRequired" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "intnullable" class = "form-label">IntNullable:</label>
<InputNumber id = "intnullable" @bind-Value = "Sample.IntNullable" class = "form-control" />
<ValidationMessage For = "() => Sample.IntNullable" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "tinyintrequired" class = "form-label">TinyIntRequired:</label>
<InputText id = "tinyintrequired" @bind-Value = "Sample.TinyIntRequired" class = "form-control" />
<ValidationMessage For = "() => Sample.TinyIntRequired" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "tinyintnullable" class = "form-label">TinyIntNullable:</label>
<InputText id = "tinyintnullable" @bind-Value = "Sample.TinyIntNullable" class = "form-control" />
<ValidationMessage For = "() => Sample.TinyIntNullable" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "bitrequired" class = "form-label">BitRequired:</label>
<InputCheckbox id = "bitrequired" @bind-Value = "Sample.BitRequired" class = "form-check-input" />
<ValidationMessage For = "() => Sample.BitRequired" class = "text-danger" />
</div>
<div class = "mb-3">
<label for = "bitnullable" class = "form-label">BitNullable:</label>
<InputCheckbox id = "bitnullable" @bind-Value = "Sample.BitNullable" class = "form-check-input" />
<ValidationMessage For = "() => Sample.BitNullable" class = "text-danger" />
</div>
<button type = "submit" class = "btn btn-primary">Save</button>
</EditForm>
</div>
</div>
}
<div>
<a href = "/samples">Back to List</a>
</div>
@code {
[SupplyParameterFromQuery]
public int Id { get; set; }
[SupplyParameterFromForm]
public Sample? Sample { get; set; }
protected override async Task OnInitializedAsync()
{
Sample ??= await DB.Samples.FirstOrDefaultAsync(m => m.Id == Id);
if (Sample is null)
{
NavigationManager.NavigateTo("notfound");
}
}
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see https://aka.ms/RazorPagesCRUD.
public async Task UpdateSample()
{
DB.Attach(Sample!).State = EntityState.Modified;
try
{
await DB.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!SampleExists(Sample!.Id))
{
NavigationManager.NavigateTo("notfound");
}
else
{
throw;
}
}
NavigationManager.NavigateTo("/samples");
}
bool SampleExists(int id)
{
return DB.Samples.Any(e => e.Id == id);
}
}
окно: Список ошибок
Error (active) CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type BlazorApp1 .\Create.razor 14
Error (active) CS1503 Argument 1: cannot convert from 'byte' to 'string' BlazorApp1 .\Create.razor 39
Error (active) CS1503 Argument 2: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<byte>' to 'Microsoft.AspNetCore.Components.EventCallback' BlazorApp1 .\Create.razor 39
Error (active) CS0029 Cannot implicitly convert type 'byte' to 'string' BlazorApp1 .\Create.razor 39
Error (active) CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type BlazorApp1 .\Create.razor 39
Error (active) CS1503 Argument 1: cannot convert from 'byte?' to 'string' BlazorApp1 .\Create.razor 44
Error (active) CS1503 Argument 2: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<byte?>' to 'Microsoft.AspNetCore.Components.EventCallback' BlazorApp1 .\Create.razor 44
Error (active) CS0029 Cannot implicitly convert type 'byte?' to 'string' BlazorApp1 .\Create.razor 44
Error (active) CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type BlazorApp1 .\Create.razor 44
Error (active) CS1503 Argument 1: cannot convert from 'bool?' to 'bool' BlazorApp1 .\Create.razor 54
Error (active) CS1503 Argument 2: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<bool?>' to 'Microsoft.AspNetCore.Components.EventCallback' BlazorApp1 .\Create.razor 54
Error (active) CS0266 Cannot implicitly convert type 'bool?' to 'bool'. An explicit conversion exists (are you missing a cast?) BlazorApp1 .\Create.razor 54
Error (active) CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type BlazorApp1 .\Create.razor 54
Error (active) CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type BlazorApp1 .\Edit.razor 21
Error (active) CS1503 Argument 1: cannot convert from 'byte' to 'string' BlazorApp1 .\Edit.razor 47
Error (active) CS1503 Argument 2: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<byte>' to 'Microsoft.AspNetCore.Components.EventCallback' BlazorApp1 .\Edit.razor 47
Error (active) CS0029 Cannot implicitly convert type 'byte' to 'string' BlazorApp1 .\Edit.razor 47
Error (active) CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type BlazorApp1 .\Edit.razor 47
Error (active) CS1503 Argument 1: cannot convert from 'byte?' to 'string' BlazorApp1 .\Edit.razor 52
Error (active) CS1503 Argument 2: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<byte?>' to 'Microsoft.AspNetCore.Components.EventCallback' BlazorApp1 .\Edit.razor 52
Error (active) CS0029 Cannot implicitly convert type 'byte?' to 'string' BlazorApp1 .\Edit.razor 52
Error (active) CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type BlazorApp1 .\Edit.razor 52
Error (active) CS1503 Argument 1: cannot convert from 'bool?' to 'bool' BlazorApp1 .\Edit.razor 62
Error (active) CS1503 Argument 2: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<bool?>' to 'Microsoft.AspNetCore.Components.EventCallback' BlazorApp1 .\Edit.razor 62
Error (active) CS0266 Cannot implicitly convert type 'bool?' to 'bool'. An explicit conversion exists (are you missing a cast?) BlazorApp1 .\Edit.razor 62
Error (active) CS1662 Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type BlazorApp1 .\Edit.razor 62
Попробовал:
Активно искал в Интернете и просматривал множество связанных статей, но не нашел решения.
Добавление их в OnModelCreating, но ошибки не исчезли.
entity.Property(e => e.TinyIntRequired).HasColumnType("tinyint").IsRequired(true);
entity.Property(e => e.TinyIntNullable).HasColumnType("tinyint").IsRequired(false);
entity.Property(e => e.BitNullable).HasColumnType("bit").IsRequired(false);





Похоже, ваша проблема заключается в том, что вы пытаетесь использовать элементы управления вводом, которые не поддерживают используемые вами типы данных.
InputNumber не поддерживает byte, поэтому вам нужно создать версию, которая поддерживает.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Rendering;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.RegularExpressions;
namespace SO78206175.Components;
public class BlazrInputNumber<TValue> : InputBase<TValue>
{
private static readonly string _stepAttributeValue = GetStepAttributeValue();
private static string GetStepAttributeValue()
{
// Unwrap Nullable<T>, because InputBase already deals with the Nullable aspect
// of it for us. We will only get asked to parse the T for nonempty inputs.
var targetType = Nullable.GetUnderlyingType(typeof(TValue)) ?? typeof(TValue);
if (targetType == typeof(int) ||
targetType == typeof(long) ||
targetType == typeof(short) ||
targetType == typeof(float) ||
targetType == typeof(double) ||
targetType == typeof(byte) ||
targetType == typeof(decimal))
{
return "any";
}
else
{
throw new InvalidOperationException($"The type '{targetType}' is not a supported numeric type.");
}
}
[Parameter] public string ParsingErrorMessage { get; set; } = "The {0} field must be a number.";
[DisallowNull] public ElementReference? Element { get; protected set; }
/// <inheritdoc />
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenElement(0, "input");
builder.AddAttribute(1, "step", _stepAttributeValue);
builder.AddMultipleAttributes(2, AdditionalAttributes);
builder.AddAttribute(3, "type", "number");
if (NameAttributeValue is not null)
builder.AddAttribute(4, "name", NameAttributeValue);
if (CssClass is not null)
builder.AddAttribute(5, "class", CssClass);
builder.AddAttribute(6, "value", CurrentValueAsString);
builder.AddAttribute(7, "onchange", EventCallback.Factory.CreateBinder<string?>(this, __value => CurrentValueAsString = __value, CurrentValueAsString));
builder.SetUpdatesAttributeName("value");
builder.AddElementReferenceCapture(8, __inputReference => Element = __inputReference);
builder.CloseElement();
}
protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(false)] out TValue result, [NotNullWhen(false)] out string? validationErrorMessage)
{
if (typeof(TValue) == typeof(byte))
{
if (!byte.TryParse(value, out byte outcome))
{
result = default;
validationErrorMessage = "The entry exeeds the maximum or minimum value for a byte.";
return false;
}
}
if (typeof(TValue) == typeof(byte?))
{
if (value is not null && !byte.TryParse(value, out byte outcome))
{
result = default;
validationErrorMessage = "The entry exeeds the maximum or minimum value for a byte.";
return false;
}
}
if (BindConverter.TryConvertTo<TValue>(value, CultureInfo.InvariantCulture, out result))
{
validationErrorMessage = null;
return true;
}
else
{
validationErrorMessage = string.Format(CultureInfo.InvariantCulture, ParsingErrorMessage, DisplayName ?? FieldIdentifier.FieldName);
return false;
}
}
protected override string? FormatValueAsString(TValue? value)
{
// Avoiding a cast to IFormattable to avoid boxing.
switch (value)
{
case null:
return null;
case byte @byte:
return @byte.ToString(CultureInfo.CurrentCulture);
case int @int:
return BindConverter.FormatValue(@int, CultureInfo.InvariantCulture);
case long @long:
return BindConverter.FormatValue(@long, CultureInfo.InvariantCulture);
case short @short:
return BindConverter.FormatValue(@short, CultureInfo.InvariantCulture);
case float @float:
return BindConverter.FormatValue(@float, CultureInfo.InvariantCulture);
case double @double:
return BindConverter.FormatValue(@double, CultureInfo.InvariantCulture);
case decimal @decimal:
return BindConverter.FormatValue(@decimal, CultureInfo.InvariantCulture);
default:
throw new InvalidOperationException($"Unsupported type {value.GetType()}");
}
}
}
Флажки не поддерживают bool?, поскольку они двоичные: a bool? имеет три состояния! Вам нужно создать специальный элемент управления. Вот пример элемента управления группой кнопок:
<div class = "form-control">
<div class = "btn-group" role = "group" aria-label = "Basic example">
<button type = "button" class = "@_notSetColour" @onclick = "() => OnButtonChanged(-1)"> Not Set</button>
<button type = "button" class = "@_onColour" @onclick = "() => OnButtonChanged(1)">On</button>
<button type = "button" class = "@_offColour" @onclick = "() => OnButtonChanged(0)">Off</button>
</div>
</div>
@code {
[Parameter] public bool? Value { get; set; }
[Parameter] public EventCallback<bool?> ValueChanged { get; set; }
private int _value => this.Value switch
{
true => 1,
false => 0,
_ => -1
};
private bool? GetBoolValue(int value) => value switch
{
1 => true,
0 => false,
_ => null
};
private string _notSetColour => _value == -1 ? "btn btn-secondary" : "btn btn-outline-secondary";
private string _onColour => _value == 1 ? "btn btn-success" : "btn btn-outline-success";
private string _offColour => _value == 0 ? "btn btn-danger" : "btn btn-outline-danger";
private Task OnButtonChanged(int value)
{
this.ValueChanged.InvokeAsync(GetBoolValue(value));
return Task.CompletedTask;
}
}
Моя демо-страница:
@page "/"
<PageTitle>Home</PageTitle>
<h1>Example</h1>
<EditForm EditContext = "_editContext">
<label>Byte Required</label>
<BlazrInputNumber class = "form-control mb-2" max = "@byte.MaxValue" min = "@byte.MinValue" @bind-Value = "_model.TinyIntRequired" />
<ValidationMessage For = "() => _model.TinyIntRequired" />
<label>Byte Nullable</label>
<BlazrInputNumber class = "form-control mb-2" max = "@byte.MaxValue" min = "@byte.MinValue" @bind-Value = "_model.TinyIntNullable" />
<ValidationMessage For = "() => _model.TinyIntNullable" />
<label>Byte Nullable</label>
<InputBoolButtons @bind-Value = "_model.BitNullable" />
</EditForm>
<div class = "bg-dark text-white m-2 p-2">
<pre>Byte Required: @_model.TinyIntRequired</pre>
<pre>Byte Nullable: @(_model.TinyIntNullable?.ToString() ?? "Null")</pre>
<pre>Bit Nullable: @(_model.BitNullable?.ToString() ?? "Null")</pre>
</div>
@code {
private Sample _model = new();
private EditContext? _editContext;
protected override Task OnInitializedAsync()
{
_editContext = new(_model);
return Task.CompletedTask;
}
}
Если вы хотите использовать стандартные элементы управления редактированием, вы можете создать объект редактирования, в который вы сопоставляете свой объект данных, а затем извлекаете его для сохранения.
Вот код, демонстрирующий, как:
public partial class Sample
{
public int Id { get; set; }
public byte? TinyIntNullable { get; set; }
}
// This is the object you write the validator for
// and you point the editor controls to
public class SampleEditMutator
{
public int Id { get; private set; }
public short? TinyIntNullable { get; set; }
public SampleEditMutator(Sample record)
{
this.Id = record.Id;
this.TinyIntNullable = Convert.ToInt16(record.TinyIntNullable);
}
// Call this to apply the edit changes to a Sample object
public Sample Mutate(Sample record)
{
record.TinyIntNullable = ConvertToByte(this.TinyIntNullable);
return record;
}
private byte? ConvertToByte(short? value)
{
if (value is null)
return null;
if (byte.TryParse(this.TinyIntNullable.ToString(), out byte outvalue))
throw new Exception("Not Allowed");
return outvalue;
}
}
См. мой обновленный ответ, чтобы показать, как использовать отдельный объект редактирования.