【学习笔记】Silverlight框架:Jounce(5)——工作流

按照作者说的,Jounce里的工作流也受到Caliburn的很大启发(Prism里没有类似概念)。

因为还没仔细研究过Caliburn,不知道Caliburn和CM的区别有多大。CM里面的工作流叫做Coroutine,整体使用和里面的Action息息相关。

相对来说来Jounce里工作流的定义和使用就比较简单。

此处涉及的类和接口有:

工作项的接口IWorkflow,定义了执行工作的方法Invoke和工作完成后的回调Invoked。

工作流控制台WorkflowController,定义了2个静态重载方法Begin用于启动工作流,可以传入的参数是IEnumerable<IWorkflow>或者IWorkflow(最终也会转化成IEnumerable<IWorkflow>)。

程序会调用第一个IWorkflow的Invoke方法,在回调Invoked后再调用第二个IWorkflow的Invoke,依次。

然后是几个实现了接口IWorkflow的类,其中

WorkflowAction(可以手动触发Invoked执行);

WorkflowBackgroundWorker(另起线程执行,线程完成后调用Invoked);

WorkflowDelay(传入TimeSpan,设置计时器,在计时完成后调用Invoked);

WorkflowEvent(传入注册事件的委托,在事件触发后调用Invoked);

WorkflowRoutedEvent(和WorkflowEvent类似,路由事件)。

来实际操作下看看,结构:

这次的操作代码都写在MainPage的后台代码中,看下Xaml:

<UserControl x:Class="JounceWorkflow.MainPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable
="d"
d:DesignHeight
="300" d:DesignWidth="400">

<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Button Margin="5" Content="启动"
x:Name
="StartButton"
Click
="StartButton_Click"/>

<Button Margin="5" Content="继续Action"
x:Name
="ContinueActionButton"
Click
="ContinueActionButton_Click"
Visibility
="Collapsed"/>

<Button Margin="5" Content="继续Event"
x:Name
="ContinueEventButton"
Visibility
="Collapsed"/>
</StackPanel>
<ProgressBar Margin="2" Grid.Row="1" x:Name="ProgressBar" Height="20"/>
<TextBox Margin="5" Text="点击启动按钮启动工作流。"
Grid.Row
="2" x:Name="OutTextBox"/>
</Grid>
</UserControl>

后台代码:

    [ExportAsView("MainPage", IsShell = true)]
    public partial class MainPage : UserControl
    {
        private WorkflowAction _workflowAction;

        public MainPage()
        {
            InitializeComponent();
            this.ProgressBar.Maximum = int.MaxValue;
            _workflowAction = new WorkflowAction(
                () =>
                {
                    this.OutInformation("进入 WorkflowAction 执行。");
                    this.OutInformation("点击 继续Action按钮 继续。");
                    this.ContinueActionButton.Visibility = Visibility.Visible;
                });
        }

        //启动工作流。
        private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            WorkflowController.Begin(this.Workflow(), ex => JounceHelper.ExecuteOnUI(() => MessageBox.Show(ex.Message)));
        }

        //提供工作流枚举。
        private IEnumerable<IWorkflow> Workflow()
        {
            this.StartButton.IsEnabled = false;
            this.OutInformation("工作流已启动。");

            this.OutInformation("开始 WorkflowAction。");
            yield return _workflowAction;
            this.OutInformation("完成 WorkflowAction。");

            this.OutInformation("开始 WorkflowBackgroundWorker。");
            yield return new WorkflowBackgroundWorker(
                backgroundWorker =>
                {
                    var mod = (int)Math.Ceiling(int.MaxValue / 100);
                    for (var x = 0; x < int.MaxValue; x++)
                    {
                        if (x % mod == 0)
                            backgroundWorker.ReportProgress(x / mod, x);
                    }
                },
                (backgroundWorker, progressChangedEventArgs) =>
                {
                    this.ProgressBar.Value = (int)progressChangedEventArgs.UserState;
                });
            this.OutInformation("完成 WorkflowBackgroundWorker。");

            this.OutInformation("开始 WorkflowDelay,延迟5秒。");
            yield return new WorkflowDelay(TimeSpan.FromSeconds(5));
            this.OutInformation("完成 WorkflowDelay。");

            this.OutInformation("开始 WorkflowRoutedEvent。");
            yield return new WorkflowRoutedEvent(
                () =>
                {
                    this.OutInformation("进入 WorkflowRoutedEvent 执行。");
                    this.OutInformation("点击 继续Event 按钮继续。");
                    this.ContinueEventButton.Visibility = Visibility.Visible;
                },
                routedEventHandler => this.ContinueEventButton.Click += routedEventHandler,
                routedEventHandler => this.ContinueEventButton.Click -= routedEventHandler,
                routedEventArgs =>
                {
                    this.ContinueEventButton.Visibility = Visibility.Collapsed;
                });
            this.OutInformation("完成 WorkflowRoutedEvent。");

            this.OutInformation("完成整个工作流。");
            this.StartButton.IsEnabled = true;
        }

        private void ContinueActionButton_Click(object sender, RoutedEventArgs e)
        {
            this.ContinueActionButton.Visibility = Visibility.Collapsed;
            _workflowAction.Invoked();
        }

        private void OutInformation(string information)
        {
            this.OutTextBox.Text += "\r\n" + information;
        }
    }

为了便于理解,很多方法都直接用匿名委托来写了,yield这东西平常真的用的很少,这里刚好练练手。

还可以看到,输出方式的多样性,可以直接写在定义工作流的方法里,或者传入参数的Action委托里,或者回调方法里。

本例中的WorkflowAction和WorkflowRoutedEvent虽然都用Button.Click来控制继续执行,但是机制是完全不一样的。

其他的就不解释了。

PS:

1.虽然WorkflowController提供了Public的构造函数,但是并没有提供Public的实例启动方法,因此就算在外部实例了WorkflowController也无法启动工作流执行。这种Public的方法无实际用处的情况还在另外几个类里出现了。

2.可以留意下另起线程执行时,UI线程是否灵活机动。

3.在实际应用中尝试自己实现下IWorkflow接口。

posted @ 2011-07-31 01:14  超时空饭盒  阅读(1205)  评论(0编辑  收藏  举报