I have an enum type for user privileges that looks like this:
[Flags]
public enum UserPrivileges : byte
{
None = 0, // 0000 0000
View = 1 << 0, // 0000 0001
Import = 1 << 1, // 0000 0010
Export = 1 << 2, // 0000 0100
Supervisor = View | Import | Export | 1 << 3, // 0000 1111
Admin = Supervisor | 1 << 4 // 0001 1111
}
These values are bound to CheckBoxes in the GUI with a value converter. (I wanted to do this as generic as possible because there are also different privileges [eg EmployeePrivileges])
public class ByteFlagsEnumValueConverter : IValueConverter
{
private byte _targetValue;
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var mask = (byte)parameter;
_targetValue = (byte)value;
return ((mask | _targetValue) == _targetValue);
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
var mask = (byte)parameter;
if ((bool)value)
{
_targetValue |= mask;
}
else
{
// Get next superflag for mask (e.g. 0110 -> 1111)
var b = mask;
b--;
b |= (byte)(b >> 1);
b |= (byte)(b >> 2);
b |= (byte)(b >> 4);
b |= (byte)(b >> 8);
// if you remove a superflag (e.g. 1111) also remove
// everything higher than this flag
if (mask == b || mask == 1)
_targetValue &= (byte)(mask >> 1);
else
// ????????
}
return Enum.Parse(targetType, _targetValue.ToString());
}
}
This works really fine for displaying and adding privileges to the user in the GUI. Also it works for removing Superflags like Supervisor (all flags >=
Supervisor get removed, the other flags don't change).
The problem is when I uncheck Import for example, I want to remove all Superflags (Supervisor, Admin) but would like to keep the other flags (View, Export).
0001 1111 // Admin
0000 0010 // Import
---------
0000 0101 // View | Export
But I haven't come up with an good idea how to accomplish this. Anyboy who has a good solution for this?
If I understand what you want , this should do the job
byte tmp = 1 << 3 | 1 << 4;
byte removeSuperFlagMask = (byte) (~tmp);
byte notSuperflagsMask = 1 << 3 | 1 << 2 | 1 << 1;
if ((valueToRemove & notSuperflagsMask) != 0)
{
newValue = (byte)(removeSuperFlagMask & currentValue & ~valueToRemove);
}
If I understood correctly you want to remove Supervisor
and Admin
so:
UserPrivileges newPrivileges = (UserPrivileges)(((byte)currentPrivileges) & 7;
It will perform like this:
0001 1111 // Admin
0000 0111 // 7 flag
---------
0000 0111 // Remain only where 7 bit was set.
Another example
0000 0011 // View | Import
0000 0111 // 7 flag
---------
0000 0011 // Remain only where 7 bit was set.
By remain I mean that where 7
flag is set it will persist the value in the result (beein 0
or 1
). And where the 7
flag is 0
it will kill the value to 0
.
Mfz brought me on the right way but, it wasn't generic enough for me, so I came up with another solution:
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
var mask = (byte)parameter;
if ((bool)value)
{
_targetValue |= mask;
}
else
{
if (IsSuperFlag(mask) && mask != 1)
_targetValue &= (byte)(mask >> 1);
else
{
// Get all flags from enum type that are no SuperFlags
var flags = Enum.GetValues(targetType).Cast<Enum>();
flags = flags.Where(x => !IsSuperFlag(System.Convert.ToByte(x)));
long nonSuperFlags = 0;
foreach (var flag in flags)
{
nonSuperFlags |= System.Convert.ToByte(flag);
}
// Now only remove everything except the nonSuperFlags
// and then remove the mask
_targetValue &= (byte)(~(_targetValue ^ nonSuperFlags | mask));
}
}
return Enum.Parse(targetType, _targetValue.ToString());
}
private bool IsSuperFlag(byte flag)
{
var b = flag;
b--;
b |= (byte)(b >> 1);
b |= (byte)(b >> 2);
b |= (byte)(b >> 4);
b |= (byte)(b >> 8);
return b == flag;
}
I simply got all non superflags for the enum type and them removed only the superflags and afterwards removed the flag.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.