在一个给客户做的项目中,界面要求修改增加通用工具栏按钮的事件处理,也就是在主界面中放置几个固定的功能操作按钮,打开不同的页面的时候,实现对应页面的功能处理,这种和我标准的界面处理方式有所不同,标准的列表界面,一般在界面中放置了一些常规的按钮,如查询/更新、新建、编辑、删除、导入、导出等常规操作,现在是需要把这些提升到主界面的层次上放置按钮,这种处理方式也算是提供一种方便吧。本篇随笔介绍实现这个功能的思路和代码实现逻辑。

1、界面功能介绍

这里要实现的通用工具栏按钮的事件处理,具体的界面是这样的,我们处于一个多文档的主界面中,在主界面的顶部工具栏放置这些通用的工具栏按钮,以便提高相关的处理便利和效率。

从上面的界面我们可以看到,程序主界面的顶部工具栏上有一些常规的操作,包括如查询、新建、编辑、删除、导入、导出等按钮,可以为程序的功能操作提供方便。

当我们打开一个新的窗体页面,那么对应的按钮事件也应该和这个窗体相关,或者我们切换到其他窗体,那么按钮的处理事件也应该跟着变化到对应的窗体上,这种就是我们需要的效果。

上面的逻辑也就是我们新建一个窗体、或者切换一个窗体,那么需要通知顶部工具栏进行更新或者进行一个对接的处理才可以。

2、界面窗体基类的处理

由于我们想尽可能的减少开发的工作量,因此希望在基类进行一些事件或者接口的封装,以便降低新建列表窗体的时候的代码编写。

对于一个如查询操作的处理事件,我们需要定义一个接口来实现这个功能,这样我们才可以在打开的窗体的时候,把它转换为对应的接口处理。

例如我们定义一个IMenuAction的接口,以更新事件为例,需要实现三部分的接口,一个是事件定义,一个是判断是否包含更新事件,一个是具体的处理逻辑。

    /// <summary>
/// 定义菜单中的通用按钮事件
/// </summary>
public interface IMenuAction
{
/// <summary>
/// 更新按钮事件
/// </summary>
event EventHandler Refresh_MenuEvent; /// <summary>
/// 是否包含更新事件
/// </summary>
bool HasEventRefresh { get; } /// <summary>
/// 更新操作
/// </summary>
void ProcessRefresh(object sender, EventArgs e);

对于其他总共6个标准的按钮事件处理,我们也同样一样定义,那么整个IMenuAction的接口定义如下所示。

    /// <summary>
/// 定义菜单中的通用按钮事件
/// </summary>
public interface IMenuAction
{
/// <summary>
/// 更新按钮事件
/// </summary>
event EventHandler Refresh_MenuEvent;
/// <summary>
/// 新建按钮事件
/// </summary>
event EventHandler Add_MenuEvent;
/// <summary>
/// 编辑按钮事件
/// </summary>
event EventHandler Edit_MenuEvent;
/// <summary>
/// 删除按钮事件
/// </summary>
event EventHandler Delete_MenuEvent;
/// <summary>
/// 导入按钮事件
/// </summary>
event EventHandler Import_MenuEvent;
/// <summary>
/// 导出按钮事件
/// </summary>
event EventHandler Export_MenuEvent; /// <summary>
/// 是否包含更新事件
/// </summary>
bool HasEventRefresh { get; }
/// <summary>
/// 是否包含增加事件
/// </summary>
bool HasEventAdd { get; }
/// <summary>
/// 是否包含编辑事件
/// </summary>
bool HasEventEdit { get; }
/// <summary>
/// 是否包含删除事件
/// </summary>
bool HasEventDelete { get; }
/// <summary>
/// 是否包含导入事件
/// </summary>
bool HasEventImport { get; }
/// <summary>
/// 是否包含导出事件
/// </summary>
bool HasEventExport { get; } /// <summary>
/// 更新操作
/// </summary>
void ProcessRefresh(object sender, EventArgs e);
/// <summary>
/// 增加操作
/// </summary>
void ProcessAdd(object sender, EventArgs e);
/// <summary>
/// 编辑操作
/// </summary>
void ProcessEdit(object sender, EventArgs e);
/// <summary>
/// 删除操作
/// </summary>
void ProcessDelete(object sender, EventArgs e);
/// <summary>
/// 导入操作
/// </summary>
void ProcessImport(object sender, EventArgs e);
/// <summary>
/// 导出操作
/// </summary>
void ProcessExport(object sender, EventArgs e);
}

那么对于列表界面的基类窗体,我们除了让他继承自XtraForm这个标准的窗体外,我们还让它实现对应的IMenuAction接口,如下是列表界面基类BaseDock的窗体定义。

