[C#.NET][Winform][User Control] 使用 IExtenderProvider 擴充控制項屬性 並 驗証控制項角色
比如說我要為Textbox增加一個叫Role的屬性,除了繼承Textbox類別增加屬性之外,我們還可以使用IExtenderProvider來為現有的物件擴充屬性,就像下圖那樣,新增了自己定義的屬性
有了Role屬性之後,我還要驗証登入的帳號是什麼Role,我會利用Thread.CurrentPrincipal屬性來決定角色及規則,若帳號的Role跟控制項的Role相同,該帳號才能使用這個控制項
開始前的準備:
1.我們會需要ProvideProperty Attribute,在類別加入以下定義,其中Role就是我們要擴充的屬性:
[ToolboxItemFilter("System.Windows.Forms"), ProvideProperty("Role", typeof(Control))]
2.類別需要繼承IExtenderProvider介面
3.類別裡需要定義SetRole以及GetRole方法,這樣才能在設計對話框裡看到Role屬性。
4.由GetRole方法回傳的型別決定屬性對話框的樣式,基本上它能依你的屬性來決定樣式,當然你也可以自己定義Attribute,就像下列程式碼是多行字串的樣式:
[DefaultValue(""), Localizable(true), Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
當然囉,特殊的屬性必須要自己定義,比如類別,詳細做法可參考我以前的文章,http://www.dotblogs.com.tw/yc421206/archive/2010/07/04/16351.aspx
接下來就來開始實作:
先建立一個User Control控制項專案Security.Forms
然後把UserControl1.cs改成RoleContainer.cs,並增加IExtenderProvider繼承,當然你也可以把UserControl的繼承改成Component;UserControl會在UI上顯示控制項,Component不會在UI上顯示控制項,我在VS2010找不到Component的範本,只好手動這樣改,先完成初步的外殼
namespace Security.Forms
{
[ToolboxItemFilter("System.Windows.Forms"), ProvideProperty("Role", typeof(Control))]
public partial class RoleContainer : Component, IExtenderProvider
{
#region 實作 IExtenderProvider 成员
public bool CanExtend(object target)
{
//排除自己跟Form
return ((target is Control) && !(target is RoleContainer) && !(target is Form));
}
#endregion
#region construct
public RoleContainer(IContainer Cont)
: this()
{
if (Cont == null)
{
throw new ArgumentNullException("cont");
}
Cont.Add(this);
}
public RoleContainer()
{
}
#endregion
//TODO:實作Role屬性
}
}
TODO裡要做的就是SetRole以及GetRole方法
private List<Role> _RoleControls = new List<Role>();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ReadOnlyCollection<Role> RoleControls
{
get
{
return new ReadOnlyCollection<Role>(this._RoleControls);
}
private set { }
}
public void SetRole(Control Ctrl, RoleType? ControlRole)
{
if (Ctrl is RoleContainer)
{
return;
}
if (ControlRole != null)
{
Ctrl.Enabled = Thread.CurrentPrincipal.IsInRole(ControlRole.ToString());
}
//判斷控制項是否存在
Role role = this.findControl(Ctrl, this._RoleControls);
if (role == null)
{
role = new Role() { Control = Ctrl, RoleType = ControlRole };
this._RoleControls.Add(role);
}
else
{
role.RoleType = ControlRole;
}
}
public RoleType? GetRole(Control Ctrl)
{
Role item = this.findControl(Ctrl, this._RoleControls);
if (item != null)
{
return item.RoleType;
}
else
{
return null;
}
}
Role findControl(Control Ctrl, List<Role> Collection)
{
//判斷控制項是否存在
var query = from data in Collection
where data.Control.Name == Ctrl.Name
let Index = Collection.IndexOf(data)
select new { Index };
int count = query.Count();
Role item = null;
if (count > 0)
{
item = Collection[query.First().Index];
}
return item;
}
建立Security.Role Class專案
加入RoleType類別
namespace Security.Role
{
public enum RoleType
{
Admin = 1,
User = 2,
PowerUser = 3,
}
}
加入Identity 類別
namespace Security.Role
{
public class Identity : IIdentity
{
public string AuthenticationType
{
get
{
return "Custom AuthenticationType";
}
}
public bool IsAuthenticated { get; internal set; }
public string Name { get; private set; }
public RoleType RoleType { get; set; }
public string Password { get; private set; }
public Identity(string Name)
: this(Name, "", RoleType.Admin)
{
}
public Identity(string Name, string Password)
: this(Name, Password, RoleType.Admin)
{
}
public Identity(string Name, RoleType Role)
: this(Name, "", Role)
{
}
public Identity(string Name, string Password, RoleType Role)
{
this.Name = Name;
this.Password = Password;
this.RoleType = Role;
}
}
}
加入Principle 類別,在這裡我用了一些假帳號資料DefaultRoles,verifyIdentity方法會去驗証帳號是否正確
namespace Security.Role
{
public class Principle : IPrincipal
{
#region 實作IPrincipal 成员
private Identity _Identity;
public IIdentity Identity
{
get
{
return _Identity;
}
}
//判斷角色是否在規則內
public bool IsInRole(string ControlRole)
{
RoleType controlRole = (RoleType)Enum.Parse(typeof(RoleType), ControlRole);
if (this._Identity == null)
{
//身份驗證失敗
return false;
}
else
{
//身份驗證成功
if (this._Identity.RoleType == controlRole)
{
//登入角色驗証成功
return true;
}
else
{
//登入角色驗証失敗
return false;
}
}
}
#endregion
public Principle(Identity Identity)
{
//搜尋帳號是否已建立
this._Identity = verifyIdentity(Identity);
if (this._Identity != null)
{
this._Identity.IsAuthenticated = true;
}
}
//身份驗証
Identity verifyIdentity(Identity Identity)
{
var query = from data in DefaultRoles
where data.Name.ToLower() == Identity.Name.ToLower()
let Index = this.DefaultRoles.IndexOf(data)
select new { Index };
int count = query.Count();
Identity identity = null;
if (count > 0)
{
identity = this.DefaultRoles[query.First().Index];
return identity;
}
else
{
return null;
}
}
public override string ToString()
{
if (this._Identity == null)
return "";
else
return string.Format("帳號:{0},角色:{1}", this._Identity.Name, this._Identity.RoleType.ToString());
}
//定義內建帳號
private List<Identity> _DefaultRoles;
public List<Identity> DefaultRoles
{
get
{
if (this._DefaultRoles == null)
{
this._DefaultRoles = new List<Identity>()
{
new Identity("admin",RoleType.Admin),
new Identity("user",RoleType.User),
new Identity("power",RoleType.PowerUser)
};
}
return _DefaultRoles;
}
}
}
}
完成後在Client裡引用它們建立以下控制項
定義控制項的Role屬性
呼叫以下方法決定控制項顯示樣式
void login(string user)
{
this._Ientity = new Identity(user);
this._Principle = new Principle(_Identity);
Thread.CurrentPrincipal = _Principle;
this.roleContainer1.SwitchRole();
this.label1.Text = this._Principle.ToString();
}
程式載入,有定義Role屬性的控制項,因身份不明被停用
按下power login
按下user login
範例下載
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET