- A+
所属分类:.NET技术
问题描述
考虑这样一个需求:画布上的对象支持手势操作,手势操作模式有平移、缩放、旋转,对象可以支持一种或多种手势,如何定义这个手势操作模式?
就像文件的权限一样,只读、只写、读写,手势操作也可以这样设计。将手势操作模式定义为简单的枚举类型是不够的,我们需要表示不同模式的组合,需要支持位运算,因此每个枚举成员应该是位字段,即每个枚举成员都应该是2的幂。这样我们就可以使用&、|、^、~
运算符对模式进行逻辑运算。手势操作模式定义如下:
public enum ManipulationModes { None = 0, Translate = 2, Rotate = 4, Scale = 8, }
此时会有一个问题,比如想表示平移旋转时,结果如下:
static void Main() { ManipulationModes mode = ManipulationModes.Translate | ManipulationModes.Rotate; Console.WriteLine(mode); // 输出:6 }
我们期望像文件读写权限一样,打印结果能为Translate, Rotate,但打印输出结果为6,与期望不符。而且6不是ManipulationModes的成员,无法表示ManipulationModes操作模式。
FlagsAttribute
.NET提供了FlagsAttribute特性,表示声明为位字段的枚举类型,我们需要为ManipulationModes添加FlagsAttribute:
[Flags] public enum ManipulationModes { None = 0, Translate = 2, Rotate = 4, Scale = 8, } static void Main() { ManipulationModes mode = ManipulationModes.Translate | ManipulationModes.Rotate; Console.WriteLine(mode); // 输出:Translate, Rotate }
这样输出结果就符合期望值了,经过逻辑运算的值仍然是ManipulationModes的基础值。
逻辑运算
可以使用|
运算符表示组合模式,使用&
运算符判断是否支持特定模式,
// 使用 | 表示组合模式 var operMode = ManipulationModes.Translate | ManipulationModes.Rotate; var transScaleMode = ManipulationModes.Translate | ManipulationModes.Scale; // 使用 & 判断是否支持某种模式 Console.WriteLine($"operMode是否支持平移模式:{(operMode & ManipulationModes.Translate) == ManipulationModes.Translate}"); Console.WriteLine($"operMode是否支持平移、旋转模式:{(operMode & transScaleMode) == transScaleMode}");
WPF ManipulationModes源码
下述代码为WPF ManipulationModes的源码:
[Flags] public enum ManipulationModes { None = 0x0000, TranslateX = 0x0001, TranslateY = 0x0002, Translate = TranslateX | TranslateY, Rotate = 0x0004, Scale = 0x0008, All = Translate | Rotate | Scale, }