    /// <summary>
/// 用于一般列表界面的基类
/// </summary>
public partial class BaseDock : XtraForm, IMenuAction

那么这个BaseDock的基类需要实现那些通用按钮事件的接口,如下所示。

        #region 通用按钮菜单事件
/// <summary>
/// 更新按钮事件
/// </summary>
public event EventHandler Refresh_MenuEvent;
/// <summary>
/// 根据事件判断是否有
/// </summary>
public bool HasEventRefresh
{
get
{
return Refresh_MenuEvent != null;
}
}
/// <summary>
/// 调用事件定义
/// </summary>
public void ProcessRefresh(object sender, EventArgs e)
{
if (Refresh_MenuEvent != null)
{
Refresh_MenuEvent(sender, e);
}
} ....................... #endregion

通过基类的这样处理,我们就可以在具体列表窗体里,赋值给对应的事件就可以了。

3、列表窗体界面的处理

例如我们处理一个应用菜单的列表管理界面,定义窗体如下所示,继承了我们所实现IMenuAction的基类BaseDock。

    /// <summary>
/// 应用菜单管理
/// </summary>
public partial class FrmApplicationMenu : BaseDock

那么我们需要指定它的几个处理事件,初始化代码如下所示。

        /// <summary>
/// 初始化公用菜单按钮的处理
/// </summary>
private void InitMenuAction()
{
this.Refresh_MenuEvent += (s, e) => { btnSearch_Click(s, e); };
this.Add_MenuEvent += (s, e) => { btnAddNew_Click(s, e); };
this.Edit_MenuEvent += (s, e) => { winGridViewPager1_OnEditSelected(s, e); };
this.Delete_MenuEvent += (s, e) => { winGridViewPager1_OnDeleteSelected(s, e); };
this.Import_MenuEvent += (s, e) => { btnImport_Click(s, e); };
this.Export_MenuEvent += (s, e) => { btnExport_Click(s,e);};
}

这样我们就知道对应接口是如何和具体的页面事件发生关系了。

4、主窗体界面的处理

我们在构建主界面的左侧功能树的时候,我们通过树列表的选中事件加载对应的窗体,具体代码如下所示。

    //处理树形菜单的点击操作,如果TAG存在,则解析并加载对应的页面到多文档里面
treeView.AfterSelect += (sender, e) =>
{
string tag = e.Node.Tag as string;
if (!string.IsNullOrEmpty(tag))
{
LoadPlugInForm(tag);
}
};

在这个函数里面,我们最终是通过配置动态构建对应的窗体,LoadPlugInForm逻辑的最终实现的部分代码如下所示。

    var form = LoadMdiForm(this.mainForm, objType, isShowDialog);
RefreshButton(form);

这里我们构建窗体或者激活窗体都获得一个窗体对象,然后刷新功能按钮的状态处理即可。

    /// <summary>
/// 更新按钮状态
/// </summary>
/// <param name="form">当前窗体</param>
public void RefreshButton(Form form)
{
this.CurrentForm = form;
IMenuAction action = form as IMenuAction;
if (action != null)
{
//事件处理后再判断
menuButton.refresh.Enabled = (action.HasEventRefresh);
menuButton.add.Enabled = (action.HasEventAdd);
menuButton.edit.Enabled = (action.HasEventEdit);
menuButton.delete.Enabled = (action.HasEventDelete);
menuButton.import.Enabled = (action.HasEventImport);
menuButton.export.Enabled = (action.HasEventExport);
}
}

这样的处理,就可以实现了在主界面的多文档处理中,不管我们是新建一个列表窗体,还是激活切换到一个其他的窗体的时候,按钮的状态和对应的窗体绑定,实现随时更新显示。

当然通用工具栏按钮的事件我们需要初始化,它是根据当前选中的窗体进行统一的处理的,具体代码如下所示。

        /// <summary>
/// 初始化菜单按钮的事件处理
/// </summary>
private void InitMenuEvent()
{
//事件绑定
//先实现事件绑定
menuButton.add.ItemClick += (s, e) =>
{
if (CurrentForm != null)
{
IMenuAction action = CurrentForm as IMenuAction;
if (action != null)
{
action.ProcessAdd(s, e);
}
}
};
menuButton.edit.ItemClick += (s, e) =>
{
if (CurrentForm != null)
{
IMenuAction action = CurrentForm as IMenuAction;
if (action != null)
{
action.ProcessEdit(s, e);
}
}
};
menuButton.delete.ItemClick += (s, e) =>
{
if (CurrentForm != null)
{
IMenuAction action = CurrentForm as IMenuAction;
if (action != null)
{
action.ProcessDelete(s, e);
}
}
};
menuButton.import.ItemClick += (s, e) =>
{
if (CurrentForm != null)
{
IMenuAction action = CurrentForm as IMenuAction;
if (action != null)
{
action.ProcessImport(s, e);
}
}
};
menuButton.export.ItemClick += (s, e) =>
{
if (CurrentForm != null)
{
IMenuAction action = CurrentForm as IMenuAction;
if (action != null)
{
action.ProcessExport(s, e);
}
}
};
menuButton.refresh.ItemClick += (s, e) =>
{
if (CurrentForm != null)
{
IMenuAction action = CurrentForm as IMenuAction;
if (action != null)
{
action.ProcessRefresh(s, e);
}
}
};
}

上面这个事件只需要绑定一次,不会造成按钮的事件多次绑定问题,虽然一次绑定,它的具体处理还是和当前窗体有关,它会把当前窗体转换为对应的IMenuAction接口,然后调用对应的处理函数实现功能的绑定。

以上就是我对于实现这种通用按钮事件处理的思路和具体逻辑代码,供大家参考学习,有错漏之处还请多多包涵。

Winform界面中实现通用工具栏按钮的事件处理的更多相关文章

  1. 在Winform界面中实现对多文档窗体的参数传值

    在Winform界面中窗体我们一般使用多文档进行展示,也就是类似一般的选项卡的方式可以加载多个窗体界面.一般来说,我们如果打开新的窗体,给窗体传递参数是很容易的事情,但是在框架层面,一般的窗体是通过动 ...

  2. Winform界面中主从表编辑界面的快速处理

    在Winform开发中,我们往往除了常规的单表信息录入外,有时候设计到多个主从表的数据显示.编辑等界面,单表的信息一般就是控件和对象实体一一对应,然后调用API保存即可,主从表就需要另外特殊处理,本随 ...

  3. C# Winform 界面中各控件随着窗口大小变化

    在做一项工程中,由于不确定目标平台的分辨率,而正常使用要求铺满整个屏幕,所以界面中的各个控件必须能够适应窗口的变化. 首先想到的就是控件的百分比布局,但是再尝试写了几个控件的Location和Size ...

  4. Winform界面中实现菜单列表的动态个性化配置管理

