Blazor编辑表单状态控件

Blazor编辑表单状态控件概述 BlazorEditFo 控件这是描述一组有用的 BlazorEdit 控件的系列文章中的第一篇 这些控件解决了开箱即用编辑体验中的一些当前缺点 而无需购买昂贵的工具包 代码和示例该存储库包含一个项目 该项目实现了本系列中所有文章的控件 你可以在这里找到它 示例站点位于 https cec blazor database azurewebsite net 您可以在 https cec blazor database azurewebsite net

目录

概述——Blazor EditFormState控件

代码和示例

Blazor编辑设置

EditForm

EditContext

FieldIdentifier

输入控件

重新审视EditContext

EditFormState 控件

WeatherForecast

EditField

EditFieldCollection

EditFormState

一个简单的实现

总结


概述——Blazor EditFormState控件

这是描述一组有用的Blazor Edit控件的系列文章中的第一篇,这些控件解决了开箱即用编辑体验中的一些当前缺点,而无需购买昂贵的工具包。

Blazor编辑表单状态控件

代码和示例

该存储库包含一个项目,该项目实现了本系列中所有文章的控件。你可以在这里找到它。

示例站点位于https://cec-blazor-database.azurewebsites.net/

您可以在https://cec-blazor-database.azurewebsites.net//testeditor 中查看稍后描述的测试表单。

Repo是未来文章的一项正在进行的工作,因此会发生变化和发展。

Blazor编辑设置

首先,让我们看看当前的表单控件以及它们如何协同工作。一个经典的形式看起来像这样:

 
    
     
     
     
     
     
   

EditForm

EditForm是整体包装。它:

  1. 创建html Form上下文。
  2. 连接任何Submit按钮——即,在表单内将type设置为submit的按钮。
  3. 创建/管理EditContext.
  4. 级联EditContextEditForm中的所有控件将被捕获并以一种或另一种方式使用它。
  5. 为提交过程的父控件提供回调委托——OnSubmitOnValidSubmitOnInvalidSubmit

EditContext

EditContext是编辑过程核心的类,提供整体管理。它操作的数据类是model: 定义为object类型。它可以是任何对象,但实际上是某种类型的数据类。唯一的先决条件是表单中使用的字段被声明为public/写属性。

EditContext可以是:

  • 直接作为EditContext参数传递给EditForm
  • 或者模型的对象实例被设置为Model参数并从EditForm中创建一个EditContext实例。

要记住的重要一点是,一旦创建了另一个对象,就不要更改它的EditContext模型。虽然有可能,但不建议这样做。如果模型需要改变,代码刷新整个表单:会更安全!

FieldIdentifier

FieldIdentifier类代表一个模型属性的部分系列化EditContext通过他们的FieldIdentifier踪迹和识别单个属性。Model是拥有该属性的对象,FieldName是通过反射得到的属性名。

输入控件

InputTextInputNumber和其他InputBase控件捕获级联EditContext.。通过使用他们的FieldIdentifier调用NotifyFieldChanged,任何值的变动被向上推至EditContext

重新审视EditContext

在内部EditContext维护一个FieldIdentifier列表。FieldIdentifier对象在各种方法和事件中传递以识别特定字段。调用NotifyFieldChangedFieldIdentifier对象添加到列表中。每当调用NotifyFieldChangedEditContext触发OnFieldChanged

IsModified提供对列表或个人FieldIdentifier状态的访问。MarkAsUnmodified重置集合中的单个FieldIdentifier或全部FieldIdentifiers

EditContext还包含管理验证的功能,但实际上并没有这样做。我们将在下一篇文章中介绍验证过程。

EditFormState 控件

EditFormState控件与所有编辑表单控件一样,捕获级联的EditState 。它的作用是:

  1. 构建由Model公开的public属性列表并维护每个属性的编辑状态——原始值与编辑值的相等性检查。
  2. 在字段值的每次更改时更新状态。
  3. 通过readonly属性公开状态。
  4. 提供在编辑状态更新时触发的EventCallback委托。

