C#如何优雅的对WinForm窗体应用程序进行权限控制

目录
  • 前言
  • 数据库
  • 如何控制
  • 问题
  • 总结

前言

特别复杂特别高大上的系统我还没有机会接触,就我了解的来看,普通的功能权限控制的流程都差不多只有两个过程:

  • 获取当前用户拥有的权限
  • 在界面上对功能入库的可用性或者可见性进行控制

这里说一种在WinForm窗体应用开发时进行权限控制的办法,文章中主要针对上述两个过程的第二步。不过为了说清楚,我先简单说一下我的数据库功能表设计。

数据库

大家的权限数据库好像都差不多,我比较习惯Code First,所以就直接贴数据库对应的对象。记录下功能名称,所属模块,窗体名称,控件名称。权限表里面主要就是记录了用户(角色)ID和功能的对应了,有记录就表示该用户(角色)拥有该功能权限,没有记录就是没有权限。

/// <summary>
/// 系统功能
/// </summary>
[SugarTable("X_FUNCTION", "系统功能")]
public class FUNCTION
{
    [SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键", Length = 50)]
    public string GUID { get; set; }

    /// <summary>
    /// 功能名称
    /// </summary>
    [SugarColumn(ColumnDataType = "NVARCHAR2(30)", ColumnDescription = "功能名称")]
    public string NAME
    {
        get;
        set;
    }

    /// <summary>
    /// 模块ID
    /// </summary>
    [SugarColumn(ColumnDescription = "模块ID", Length = 50)]
    public string MODULEID
    {
        get;
        set;
    }

    /// <summary>
    /// 窗体名称
    /// </summary>
    [SugarColumn(ColumnDescription = "窗体名称", Length = 50)]
    public string FORMNAME
    {
        get;
        set;
    }

    /// <summary>
    /// 控件名称
    /// </summary>
    [SugarColumn(ColumnDescription = "控件名称", Length = 50)]
    public string CONTROLNAME
    {
        get;
        set;
    }
}

如何控制

最简单的方法,就是自己在代码里面把每个功能入口的控件都手动判断一遍,他们的name在不在有权限的功能列表的控件名称里。当然简单很有可能就代表麻烦,有的窗口可能要控制的上百控件,得写上百if-esle,这实在是太不优雅了,如果还有多个窗口的权限需要控制,那就真是灾难了。这个时候反射就可以起到比较好的作用。我们可以创建一个继承自Form的类,在这个类里面检查权限并设置控件是否可用。我使用了DevExpress控件,所以继承自XtraForm。然后只要窗口继承CheckPowerXtraForm,就可以进行权限控制了。

代码中有两个地方需要注意,第一是要等待创建窗口句柄再设置窗口控件的可用性。因为要等待,以及读数据库,所以不能放在主线程里面(写到这里,忽然觉得这个检查权限应该放在FormLoad事件里比较好,不用Thread.Sleep,不过要读数据库,还是不适合放在主线程)。

/// <summary>
/// 检查权限
/// </summary>
public class CheckPowerXtraForm : XtraForm
{
    public CheckPowerXtraForm()
    {
        //不要再主线程运行
        Task.Run(() =>
        {
            CheckPower();
        });
    }

    /// <summary>
    /// 检查权限
    /// </summary>
    private async void CheckPower()
    {
        var powerDal = new PowerDAL();
        var functions = await powerDal.GetPowerFunctionsByUserAsync(Global.User.GUID);
        //获取值属于本窗体的权限控件名称
        var formControls = functions.Where(f => f.FORMNAME == this.GetType().Name).Select(f => f.CONTROLNAME).ToList();
        //等待创建窗口句柄
        while (!this.Visible)
        {
            Thread.Sleep(100);
        }
        this.BeginInvoke(new Action(()=>{
            var type = this.GetType();
            var fields = this.GetType().GetFields(BindingFlags.NonPublic|BindingFlags.Instance);
            foreach (var field in fields)
            {
                var value = field.GetValue(this);
                if (value is Control)
                {
                    var control = value as Control;
                    if (!formControls.Contains(control.Name))
                    {
                        control.Enabled = false;
                    }
                }
                else if (value is BarItem)
                {
                    var item = value as BarItem;
                    if (!formControls.Contains(item.Name))
                    {
                        item.Enabled = false;
                    }
                }
                else if (value is ToolStripMenuItem)
                {
                    var item = value as ToolStripMenuItem;
                    if (!formControls.Contains(item.Name))
                    {
                        item.Enabled = false;
                    }
                }
            }
        }));
    }
}

问题

上面的做法有一个问题,窗口里面不是所有控件都需要权限控制的,有的是一些容器性的控件比如Groupbox,有的是一些是个用户就有的功能比如退出登录。按上面代码的做法,只要没有记录的,全部都会设置成不可用。所以我们需要对需要权限控制的做一个标记。有两个办法:

