混合式提高用户编辑与操作效率
近段时间修改一个较古老的项目,把涉及到的技术与问题分享于此。
提高用户操作效率,键盘录入数据与鼠标之间操作方面。
原来的操作,用户并没有什么说法,随之需要录入的数据量大,时间与效率自然产生。
下面把改善相关问题,集中成一个小案例,
SQL Code
ZTestData Code
ZTestDataEntity Code
View Code
View Code
View Code
View Code
提高用户操作效率,键盘录入数据与鼠标之间操作方面。
原来的操作,用户并没有什么说法,随之需要录入的数据量大,时间与效率自然产生。
下面把改善相关问题,集中成一个小案例,
项目是WebForm的asp.net。
是显示数据是使用Gridview服务控件。
每行最右边是更新按钮,各行各自更新。
在GridView外,即下面还有一个按钮,“一次性更新”,对所有行的备注进行一次性更新。
还有每行中的备注栏的文本框,用户输入备注信息后,点击文本框外,即更新。
它还可以输入完备注后,按回车亦可更新。
用户按自己习惯来操作。
为了这个示例,先准备一些数据,数据表,添加演示临时数据,创建存储过程,自定义表函数等...
-- ============================================= -- Author: Insus.NET -- Create date: 2026-04-28 -- Description: 数据表ZTestData -- ============================================= CREATE TABLE [dbo].[ZTestData] ( [ID] INT NOT NULL IDENTITY(1,1) PRIMARY KEY, [IMT_pz] NVARCHAR(30) NOT NULL, [IMT_gx] NVARCHAR(30) NOT NULL, [BeiZhu] NVARCHAR(30) NULL ) GO -- ============================================= -- Author: Insus.NET -- Create date: 2026-04-28 -- Description: 数据表添加一些示例临时数据 -- ============================================= INSERT INTO [dbo].[ZTestData] ( [IMT_pz], [IMT_gx] ) VALUES ( N'f043', N'P10' ) ,( N'l52', N'P10' ) ,( N'j71', N'P30' ) ,( N'v11', N'P20' ) ,( N'U33', N'P20' ) GO -- ============================================= -- Author: Insus.NET -- Create date: 2026-04-28 -- Description: 存储过程,获取所有数据 -- ============================================= CREATE PROCEDURE [dbo].[usp_ZTestData_SelectAll] AS BEGIN SELECT [ID], [IMT_pz], [IMT_gx], [BeiZhu] FROM [dbo].[ZTestData] END GO -- ============================================= -- Author: Insus.NET -- Create date: 2026-04-28 -- Description: 更新存储过程 -- ============================================= CREATE PROCEDURE [dbo].[usp_ZTestData_UpdateBeiZhu] @ID INT, @BeiZhu NVARCHAR(30) AS BEGIN UPDATE [dbo].[ZTestData] SET [BeiZhu] = @BeiZhu WHERE [ID] = @ID END GO -- ============================================= -- Author: Insus.NET -- Create date: 2026-04-28 -- Description: 创建一个表函,批量更新,作为存储过程传入的参数 -- ============================================= CREATE TYPE [dbo].[udtt_ZTestData_BZ] AS TABLE( [ID] [int] NOT NULL, [BeiZhu] [nvarchar](30) NULL ) GO -- ============================================= -- Author: Insus.NET -- Create date: 2026-04-28 -- Description: 批理更新存储过程 -- ============================================= CREATE PROCEDURE [dbo].[usp_ZTestData_BatchUpdate] @BatchBeiZhu [dbo].[udtt_ZTestData_BZ] READONLY AS BEGIN MERGE [dbo].[ZTestData] AS TARGET USING @BatchBeiZhu AS SOURCE ON TARGET.[ID] = SOURCE.[ID] WHEN MATCHED THEN UPDATE SET TARGET.[BeiZhu] = SOURCE.[BeiZhu] ; END GO
在App_Code目录下,添加2个类,虽然不是ASP.NET MVC项目,修改的项目.NET 2.0时代,那时MVC还没有出来吧。
ZTestData.cs
namespace Insus.NET { public class ZTestData { public int ID { get; set; } public string IMT_pz { get; set; } public string IMT_gx { get; set; } public string BeiZhu { get; set; } public DataTable BatchBeiZhu { get; set; } } }
ZTestDataEntity.cs
namespace Insus.NET { /// <summary> /// ZTestDataEntity 的摘要说明 /// </summary> public class ZTestDataEntity { BusinessBase objBusinessBase = new BusinessBase(); public DataTable Get_DataTable_GetData() { return objBusinessBase.GetDataToDataSet("usp_ZTestData_SelectAll").Tables[0]; } public void UpdateBeiZhu(ZTestData ztd) { Parameter[] parameter = { new Parameter("@ID",SqlDbType.Int,4,ztd.ID), new Parameter("@BeiZhu",SqlDbType.NVarChar,-1,ztd.BeiZhu) }; objBusinessBase.ExecuteProcedure("usp_ZTestData_UpdateBeiZhu", parameter); } public void BatchUpdateBeiZhu(ZTestData ztd) { Parameter[] parameter = { new Parameter("@BatchBeiZhu",SqlDbType.Structured,-1,ztd.BatchBeiZhu) }; objBusinessBase.ExecuteProcedure("usp_ZTestData_BatchUpdate", parameter); } } }
在App_Code目录下,创建一个新目录APIs,然后在此目录创建WebAPI
《WebForm实现Web API》https://www.cnblogs.com/insus/p/19937505
后端实现的功能,每行各自更新功能,和一次性更新功能。
public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Data_Binding(); } } private void Data_Binding() { ZTestDataEntity ztde = new ZTestDataEntity(); this.GridViewZTestData.DataSource = ztde.Get_DataTable_GetData(); this.GridViewZTestData.DataBind(); } protected void GridViewZTestData_RowCreated(object sender, GridViewRowEventArgs e) { if (e.Row.RowType != DataControlRowType.DataRow) return; Button btnUpdate = (Button)e.Row.FindControl("ButtonUpdate"); if (btnUpdate != null) { btnUpdate.Click += BtnUpdate_Click; } } private void BtnUpdate_Click(object sender, EventArgs e) { Button button = (Button)sender; GridViewRow gvr = (GridViewRow)button.Parent.Parent; var textboxBeiZhu = (TextBox)gvr.FindControl("TextBoxBeiZhu"); try { string keyVal = GridViewZTestData.DataKeys[gvr.RowIndex].Value.ToString(); ZTestData ztd = new ZTestData(); ztd.ID = Convert.ToInt32(keyVal); ztd.BeiZhu = textboxBeiZhu.Text.Trim(); ZTestDataEntity ztde = new ZTestDataEntity(); ztde.UpdateBeiZhu(ztd); //JsAlert("保存成功。"); } catch (Exception ex) { //JsAlert(ex.Message); return; } finally { Data_Binding(); } } protected void ButtonOneTimeUpdate_Click(object sender, EventArgs e) { DataTable _dt_bz = new DataTable(); _dt_bz.Columns.Add("ID", typeof(int)); _dt_bz.Columns.Add("BeiZhu", typeof(string)); foreach (GridViewRow gvr in this.GridViewZTestData.Rows) { int keyID = Convert.ToInt32(this.GridViewZTestData.DataKeys[gvr.RowIndex].Value); string bz = ((TextBox)gvr.FindControl("TextBoxBeiZhu")).Text.Trim(); _dt_bz.Rows.Add(keyID, bz); } try { ZTestData ztd = new ZTestData(); ztd.BatchBeiZhu = _dt_bz; ZTestDataEntity ztde = new ZTestDataEntity(); ztde.BatchUpdateBeiZhu(ztd); //JsAlert("数据已经保存。"); } catch (Exception ex) { //JsAlert(ex.Message); } } }
本随笔着重是GridView每行的备注文本框,让其实现OnBlur和用户输入完后按回车提交更新。
打开上面
protected void GridViewZTestData_RowCreated(object sender, GridViewRowEventArgs e)
let isUpdating = false; //更新请求 let skipBlurOnce = false; //区分是否为blur事件 function updateBeizhuByTextBox(txtboxElement) { return new Promise((resolve, reject) => { if (isUpdating) return reject("已有请求进行中"); var id = txtboxElement.id; var baseId = id.substring(0, id.lastIndexOf("_") + 1); var hiddenKey = document.getElementById(baseId + "HiddenFieldID"); isUpdating = true; let url = '/api/MyTest/UpdateBeiZhu'; var postData = { ID: hiddenKey.value, BeiZhu: txtboxElement.value.trim() }; axios.post(url, JSON.stringify(postData), { headers: { 'Content-Type': 'application/json; charset=utf-8' } }) .then(response => { if (!response.data.Status) { alert(response.data.Message); reject(response.data.Message); } else { alert(response.data.Message); resolve(response.data); } }) .catch(error => { console.error(error); reject(error); }) .finally(() => { isUpdating = false; }); }); }
function UpdateBeiZhu(event) { if (skipBlurOnce) { skipBlurOnce = false; return; } updateBeizhuByTextBox(event.target) .catch(console.warn); }
document.addEventListener('keydown', function (e) {
if (e.key === 'Enter' || e.keyCode === 13) {
var activeEl = document.activeElement;
if (activeEl && activeEl.getAttribute('data-bz') === 'gv-txtbox-beizhu') {
e.preventDefault();
skipBlurOnce = true; // 阻止随后的 blur 触发
activeEl.blur(); //让按完回车后文框的focus焦点去除。
updateBeizhuByTextBox(activeEl)
.catch(console.warn)
.finally(() => {
// 延迟重置标志,确保 blur 已被忽略
setTimeout(() => { skipBlurOnce = false; }, 300);
});
} else {
// 如果其他元素按回车不想提交表单,可以阻止默认
// e.preventDefault(); // 根据需求决定是否全局阻止
}
}
});
最后截屏图,还可以与下这篇对比,单独文框与GridView行内的文框按回车实现的方法。
《文本框输入完后直接按回车提交数据》https://www.cnblogs.com/insus/p/19811442
另外,你会看到下面代码:
var id = txtboxElement.id; var baseId = id.substring(0, id.lastIndexOf("_") + 1); var hiddenKey = document.getElementById(baseId + "HiddenFieldID");
日后你可以参考这个方法来获取GridView行中各列服务控件。
下面是示例运行时,按F12,在查看器展开代码可见,
TextBoxBeiZhu这是服务控件的ID,生成网页时,它的id会添加前缀高亮部分。GridView的ID + _Ctl +行索引_ + 列服务控件ID
var id = txtboxElement.id;
获取本身的ID。
var baseId = id.substring(0, id.lastIndexOf("_") + 1);
然后使用substring()进行切割得到ID前缀(高亮部分),
var hiddenKey = document.getElementById(baseId + "HiddenFieldID");
最后与服务控件ID拼接。
整篇关键功能随笔至此。看不明或者参考使用有啥问题,可以跟Insus.NET反馈或分享。





浙公网安备 33010602011771号