(后续) 使用 Builder 模式让右键菜单的创建更上一层楼
本文最后更新于:11 天前
前言
接上文 (没看的快去看!),我们讨论了如何以最爽的方式创建右键菜单。但后台有小伙伴留言说那么多方法写在窗体里面显得太冗余且无法在其他窗体中调用。如果全部放在实例类里面的话,又要写个 new()
也显得不优雅;放静态类每次都要写类名,太冗长了。所以这期我们用 Builder 设计模式来使它变得更好用。(以 ContextMenu
为例,ContextMenuStrip
请以此类推)
正文
首先,创建 Builder 实例类,名为 ContextMenuBuilder
1 |
|
其次,创建 MenuItem
各方法不变,还是这几个,如下:(为了后面调用时简洁明了,我们可以省略方法名的动词)
1 |
|
关键在于 Build()
方法应该怎么写。首先我们要求在使用 Builder 时,不要显式出现 new()
,那么第一可以确定的是该方法应该为静态方法,即
1 |
|
那么参数应该是什么呢?由于我们的 Builder 是个实例对象,所以在静态方法中调用实例对象中的方法,必须要创建对象实例。但是我们又不能直接在方法里面 var
一个变量等于 new ContextMenuBuilder()
,并且需要 MenuItem
各方法的返回值来拿出对应的菜单项,以便在其他地方控制状态等。所以我们仍要使用 MenuItem[]
数组来作为最终创建 ContextMenu
的原材料。这时就要动动脑筋了,有什么东西可以作为 Build()
方法的参数,并且可以调用的到 ContextMenuBuilder
的实例方法,还要获得 MenuItem[]
输出?
没错,就是 Func<T, TResult>
,先来看看这个方法的签名。
1 |
|
这个委托使用泛型逆变和协变来约束指定类型的行为,人话就是输入 T
(委托的参数),输出 TResult
(委托返回值),这不正是我们想要的吗?所以我们可以这么写:
1 |
|
这表示我们可以传入 ContextMenuBuilder
实例来调用创建 MenuItem
的方法,并且可以获得 MenuItem[]
输出。那这个参数 Builder
怎么使用呢?很简单,委托可以理解为就是一种方法,用它时就像调用方法那样就行,要注意我们需要传入 ContextMenuBuilder
实例,所以 Builder
的参数为 new()
1 |
|
现在我们就通过 Builder
委托拿到了 MenuItem[]
返回值,直接传入 ContextMenu
构造函数,我们就获得了 ContextMenu
实例。(关于 ContextMenuStrip
可以参考上一篇文章,在本文开头跳转)
1 |
|
那我们应该这么使用这个 Build()
方法并且表示 Func<ContextMenuBuilder, MenuItem[]>
呢?这不,Lambda 表达式就来啦,如下:
1 |
|
怎么样,是不是感觉更爽了呢。最终效果如图:
最后献上完整代码!外加 Merge()
方法,这个方法推荐为静态,用法见上一篇文章。
1 |
|
相关链接
- ContextMenuBuilder 在 PlainCEETimer 中的应用:
PlainCEETimer/PlainCEETimer/Modules/ContextMenuBuilder.cs at main · WangHaonie/PlainCEETimer
https://github.com/WangHaonie/PlainCEETimer/blob/main/PlainCEETimer/Modules/ContextMenuBuilder.cs - 上期文章链接:
【C# WinForms】如何以最爽的方式创建 ContextMenu/Strip 右键菜单,不需要设计器_c# contextmenustrip-CSDN博客
https://blog.csdn.net/WHNdeCSDN/article/details/145893969 - 上期文章链接:
如何以最爽的方式创建 ContextMenu/Strip 右键菜单,不需要设计器 | WangHaonie 的博客
https://wanghaonie.github.io/posts/95b4fdac793d/