    在我们一般的应用系统里面,由于系统是面向不同类型的用户,我们所看到的菜单会越来越多,多一点的甚至上百个,但是我们实际工作接触的菜单可能就是那么几个,那么对于这种庞大的菜单体系,寻找起来非常不便.因此对 ...

  5. 原创+部分引用啦:C# Winform界面中的分隔线问题

    C sharp 中Winform中的控件很多,一个小小的问题居然会绕上一个小弯子,做界面的时候, 你需要在界面上弄一条分隔线,把相关的功能分隔开来,结果原来在其它 IDE编辑器里很容易实现的这个功能, ...

  6. 在Winform界面中使用DevExpress的TreeList实现节点过滤查询的两种方式

    在我较早的一篇随笔<在DevExpress程序中使用TeeList控件以及节点查询的处理>中,介绍了在树形列表TreeList控件上面,利用SearchControl实现节点的模糊查询过滤 ...

  7. WinForm界面中快捷键设置

    这是对整个界面的快捷键的设置,比如查询,保存. 1 protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { if ...

  8. C#470多例winform 界面特效的源码

    一共470多例winform 界面特效的源码. 窗体与界面设计... 9 实例001  带历史信息的菜单    10 实例002  菜单动态合并    12 实例003  像开始菜单一样漂亮的菜单.. ...

  9. Web界面和Winform界面生成,代码生成工具

    在上面一篇随笔<代码生成工具之界面快速生成>介绍了代码生成工具Database2Sharp的界面生成操作,其中介绍了Web界面(包括列表界面.内容显示.内容编辑界面的生成,另外还介绍了Wi ...

随机推荐

  1. Python学习笔记(九)

    Python学习笔记(九): 装饰器(函数) 内置函数 1. 装饰器 1. 作用域 2. 高阶函数 3. 闭包 如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就 ...

  2. Locust性能测试框架,从入门到精通

    1. Locust简介 Locust是使用Python语言编写实现的开源性能测试工具,简洁.轻量.高效,并发机制基于gevent协程,可以实现单机模拟生成较高的并发压力. 主要特点如下: 使用普通的P ...

  3. Unix时代的开创者Ken Thompson

    自图灵奖诞生以来,其获得者一直都是计算机领域的科学家与学者,而在所有这些界的图灵奖中只有唯一的一届有个例外,那就是Ken Thompson与Dennis M. Ritchie,他们都是计算机软件工程师 ...

  4. JAVA基础知识总结:六

    一.不定长参数 1.语法:数据类型... 变量名称 使用注意事项:a.不定长参数就相当于是一个数组 b.不定长参数只能出现在参数列表的最后面 c.一个函数的参数列表中只能出现一次不定长参数 d.对于不 ...

  5. 解决phpstorm ftp自动保存文件问题

    初次使用phpstorm, 1.配置ftp时,远程文件要用/ftp用户名/文件夹名: 2.由于版本管理的原因(猜测),直接从本地原有文件修改时各种办法都无法上传,结果从服务器上下载一份再修改,解决这个 ...

  6. asp.net中使用jquery ajax保存富文本的问题

    前提:为了保证页面的不刷新行为,所以采用了html+jquery+handler的页面保存方式,通过ajax将富文本内容传递给一般处理程序进行操作. 一.问题:1.大文件无法上传? 2.传入handl ...

  7. 第三章 CUDA设备相关

    这章介绍了与CUDA设备相关的参数,并给出了了若干用于查询参数的函数. 章节代码(已合并): #include <stdio.h> #include "cuda_runtime. ...

  8. DOM 遍历-同胞

    在 DOM 树中水平遍历 有许多有用的方法让我们在 DOM 树进行水平遍历: siblings() next() nextAll() nextUntil() prev() prevAll() prev ...

  9. ⑾bootstrap组件 徽章 大屏 页头 基础案例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 数据结构 单链表元素定位 PTA

    由于这个很简单,他也貌似没要判断溢出,取巧突破 #include<stdio.h> #include<malloc.h> #include<stdlib.h> // ...