Winform界面中实现通用工具栏按钮的事件处理方法

所属分类: 软件编程 / C#教程 阅读数: 120
收藏 0 赞 0 分享

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

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接口,然后调用对应的处理函数实现功能的绑定。

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

更多精彩内容其他人还在看

c#开发word批量转pdf源码分享

已经安装有Office环境,借助一些简单的代码即可实现批量Word转PDF,看下面的实例源码吧
收藏 0 赞 0 分享

c# xml API操作的小例子

这篇文章主要介绍了c# xml API操作的小例子,有需要的朋友可以参考一下
收藏 0 赞 0 分享

c#唯一值渲染实例代码

这篇文章主要介绍了c#唯一值渲染实例代码,有需要的朋友可以参考一下
收藏 0 赞 0 分享

淘宝IP地址库采集器c#代码

这篇文章主要介绍了淘宝IP地址库采集器c#代码,有需要的朋友可以参考一下
收藏 0 赞 0 分享

C#在后台运行操作(BackgroundWorker用法)示例分享

BackgroundWorker类允许在单独的专用线程上运行操作。如果需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用BackgroundWorker类方便地解决问题,下面看示例
收藏 0 赞 0 分享

c#文本加密程序代码示例

这是一个加密软件,但只限于文本加密,加了窗口控件的滑动效果,详细看下面的代码
收藏 0 赞 0 分享

c#生成站点地图(SiteMapPath)文件示例程序

这篇文章主要介绍了c#生成站点地图(SiteMapPath)文件的示例,大家参考使用
收藏 0 赞 0 分享

C# 键盘Enter键取代Tab键实现代码

这篇文章主要介绍了C# 键盘Enter键取代Tab键实现代码,有需要的朋友可以参考一下
收藏 0 赞 0 分享

C# WinForm导出Excel方法介绍

在.NET应用中,导出Excel是很常见的需求,导出Excel报表大致有以下三种方式:Office PIA,文件流和NPOI开源库,本文只介绍前两种方式
收藏 0 赞 0 分享

C#串口通信程序实例详解

在.NET平台下创建C#串口通信程序,.NET 2.0提供了串口通信的功能,其命名空间是System.IO.Ports,创建C#串口通信程序的具体实现是如何的呢?让我们开始吧
收藏 0 赞 0 分享
查看更多