在我们查看控件之前,让我们看一下模型——在我们的例子中,WeatherForecast——以及一些支持类。

WeatherForecast

WeatherForecast 是典型的数据类。

  1. 每个字段都声明为具有默认值的属性。
  2. Validate实现IValidation。暂时忽略这一点,我们将在下一篇文章中查看验证。我已经按照你在Repo代码中看到的方式展示了它。

public class WeatherForecast : IValidation { public int ID { get; set; } = -1; public DateTime Date { get; set; } = DateTime.Now; public int TemperatureC { get; set; } = 0; [NotMapped] public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); public string Summary { get; set; } = string.Empty; /// Ignore for now, but as you'll see it in the example repo it's shown public bool Validate(ValidationMessageStore validationMessageStore, string fieldname, object model = null) { .... } }

EditField

EditField 是我们从模型中序列化属性的类。

  1. 基本字段是记录——它们只能在初始化时设置。
  2. EditedValue 携带该字段的当前值。
  3. IsDirty测试ValueEditedValue之间的相等性。

public class EditField { public string FieldName { get; init; } public Guid GUID { get; init; } public object Value { get; init; } public object Model { get; init; } public object EditedValue { get; set; } public bool IsDirty { get { if (Value != null && EditedValue != null) return !Value.Equals(EditedValue); if (Value is null && EditedValue is null) return false; return true; } } public EditField(object model, string fieldName, object value) { this.Model = model; this.FieldName = fieldName; this.Value = value; this.EditedValue = value; this.GUID = Guid.NewGuid(); } public void Reset() => this.EditedValue = this.Value; }

EditFieldCollection

EditFieldCollectionEditFieldIEnumerable集合。该类为集合提供了一组受控的settergetter,并为IEnumerable接口实现了必要的方法。它还提供了一个IsDirty属性来公开集合的状态。

public class EditFieldCollection : IEnumerable { private List 
   
     _items = new List 
    
      (); public int Count => _items.Count; public Action 
     
       FieldValueChanged; public bool IsDirty => _items.Any(item => item.IsDirty); public void Clear() => _items.Clear(); public void ResetValues() => _items.ForEach(item => item.Reset()); public IEnumerator GetEnumerator() => new EditFieldCollectionEnumerator(_items); public T Get 
      
        (string FieldName) { var x = _items.FirstOrDefault(item => item.FieldName.Equals (FieldName, StringComparison.CurrentCultureIgnoreCase)); if (x != null && x.Value is T t) return t; return default; } public T GetEditValue 
       
         (string FieldName) { var x = _items.FirstOrDefault(item => item.FieldName.Equals (FieldName, StringComparison.CurrentCultureIgnoreCase)); if (x != null && x.EditedValue is T t) return t; return default; } public bool TryGet 
        
          (string FieldName, out T value) { value = default; var x = _items.FirstOrDefault(item => item.FieldName.Equals (FieldName, StringComparison.CurrentCultureIgnoreCase)); if (x != null && x.Value is T t) value = t; return x.Value != default; } public bool TryGetEditValue 
         
           (string FieldName, out T value) { value = default; var x = _items.FirstOrDefault(item => item.FieldName.Equals (FieldName, StringComparison.CurrentCultureIgnoreCase)); if (x != null && x.EditedValue is T t) value = t; return x.EditedValue != default; } public bool HasField(EditField field) => this.HasField(field.FieldName); public bool HasField(string FieldName) { var x = _items.FirstOrDefault(item => item.FieldName.Equals (FieldName, StringComparison.CurrentCultureIgnoreCase)); if (x is null | x == default) return false; return true; } public bool SetField(string FieldName, object value) { var x = _items.FirstOrDefault(item => item.FieldName.Equals (FieldName, StringComparison.CurrentCultureIgnoreCase)); if (x != null && x != default) { x.EditedValue = value; this.FieldValueChanged?.Invoke(this.IsDirty); return true; } return false; } public bool AddField(object model, string fieldName, object value) { this._items.Add(new EditField(model, fieldName, value)); return true; } 
          
         
        
       
      
     
   

Enumerator支持类。

public class EditFieldCollectionEnumerator : IEnumerator { private List 
   
