Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to control roles/permissions in XAML with enumerators

The problem is that I have permissions and not roles.

I have database driven permissions and I get them for each user via logon in the Silverlight application and fill them into a List. I also have an enumerator for the C# code.

Anyways I do not wish to talk about why I am not using roles etc.

I want to type my permission into XAML elements and set Visibility and IsEnabled on them.

Like this:

<Button IsEnabled="{Binding IsAdmin}" />
like image 828
Rumplin Avatar asked Aug 24 '11 10:08

Rumplin


1 Answers

First the Attached dependency property:

using System;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
//using GalaSoft.MvvmLight; //optional

 namespace SL.Permissions
 {
    public enum EnumPermission : short
    {
        ADMIN = 1,  //Administrator
        EDITOR = 2, //Editor
        USER = 99 //normal user
    }

    public class Permission
    {

        #region private methods

        private static void RecalculateControlVisibility(UIElement control, bool hasPermission)
        {
            if (hasPermission)
                control.Visibility = Visibility.Visible;
            else
                control.Visibility = Visibility.Collapsed;
        }

        private static void RecalculateControlIsEnabled(Control control, bool hasPermission)
        {
            control.IsEnabled = hasPermission;
        }

        #endregion

        #region Visibility

        public static readonly DependencyProperty VisibilityProperty =
            DependencyProperty.RegisterAttached("Visibility", typeof(string), typeof(Permission), new PropertyMetadata(Visibility_Callback));

        private static void Visibility_Callback(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            bool hasPermission = false;

            var uiElement = (UIElement)source;
            var permissions = GetVisibility(uiElement).Split(',');
            EnumPermission permission = new EnumPermission();

            //if using MVVM-light toolkit
            //if (ViewModelBase.IsInDesignModeStatic)
            //{
            //  hasPermission = true;
            //  goto END;
            //}

            //loop trough enumerator
            foreach (var fieldInfo in permission.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
            {
                //loop trough parameters
                foreach (var item in permissions.Where(m => m.ToUpper() == fieldInfo.Name.ToUpper()))
                {
                    permission = (EnumPermission)Enum.Parse(permission.GetType(), fieldInfo.Name, false);
                    //hasPermission = HasUserPermission(permission); //check if this permission is in users permission list
                    hasPermission = true; //TODO: place here your code to check permission of user
                    if (hasPermission) goto END;
                }
            }

            goto END;

        END:
            RecalculateControlVisibility(uiElement, hasPermission);
        }

        public static void SetVisibility(UIElement element, string value)
        {
            element.SetValue(VisibilityProperty, value);
        }

        public static string GetVisibility(UIElement element)
        {
            return (string)element.GetValue(VisibilityProperty);
        }

        #endregion

        #region IsEnabled

        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached("IsEnabled", typeof(string), typeof(Permission), new PropertyMetadata(IsEnabled_Callback));

        private static void IsEnabled_Callback(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            bool hasPermission = false;

            var uiElement = (Control)source;
            var permissions = GetIsEnabled(uiElement).Split(',');
            EnumPermission permission = new EnumPermission();

            //if using MVVM-light toolkit
            //if (ViewModelBase.IsInDesignModeStatic)
            //{
            //  hasPermission = true;
            //  goto END;
            //}

            //loop trough enumerator
            foreach (var fieldInfo in permission.GetType().GetFields(BindingFlags.Static | BindingFlags.Public))
            {
                //loop trough parameters
                foreach (var item in permissions.Where(m => m.ToUpper() == fieldInfo.Name.ToUpper()))
                {
                    permission = (EnumPermission)Enum.Parse(permission.GetType(), fieldInfo.Name, false);
                    //hasPermission = HasUserPermission(permission); //check if this permission is in users permission list
                    hasPermission = true; //TODO: place here your code to check permission of user
                    if (hasPermission) goto END;
                }
            }

            goto END;

        END:
            RecalculateControlIsEnabled(uiElement, hasPermission);
        }

        public static void SetIsEnabled(UIElement element, string value)
        {
            element.SetValue(IsEnabledProperty, value);
        }

        public static string GetIsEnabled(UIElement element)
        {
            return (string)element.GetValue(IsEnabledProperty);
        }

        #endregion
    }
}

The XAML namespace code:

 xmlns:permissions="clr-namespace:SL.Permissions"

The button in XAML:

<Button Content="Save" permissions:Permission.IsEnabled="ADMIN,EDITOR" Command={Binding SaveClickCommand} />

So this button will be enabled only for users with ADMIN or EDITOR permissions

<Button Content="Save" permissions:Permission.Visibility="ADMIN" Command={Binding SaveClickCommand} />

This button will be visible only for user with ADMIN permissions

Of course you are not limited to use this only with buttons.

I am open for any code optimization comments or comments in general about this solution.

TODO: you will have to implement your own method to check if the user has permissions

I did that with my method hasPermission = HasUserPermission(permission); which looks up the enumrable permission in the List of permissions I get for the user via logon.

What I miss: The perfect solution for this would be intellisense for all the permissions in XAML, but since I want to set more than one permission it's kind of useless.

If you want to use only one permission and want intellisense to show you the permissions you can use, just change the attached dependency property to this (example for Visibility, you'll have to do the same for IsEnabled):

    public static readonly DependencyProperty VisibilityProperty = 
        DependencyProperty.RegisterAttached("Visibility", typeof(EnumPermission), typeof(Permission), new PropertyMetadata(Visibility_Callback));

I have set the second parameter (Type propertyType) to EnumPermission instead of string, that will enable intellisense in XAML to show you permissions from your enumerator.

like image 193
Rumplin Avatar answered Sep 25 '22 00:09

Rumplin