<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      WPF應用中一種比較完美的權限控制設計方式

      如題近段時間 需要在wpf應用中設計一個權限控制 , 簡而言之的說 你懂的 對于IT人員來說都知道的 常見的軟件功能 首先要有用戶 用戶,然后用戶屬于哪個角色 ,然后各個角色都有自己的可供操作的一堆功能,當然還有其它的復雜的控制方式 我并不想弄 只搞這種比較通用的。

      首先是權限管理界面 以及數據操作 一堆功能的實現 比如 添加角色 設置權限,這個其實沒啥好說的 就像你做傳統的winform或者web一樣 搞界面 訪問數據庫 做功能, 就是按部就班 。好吧 看下我用到的業務數據處理方法吧:

       1 public class UserLogic
       2 {
       3     internal UserInfo GetUserById(int id)
       4     {        }
       5 
       6     internal void AddOrSaveUser(UserInfo user)
       7     {        }
       8     internal List<UserInfo> GetDBUsers()
       9     {        }
      10 
      11     internal List<RoleInfo> GetRoles()
      12     {        }
      13 
      14     internal List<AuthorizationInfo> GetAllAuths()
      15     {        }
      16 
      17     internal RoleInfo GetRoleByID(int id)
      18     {        }
      19 
      20     internal List<AuthorizationInfo> GetAuthsByRoleID(int rid)
      21     {        }
      22 
      23     internal void SetAuthsByRoleID(int rid,List<EAuthorizationItem> auths)
      24     {        }
      25 
      26     internal int AddOrSaveRole(RoleInfo ro)
      27     {        }
      28 
      29     internal void DelRole(int id)
      30     {        }
      31 
      32     internal RoleInfo GetRoleByName(string name)
      33     {        }
      34 }

      刪除角色:

       1 internal void DelRole(int id)
       2 {
       3     using (MyContext db = new MyContext())
       4     {
       5         var existR = db.roles.FirstOrDefault(r => r.ID == id);
       6         db.roles.Remove(existR);
       7 
       8         var auths = db.auths.Where(r => r.RoleID == id).ToList();
       9         db.auths.RemoveRange(auths);
      10 
      11         //已經用到了此角色 的用戶 改為默認角色
      12         var users = db.users.Where(r => r.RoleID == id).ToList();
      13         var defRole = db.roles.FirstOrDefault(r => r.Name == nameof(RoleNameDefine.User));
      14         for (int i = 0; i < users.Count; i++)
      15         {
      16             users[i].RoleID = defRole.ID;
      17         }                               
      18 
      19         db.SaveChanges();
      20     }
      21 }

      設置權限:

       1 internal void SetAuthsByRoleID(int rid,List<EAuthorizationItem> auths)
       2 {
       3     using (MyContext db = new MyContext())
       4     {
       5         var existAuths= db.auths.Where(r=>r.RoleID==rid).ToList();
       6         db.auths.RemoveRange(existAuths);
       7 
       8         List<AuthorizationInfo> besave = new List<AuthorizationInfo>();
       9         for (int i = 0; i < auths.Count; i++)
      10         {
      11             besave.Add(new AuthorizationInfo()
      12             {
      13                 RoleID = rid,
      14                 AuthE = auths[i]
      15             });
      16         }
      17 
      18         db.auths.AddRange(besave);
      19         db.SaveChanges();
      20     }
      21 }

      關于最終界面的樣子嘛,也沒美化就這樣:

       

      然后就是 特定操作的 權限  ,“權限” 這個東西我們以什么方式來描述  ,說白了就是 固定的字符串 比如"Add_xxInfo" "Del_xxInfo" ,再怎么我們的系統還是比較小 屬于比較保守的 ,說白了就那么幾個功能。不可能敞著 ,我們還是得以固定代碼的方式定義這些描述  要不字符串 要不枚舉。由于我自己借鑒了一種方式 可以比較方便的 完成 枚舉數據 從代碼 到數據庫  以及界面顯示 的交換。最終經過反復斟酌 我們還是選用了枚舉: 

       1 public enum EAuthorizationItem
       2 {
       3     [EnumDescription("打印機或自助機信息更新")]
       4     PrinterOrTerminalUpdate,
       5     [EnumDescription("打印機或自助機刪除")]
       6     PrinterOrTerminalDel,
       7     [EnumDescription("數據接口管理")]
       8     DataSourceMgt,
       9     [EnumDescription("用戶信息刪除")]
      10     UserDel,
      11     [EnumDescription("用戶信息更新")]
      12     UserUpdate,
      13     [EnumDescription("權限管理")]
      14     RoleMgt
      15 }

      接下來的思路也是順水推舟:
      登錄的時候 就能夠確定所擁有的所有權限 生成功能標識數組,在登錄結果里返回到客戶端 ,客戶端功能界面處 傳入功能標識參數 通過一個統一的入口 與登錄信息里的功能標識 數組 匹配 進而確定界面此部分功能是否啟用。web那一套都熟悉 我們都知道怎么做,說起來簡單 其實是琢磨了好久的,這是wpf。 首先要形成統一入口,不能到處編寫權限判斷代碼 否則就違背我們的初衷了 哪怕復制粘貼同樣的也不行, 我是用的mvvm方式 的, 如果我要做的話直接在viewModel里面 編寫權限判斷代碼 很簡單 毫無難度。然后另一個 可以綁定command 他可以通過canexecute 來影響界面是否可用 ,也是不錯的方式 ,但是我由于一些特殊的原因 不能使用此方式。

      說道此處最顯而易見的都知道了 IsEnable=”{binding}“ ,特別說一下 通過此次的使用 讓我對wpf的binding 有了一個更清晰的理解,binding 幾大要素 ,source 數據源 沒有指定source的時候默認以當前dataContext 一級一級的向上找 ,這也是我們使用mvvm的基本支撐。然后 還有 path ,綁定方向 和 converter不用多說了。為了這玩意兒我們也是煞費苦心。首先確定的是binding 必須要用binding ,我們要用的就是它自動化計算的功能 ,什么時候自動化計算 稍后再說。為了綁定功能標識傳入參數 ,于是我們首先想到從 source入手 讓其定位到一個static的東西 好處有二 ,首先static的 在一個地方統一編寫就行了統一引用 維護方便不易出錯,第二個有編輯提示 也就是.能.出東西來 比你硬編碼字符串 不只是好點吧點。binding不都是動態值嗎 我們此處卻都是一個固定值 這感覺怪怪的,不要怪。我們上面說了利用他的動態計算功能 ,此處可以說明了 那就是converter ,通過熟讀wpf 綁定原理過程 觀察它走的路線你就會知道 最終是通過converter暴露的,對我們就在此處進行截獲 。對功能標識參數與當前用戶進行匹配 進而決定界面是否可用。說實話前面的你可以認為是傳進來的已知參數。

      好 看看我們的綁定

      <MenuItem Header="編輯所選項" Name="me_Update" Click="me_Update_Click" IsEnabled="{Binding  UserUpdate ,Source={x:Static cd:AuthorizationItemDefine.Default},Converter={StaticResource auCOnverter}  }"></MenuItem>

      來復習下wpf的綁定原理 source是讓其定位到一個靜態變量 而不是當前自動分配的datacontext, 然后綁定到里面的RoleMgt屬性。Source={x:Static 這個是wpf設計很nice的地方 ,我們通過一個static的靜態變量 但是類是new出來的 也就是單例模式,到處綁定 。

      靜態綁定定義:

       1 public class AuthorizationItemDefine : PropertyChangedBase
       2 {
       3     public static AuthorizationItemDefine Default { get { return m_Default; } }
       4     private static AuthorizationItemDefine m_Default = new AuthorizationItemDefine();
       5     AuthorizationItemDefine()
       6     {
       7     }
       8 
       9     public void RiseProperty()
      10     {
      11         OnPropertyChanged(() => PrinterOrTerminalUpdate);
      12         OnPropertyChanged(() => PrinterOrTerminalDel);
      13         OnPropertyChanged(() => DataSourceMgt);
      14         OnPropertyChanged(() => UserDel);
      15         OnPropertyChanged(() => UserUpdate);
      16         OnPropertyChanged(() => RoleMgt);
      17     }
      18     public EAuthorizationItem PrinterOrTerminalUpdate
      19     {
      20         get
      21         { return EAuthorizationItem.PrinterOrTerminalUpdate; }
      22     }
      23     public EAuthorizationItem PrinterOrTerminalDel
      24     {
      25         get
      26         { return EAuthorizationItem.PrinterOrTerminalDel; }
      27     }
      28     public EAuthorizationItem DataSourceMgt
      29     {
      30         get
      31         { return EAuthorizationItem.DataSourceMgt; }
      32     }
      33 
      34     public EAuthorizationItem UserDel
      35     {
      36         get
      37         { return EAuthorizationItem.UserDel; }
      38     }
      39     public EAuthorizationItem UserUpdate
      40     {
      41         get
      42         { return EAuthorizationItem.UserUpdate; }
      43     }
      44     public EAuthorizationItem RoleMgt
      45     {
      46         get
      47         { return EAuthorizationItem.RoleMgt; }
      48     }
      49 }

      頁面需要引入,以及定義converter:

      1 xmlns:cd="clr-namespace:Common.Define;assembly=Common"
      2 xmlns:cc="clr-namespace:AutoPrintClient"
      3 <UserControl.Resources>
      4     <cc:AuthConverter x:Key="auCOnverter"/>
      5 </UserControl.Resources>

      轉換器很簡單,就是看登錄信息里有無對應的功能標識:

       1 class AuthConverter : IValueConverter
       2 {
       3     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
       4     {
       5         if (value == null)
       6             return false;
       7         if (Runtime.Default.loginInfo == null || Runtime.Default.loginInfo.Auths == null)
       8             return false;
       9         string machAu = value.ToString();
      10         if (Runtime.Default.loginInfo.Auths.Contains(machAu))
      11         {
      12             return true;
      13         }
      14         else
      15         {
      16             return false;
      17         }
      18     }
      19 
      20     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      21     {
      22         throw new NotImplementedException();
      23     }
      24 }

      我們在用戶登錄之處就已經把功能標識數組 附在返回的登錄信息里(Auths):

       1 //用戶登錄
       2 var user = db.users.FirstOrDefault(r => r.LoginName == loginName && r.Password == password);
       3 if (user != null)
       4 {
       5     RoleInfo ptrU = db.roles.FirstOrDefault(r => r.ID == user.RoleID);
       6     log = new LoginInfo();
       7     log.LoginName = loginName;
       8     log.Password = password;
       9     log.LoginAt = DateTime.Now;
      10     if (ptrU != null)
      11     {
      12         log.RoleID = ptrU.ID;
      13         log.RoleName = ptrU.Name;
      14         log.RoleDescription = ptrU.Description;
      15 
      16         var auths= db.auths.Where(r => r.RoleID == log.RoleID).ToList();
      17         for (int i = 0; i < auths.Count; i++)
      18         {
      19             log.Auths.Add(auths[i].AuthE.ToString());
      20         }
      21     }
      22 }
      23 else
      24 {
      25     errorMsg = "數據庫未找到對應用戶記錄";
      26 }

      問題又來了 ,何時進行更新

      測試發現界面一直沒有更新置灰 ,最后我們跟蹤發現原來是usercontrol一出現的時候 就通過converter完成了binding ,而這時候其實我們還沒有登錄,而converter又是一個很特殊的玩意兒。我們是無法代碼手動去觸發他的,通過復習binding過程 推斷 還是只得從值本身出發 , 這樣converter就會觸發了,去更新這個"其實是一直不變"的值 是不是一種很詭異的感覺 哈哈哈哈哈哈。。通過以前的知識我們知道 onPropertyChange 會觸發依賴屬性更新界面 。好咧 那就是他了 我們在前面的代碼里加上RiseProperty方法 在里面刷新所有屬性。其實上面已經是完整形式的代碼了 ,就是上面貼出來的RiseProperty()方法這里就不貼了。思路順水推舟 我們接下來做的自然是在 登錄時進行 權限刷新 各處的界面刷新,通過與上面的結合 真是神來之筆。

      登錄刷新調用代碼:

      1 private void Click_login(object sender, RoutedEventArgs e)
      2 {
      3     if (vm.Login(passwordBox.Password) == true)
      4     {
      5         dlg_login.Visibility = Visibility.Hidden;
      6         this.uct_Onlines.LoadFirstPage();
      7         AuthorizationItemDefine.Default.RiseProperty();
      8     }
      9 }

      最終的不同用戶登錄效果:

       

       

       

      測試發現只需再登錄成功后統一刷新一下就可以了 ,各處都會 按設想的工作 ,完美。干凈手段解決問題的方式 你會發現  真的 真的 真的 很爽。

       

      posted @ 2020-11-13 13:23  assassinx  閱讀(5164)  評論(2)    收藏  舉報
      主站蜘蛛池模板: 国产日韩精品一区二区三区在线| 日本丰满熟妇videossexhd| 国产一精品一av一免费爽爽| 亚洲精品熟女一区二区| 少妇被粗大的猛烈进出视频| 托克逊县| 亚洲性夜夜天天天| 午夜福利在线观看6080| 国产成人亚洲精品成人区| 自拍偷拍一区二区三区四| 国产成人欧美一区二区三区在线| 徐闻县| 免费无码久久成人网站入口| 久久国产精品第一区二区| 亚洲第一区二区快射影院| 国产在线一区二区不卡| 极品人妻少妇一区二区三区| 国产农村妇女高潮大叫| 当雄县| 99久久亚洲综合精品成人网| 日本不卡不二三区在线看| 男人的天堂av一二三区| 九九热爱视频精品视频| 精品国产免费一区二区三区香蕉| 1024你懂的国产精品| 天堂va欧美ⅴa亚洲va在线| 中文字幕人妻色偷偷久久| 国产精品无码午夜福利| 国产不卡av一区二区| 国内外精品激情刺激在线| 伊人久久精品无码麻豆一区| 久久综合色之久久综合色| 欧美寡妇xxxx黑人猛交| 亚洲国产成人自拍视频网| 人妻无码| 精品国产午夜福利在线观看| 熟女精品色一区二区三区| 久久精品免费无码区| 亚洲综合在线日韩av| 亚洲性日韩精品一区二区| 阜宁县|