     _items = new List 
    
      (); private int _cursor; object IEnumerator.Current { get { if ((_cursor < 0) || (_cursor == _items.Count)) throw new InvalidOperationException(); return _items[_cursor]; } } public EditFieldCollectionEnumerator(List 
     
       items) { this._items = items; _cursor = -1; } void IEnumerator.Reset() => _cursor = -1; bool IEnumerator.MoveNext() { if (_cursor < _items.Count) _cursor++; return (!(_cursor == _items.Count)); } } } 
      
     
   

现在我们已经看到了支持类,转到主控件。

EditFormState

EditFormState被声明为一个组件并实现IDisposable

public class EditFormState : ComponentBase, IDisposable

属性是:

  1. EditContext从级联中拿起。
  2. EditStateChanged父控件提供回调以告诉它编辑状态已更改。
  3. 为控件提供只读IsDirty属性,使用@ref检查控件状态。
  4. EditFields是我们填充并用于管理编辑状态的内部EditFieldCollection
  5. disposedValueIDisposable实现的一部分。

/// EditContext - cascaded from EditForm [CascadingParameter] public EditContext EditContext { get; set; } /// EventCallback for parent to link into for Edit State Change Events /// passes the current Dirty state [Parameter] public EventCallback 
   
     EditStateChanged { get; set; } /// Property to expose the Edit/Dirty state of the control public bool IsDirty => EditFields?.IsDirty ?? false; private EditFieldCollection EditFields = new EditFieldCollection(); private bool disposedValue; 
   

当组件初始化时,它会捕获Model属性并填充EditFields初始数据。最后一步是连接EditContext.OnFieldChangedFieldChanged,因此每当字段值更改时都会调用FieldChanged

protected override Task OnInitializedAsync() { Debug.Assert(this.EditContext != null); if (this.EditContext != null) { // Populates the EditField Collection this.GetEditFields(); // Wires up to the EditContext OnFieldChanged event this.EditContext.OnFieldChanged += FieldChanged; } return Task.CompletedTask; } /// Method to populate the edit field collection protected void GetEditFields() { // Gets the model from the EditContext and populates the EditFieldCollection this.EditFields.Clear(); var model = this.EditContext.Model; var props = model.GetType().GetProperties(); foreach (var prop in props) { var value = prop.GetValue(model); EditFields.AddField(model, prop.Name, value); } }

FieldChanged事件处理程序中从EditFields中查找EditFiel并通过调用SetField设置它的EditedValue。然后使用当前的dirty状态触发EditStateChanged回调。

/// Event Handler for Editcontext.OnFieldChanged private void FieldChanged(object sender, FieldChangedEventArgs e) { // Get the PropertyInfo object for the model property // Uses reflection to get property and value var prop = e.FieldIdentifier.Model.GetType().GetProperty(e.FieldIdentifier.FieldName); if (prop != null) { // Get the value for the property var value = prop.GetValue(e.FieldIdentifier.Model); // Sets the edit value in the EditField EditFields.SetField(e.FieldIdentifier.FieldName, value); // Invokes EditStateChanged this.EditStateChanged.InvokeAsync(EditFields?.IsDirty ?? false); } }

最后,我们有一些实用方法和IDisposable实现。

/// Method to Update the Edit State to current values public void UpdateState() { this.GetEditFields(); this.EditStateChanged.InvokeAsync(EditFields?.IsDirty ?? false); } // IDisposable Implementation protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { if (this.EditContext != null) this.EditContext.OnFieldChanged -= this.FieldChanged; } disposedValue = true; } } public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); GC.SuppressFinalize(this); } }

一个简单的实现

为了测试组件,这里有一个简单的测试页面。

Blazor编辑表单状态控件

上下更改温度,您应该会看到状态按钮更改颜色和文本。

您可以在https://cec-blazor-database.azurewebsites.net/editstateeditor 上查看此示例。

@using Blazor.Database.Data @page "/test" 
    
    
        
     
     
     
     
     
     
     
     
     
    
@code { protected bool _isDirty = false; protected string btncolour => _isDirty ? "btn-danger" : "btn-success"; protected string btntext => _isDirty ? "Dirty" : "Clean"; protected EditFormState editFormState { get; set; } private WeatherForecast Model = new WeatherForecast() { ID = 1, Date = DateTime.Now, TemperatureC = 22, Summary = "Balmy" }; private void HandleValidSubmit() { this.editFormState.UpdateState(); } private void EditStateChanged(bool editstate) => this._isDirty = editstate; }

总结

如果您之前没有实现过此类功能,则此控件的真正优势可能不会立即显现出来,但我们将在后续文章中使用它来构建编辑器表单。在接下来的文章看起来在验证过程中,如何构建一个简单的自定义验证。第三篇文章着眼于表单锁定,使用此控件作为流程的一部分。

如果您在以后发现这篇文章很好,最新版本将在此处提供

https://www.codeproject.com/Articles//A-Blazor-Edit-Form-State-Control

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/229611.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午4:18
下一篇 2026年3月16日 下午4:19


相关推荐

  • C++编程语言中stringstream类介绍

    C++编程语言中stringstream类介绍本文主要介绍C++编程语言中stringstream类的相关知识,同时通过示例代码介绍stringstream类的使用方法。1概述<sstream>定义了三个类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。本文以stringstream为主,介绍流的输入和输出操作。<sstream>主要用来进行数据类型转换,由于<sstream>使用string对

    2022年6月14日
    36
  • sigaction介绍

    sigaction介绍sigaction原型:intsigaction(intsigno,conststructsigaction*restrictact,structsigaction*restrictoact);@signo信号编号@act要注册的信号动作@oact原信号动作

    2022年5月9日
    42
  • 惊艳四射的意思_词语什么四射

    惊艳四射的意思_词语什么四射分享一些CSS3相关的按钮和导航,大部分素材应该都来自一些老外的设计,希望接下来的几篇文章对你会有所帮助,当然你的支持和点评也是我坚持做下去的动力。正文今天的这款CSS3按钮应该说是非常的光彩夺目,因为不仅它的色彩调得非常的和谐,更美妙的是如果你用chrome或者safari浏览器还能看到按钮发光的特效。以下是效果截图在线示例    |    源码下载这里的发光效果主要是如

    2025年6月28日
    2
  • mac上的VSCode快捷键

    mac上的VSCode快捷键Command+Shift+N打开新窗口Command+Shift+P/F1显示命令面板Command+\编辑器分屏Command+N新建文件Command+O打开文件command+,打开用户设置shift+option+F格式化代码Command+U撤销上一个光标操作Command+B显示、隐藏侧边栏Command+Shift+F显示搜索框Ctrl+Shift+G显示Git面板Command+

    2022年5月13日
    80
  • 基于机器学习的文本分类算法的研究[通俗易懂]

    基于机器学习的文本分类算法的研究[通俗易懂]1.简述文本分类的方法属于有监督的学习方法,分类过程包括文本预处理、特征抽取、降维、分类和模型评价。本文首先研究了文本分类的背景,中文分词算法。然后是对各种各样的特征抽取进行研究,包括词项频率-逆文档频率和word2vec,降维方法有主成分分析法和潜在索引分析,最后是对分类算法进行研究,包括朴素贝叶斯的多变量贝努利模型和多项式模型,支持向量机和深度学习方法。深度学习方法包括多层感知机,卷积神…

    2022年6月8日
    43
  • 关于安装空调的请示_searchmatch安装教程

    关于安装空调的请示_searchmatch安装教程dirsearch

    2026年4月16日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号