  • 把所有需要控制权限的控件Enabled都事先设置成false,然后有权限的就设置成true。
  • 给需要控制的控件设置一个特性。

下面说说第二种做法。首先定义一个特性,里面什么都不需要写。

/// <summary>
/// 检查权限的特性
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class CheckPowerAttribute : Attribute
{
}

然后给需要控制的控件赋予这个特性。

[CheckPowerAttribute]
private DevExpress.XtraBars.BarButtonItem mbbi_exportexcel;
[CheckPowerAttribute]
private DevExpress.XtraBars.BarButtonItem mbbi_exportcad;
[CheckPowerAttribute]
private DevExpress.XtraBars.BarButtonItem mbbi_exportshp;

然后在权限控制代码里只处理具有这个特性的控件。

//~~~
foreach (var field in fields)
{
    var cattributes = field.GetCustomAttributes(typeof(CheckPowerAttribute), false);
    if (cattributes.Length != 0)
    {
        var value = field.GetValue(this);
        if (value is Control)
        {
            var control = value as Control;
            if (!formControls.Contains(control.Name))
            {
                control.Enabled = false;
            }
        }
        else if (value is BarItem)
        {
            var item = value as BarItem;
            if (!formControls.Contains(item.Name))
            {
                item.Enabled = false;
            }
        }
        else if (value is ToolStripMenuItem)
        {
            var item = value as ToolStripMenuItem;
            if (!formControls.Contains(item.Name))
            {
                item.Enabled = false;
            }
        }
    }
}
//~~~

总结

说是优雅,其实自己一边写一边都觉得有不少改进的地方,比如CheckPower()执行的位置,还有设置Enable的时候用反射设置也会简洁很多,如果有更好的改进方案欢迎评论讨论。

到此这篇关于C#如何优雅的对WinForm窗体应用程序进行权限控制的文章就介绍到这了,更多相关C# WinForm窗体应用权限控制内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C# Winform 子窗体访问父级窗体的控件和属性

    今天在做一个联系人管理的C#设计时,遇到了这个问题,我需要将父窗体中的textBox中的值传到子窗体并进行数据库查询操作,我用了new 父窗体().textBox.text;来进行值传递,然而并无卵用,经过多次试验,找到了一个比较简单的解决方法: 一.子窗体调用父窗体的静态变量 父窗体:Logout 子窗体:Affirm 父窗体文本框:tB_Logout_Username public partial class Logout : Form { //定义一个静态变量存放父窗体中的文本框的值 pu

  • Winform窗体传值的方法(示例)

    进行用C#来开发windows应用程序项目时,不同窗口之间传值有很多种不同的方法, 假设项目中有两个窗体,Form1和Form2,要实现的效果是:点击Form1中的按钮打开From2,点击Form2中的按钮改变窗体Form1的背景颜色. 示例一: 点击Form1中的按钮打开From2,点击Form2中的按钮改变窗体Form1的背景颜色. Form1的代码: public partial class Form : Form { public Form() { InitializeComponent

  • WinForm中窗体间的数据传递交互的一些方法

    实际上过去我也写过类似的主题,这里把各种方法总结一下,内容的确基础了一些,所以这篇文章是写给刚刚学习C#的同行们的,希望对大家有些帮助吧!很抱歉,这篇文章没有诡异的bug来勾起大家的兴趣,但是下篇文章我会努力写些有趣的主题的! 在窗体间传递数据的方法比较多: 1,在子窗体中自定义一个构造函数,参数类型是主窗体,当要显示子窗体的时候,就用这个构造函数来实例化子窗体,然后把this指针传进去,说起来太抽象了,我大概一写大家应该就明白了: 复制代码 代码如下: public class frmMain

