一步一步学WF系列(九)——改善模拟投票项目
1. 摘要
还记得我们在《一步一步学WF系列(六)——工作流模拟投票项目》中的那个程序么?在那篇文章中,我们用工作流模拟了一个简单的投票项目。
在本文中,我们会继续来改善这个投票项目。
2. 目的
在上文中,我们的投票项目是无限期的,但是我们考虑实际情况,比如一个最受欢迎歌手的投票,要有时间期限的,比如是投票期限是一个月等等。
在我们本文中就要为我们的投票设立一个投票期限。
(注:由于我们文章的目的不是做项目,而是为大家讲解活动的使用方式,所以有些地方是演示目的,实际不会这么使用控件)
3. Delay活动
Delay是事件类型的活动。正如我们从活动名字表面看到的一样,Delay活动的意思是延迟,也就是说让我们活动延迟一定时间。
追究Delay的本质,Delay就是当启动工作流实例时,去异步监听,然后自动触发。
让我们看下Delay活动的相关事件,他一个重要的属性就是TimeoutDuration,他设定了一个超时时间,当超时后便自动触发活动。
该活动常常作为其他事件类型的补充,当工作流没有被外界触发时,便认为该活动超时,这时便触发Delay时间。
也许大家听了这么多有些迷糊,等会看例子我想大家会明白这个活动的意思。
4. EventHandlingScope活动
EventHandlingScope有一个主活动,在主活动执行前,他会一直去监听其他的活动,并且执行其他活动。
主活动是放在默认的视图中,而其他的活动是放在事件处理视图内。
另外,补充一句,事件视图内的活动都是由EventDriven容器构成的。
让我们来一步一步去改善我们的投票项目。
5. 项目分析
我们假设这个投票项目的有效时间是一分钟。
我们要在应用程序端去触发工作流的投票相关事件。
6. 建立实体类
我们需要建立一个投票信息的实体类,类内的属性包括GUID以及客户端为某一选项所投的票数。
namespace Model { [Serializable] public class VoteInfo:ExternalDataEventArgs { private Guid guid; private int count; public VoteInfo(Guid guid, int count) : base(guid) { this.count = count; } public Guid GUID { get { return guid; } set { guid = value; } } public int Count { get { return count; } set { count = value; } } } }
7. 约定接口
我们需要约定一个接口,让应用程序端投票时去触发工作流端的相关时间,我们需要向工作流端传入投入的票数。
namespace Interface { [ExternalDataExchange] public interface IFavorate { event EventHandler<ExternalDataEventArgs> LoveZidane; event EventHandler<ExternalDataEventArgs> LoveBeckham; event EventHandler<ExternalDataEventArgs> LoveRonaldo; event EventHandler<ExternalDataEventArgs> LoveKaka; } }补充句,实际项目中,我们肯定不会这么做,这里是为了更好地解释活动。
8. 完成工作流
这是我们的默认视图:
接下来,我们在事件处理视图端,拖入四个EventDriven容器,在每一个容器中拖入一个HandlerExternal事件,让每一个选项对应一个活动。
然后分别去这样设置,我在这里只举个例子:
然后我们为每一个球星在工作流中都设置一个默认的投票数,当每一个事件触发时,便去修改这个投票数。
工作流完整代码如下:
public sealed partial class Workflow1 : SequentialWorkflowActivity { private int ZidaneCount = 0; private int BeckhamCount = 0; private int RonaldoCount = 0; private int KakaCount = 0; public Workflow1() { InitializeComponent(); } private void handleExternalEventActivity1_Invoked(object sender, ExternalDataEventArgs e) { VoteInfo vote = e as VoteInfo; if (vote != null) { ZidaneCount += vote.Count; } } private void handleExternalEventActivity2_Invoked(object sender, ExternalDataEventArgs e) { VoteInfo vote = e as VoteInfo; if (vote != null) { BeckhamCount += vote.Count; } } private void handleExternalEventActivity3_Invoked(object sender, ExternalDataEventArgs e) { VoteInfo vote = e as VoteInfo; if (vote != null) { RonaldoCount += vote.Count; } } private void handleExternalEventActivity4_Invoked(object sender, ExternalDataEventArgs e) { VoteInfo vote = e as VoteInfo; if (vote != null) { KakaCount += vote.Count; } } private void codeActivity1_ExecuteCode(object sender, EventArgs e) { if (ZidaneCount + BeckhamCount + RonaldoCount + KakaCount == 0) { MessageBox.Show("没有人投票"); } else { string result = "Zidane有 " + ZidaneCount + " 票\n"; result += "Beckham有 " + BeckhamCount + " 票\n"; result += "Ronaldo有 " + RonaldoCount + " 票\n"; result += "Kaka有 " + KakaCount + " 票\n"; MessageBox.Show(result); } } }9. 完成客户端
我们来设计一个模拟的客户端:
当用户点击投票时便触发对应的事件,代码如下:
public partial class Form1 : Form,IFavorate { private WorkflowRuntime runtime; private ExternalDataExchangeService service; private WorkflowInstance instance; public Form1() { InitializeComponent(); WorkflowRuntime runtime = new WorkflowRuntime(); service = new ExternalDataExchangeService(); runtime.AddService(service); service.AddService(this); runtime.StartRuntime(); instance = runtime.CreateWorkflow(typeof(WorkflowConsoleApplication10.Workflow1)); instance.Start(); } private void button1_Click(object sender, EventArgs e) { int count; bool temp = Int32.TryParse(this.textBox1.Text, out count); if (temp) { if (this.radioButton1.Checked) { LoveZidane(null, new VoteInfo(instance.InstanceId, count)); } if (this.radioButton2.Checked) { LoveBeckham(null, new VoteInfo(instance.InstanceId, count)); } if (this.radioButton3.Checked) { LoveRonaldo(null, new VoteInfo(instance.InstanceId, count)); } if (this.radioButton4.Checked) { LoveKaka(null, new VoteInfo(instance.InstanceId, count)); } } } #region IFavorate 成员 public event EventHandler<ExternalDataEventArgs> LoveZidane; public event EventHandler<ExternalDataEventArgs> LoveBeckham; public event EventHandler<ExternalDataEventArgs> LoveRonaldo; public event EventHandler<ExternalDataEventArgs> LoveKaka; #endregion }10. 测试结果:
11. 结语
没什么好总结的了,还是希望回去多加练习熟悉。
另外,说句废话,正式向公司提交了辞呈,目前正在找工作,希望各位多多帮忙。谢谢。
下面是我的上面项目的源码,和我的简历,如果各位可以,麻烦帮小弟向HR递份简历。
谢谢大家了。
12. 资料下载
项目源码:改善投票项目
个人简历:个人简历
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!