  • C#如何优雅的对WinForm窗体应用程序进行权限控制

    目录 前言 数据库 如何控制 问题 总结 前言 特别复杂特别高大上的系统我还没有机会接触,就我了解的来看,普通的功能权限控制的流程都差不多只有两个过程: 获取当前用户拥有的权限 在界面上对功能入库的可用性或者可见性进行控制 这里说一种在WinForm窗体应用开发时进行权限控制的办法,文章中主要针对上述两个过程的第二步.不过为了说清楚,我先简单说一下我的数据库功能表设计. 数据库 大家的权限数据库好像都差不多,我比较习惯Code First,所以就直接贴数据库对应的对象.记录下功能名称,所属模块,

  • C#中Winform窗体Form的关闭按钮变灰色的方法

    本文实例讲述了C#中Winform窗体Form的关闭按钮变灰色的方法,对C#程序设计有一定的借鉴价值,分享给大家供大家参考之用.具体方法如下: 主要功能代码如下: [ DllImport ( "USER32.DLL" ) ] public static extern int GetSystemMenu(int hwnd, int bRevert); [ DllImport ( "USER32.DLL" ) ] public static extern int Rem

  • Winform窗体效果实例分析

    本文实例分析了Winform窗体效果.分享给大家供大家参考.具体如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace WindowsApplication4 { public partial cl

  • C# WinForm窗体编程中处理数字的正确操作方法

    使用C#进行WinForm开发时,经常需要从WinForm窗体中获取用户输入数据.如果是字符串,那很好办,直接使用"控件名.Text"即可.但如果是数字类型的值呢?怎么样获取?怎么样判断?怎么样转换?怎么样错误提示?且看下文. 假如我要从WinForm界面上获取一个用户输入的数字,代码如下: 复制代码 代码如下: int num; //定义一个int类型的变量来接收值 //假设接收用户输入的文本框控件名称为"txtNum",txtNum.Text为字符串类型. //

  • 浅谈C# winForm 窗体闪烁的问题

    在构造函数里加上以下代码: this.DoubleBuffered = true;//设置本窗体 SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景. SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲 //SetStyle(ControlStyles.DoubleBuffer | Contro

  • WinForm窗体间传值的方法

    本文实例讲述了WinForm窗体间传值的方法.分享给大家供大家参考.具体实现方法如下: 窗体间传递数据,无论是父窗体操作子窗体,还是子窗体操作符窗体,有以下几种方式:   1.公共静态变量: 2.使用共有属性: 3.使用委托与事件: 4.通过构造函数把主窗体传递到从窗体中: 一.通过静态变量 特点:传值是双向的,实现简单   实现代码如下: 在一个app类中定义一个静态成员value 复制代码 代码如下: public class app { public static string value

  • Winform窗体圆角设计代码

    网上看到的很多winform窗体圆角设计代码都比较累赘,这里分享一个少量代码就可以实现的圆角.主要运用了System.Drawing.Drawing2D. 效果图 代码如下 private void BeautiLoginForm_Paint(object sender, PaintEventArgs e) { Type(this, 25, 0.1); } private void Type(Control sender, int p_1, double p_2) { GraphicsPath

  • 在多线程中调用winform窗体控件的实现方法

    本文实例讲述了在C#中实现多线程中调用winform窗体控件的方法,对于C#程序设计的学习有着很好的借鉴参考价值.具体方法如下: 首先,由于Windows窗体控件本质上不是线程安全的.因此如果有两个或多个线程适度操作某一控件的状态(set value),则可能会迫使该控件进入一种不一致的状态.还可能出现其他与线程相关的 bug,包括争用和死锁的情况.于是在调试器中运行应用程序时,如果创建某控件的线程之外的其他线程试图调用该控件,则调试器会引发一个 InvalidOperationExceptio

  • Winform窗体如何改变语言类型

    Winform改变语言类型比较复杂,需要根据不同语言应用语言资源.而软件在进行语言切换时,需要将当前的UI文化线程引用对应的语言类型.常用的有三种方式,此处使用两种,对比发现其中的优缺点: /// <summary> /// 获取UI的文化信息 /// 创建者:杨钊 /// 创建时间:2019.05.20 /// </summary> /// <param name="language">语言</param> /// <return

随机推荐