这里我们会用CM的 IResult接口
我们先定义个ResultBase,后面每个任务都继承ResultBase
新建一个Results文件夹
using Caliburn.Micro; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace cm1.Results { public abstract class ResultBase : IResult { public abstract void Execute(CoroutineExecutionContext context); public event EventHandler<ResultCompletionEventArgs> Completed = delegate { }; protected virtual void OnCompleted() { OnCompleted(new ResultCompletionEventArgs()); } protected virtual void OnError(Exception error) { OnCompleted(new ResultCompletionEventArgs { Error = error }); } protected virtual void OnCancelled() { OnCompleted(new ResultCompletionEventArgs { WasCancelled = true }); } protected virtual void OnCompleted(ResultCompletionEventArgs e) { Caliburn.Micro.Execute.OnUIThread(() => Completed(this, e)); } } } }
这里有个很常用的类Execute,用于在非UI线程 处理业务时候,然后切换到界面线程去执行指定Action的,还有判断是不是在开发模式还是运行模式InDesignMode
CM中提供了一个实现了IResult的TaskResult方便您使用,顺便提供了TaskExtensions可以把Task转为IResult
新建一个VisualStateResult用于切换一个UI过渡VisualState
public class VisualStateResult : ResultBase { public VisualStateResult(string stateName, bool useTransitions = true) { StateName = stateName; UseTransitions = useTransitions; } public string StateName { get; } public bool UseTransitions { get; } public override void Execute(CoroutineExecutionContext context) { if (!(context.View is FrameworkElement)) throw new InvalidOperationException("View must be a FrameworkElement to use VisualStateResult"); var view = (FrameworkElement)context.View; var success = VisualStateManager.GoToElementState(view, StateName, UseTransitions); OnCompleted(); } }
新建一个MessageDialogResult 用于弹窗提示
public class MessageDialogResult : ResultBase { private readonly string content; private readonly string title; public MessageDialogResult(string content, string title) { this.content = content; this.title = title; } public override void Execute(CoroutineExecutionContext context) { MessageBox.Show(content, title, MessageBoxButton.OK); OnCompleted(); } }
新建 CoroutineViewModel 使用这些IResult,CM的CoroutineExecutionContext会传递执行上一个的执行的情况
using System.Collections.Generic; using Caliburn.Micro; using cm1.Results; namespace cm1.ViewModels { public class CoroutineViewModel : Screen { public IEnumerable<IResult> Execute() { yield return new VisualStateResult("加载中"); yield return TaskHelper.Delay(2000).AsResult(); yield return new VisualStateResult("加载完成"); yield return new MessageDialogResult("来自IResult的消息的弹窗", "IResult Coroutines"); } } }
CoroutineView.xaml
<Page x:Class="cm1.Views.CoroutineView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Title="CoroutineView"> <StackPanel> <ProgressBar x:Name="LoadingBar" Minimum="0" Maximum="100" IsIndeterminate="True" Height="20" Visibility="Hidden" /> <Button x:Name="Execute" Content="Execute Coroutine" Margin="40,20"/> </StackPanel> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="LoadingStateGroup"> <VisualState x:Name="Loading"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LoadingBar" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="LoadingComplete"/> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </Page>
Page有个LoadingStateGroup的状态组,有2个状态,Loading 显示进度条,LoadingComplete状态
打开Bootstrapper.cs 修改
.PerRequest<CoroutineViewModel>()
protected override void Configure() { container = new SimpleContainer(); container.Instance(container); container .Singleton<IWindowManager, WindowManager>() .Singleton<IEventAggregator, EventAggregator>(); container .PerRequest<ShellViewModel>() .PerRequest<MenuViewModel>() .PerRequest<BindingsViewModel>() .PerRequest<ActionsViewModel>().PerRequest<CoroutineViewModel>(); }
打开MenuViewModel.cs添加菜单
Features = new BindableCollection<FeatureViewModel> { new FeatureViewModel("Binding Conventions", "Binding view model properties to your view.", typeof(BindingsViewModel)), new FeatureViewModel("Action Conventions", "Wiring view events to view model methods.", typeof(ActionsViewModel)), new FeatureViewModel("Coroutines", "Using IEnumerable<IResult>", typeof(CoroutineViewModel)), };
运行项目
效果
我们设置断点,观看CoroutineExecutionContext
传递过来了 单击的是按钮,哪个viewmodel和对应的view
这里IResult 的 添加顺序,决定了执行顺序,然后会通过CoroutineExecutionContext 传递
本文由 安徽 合肥 杨洋 1991年的 英文名AY
本文由 安徽 合肥 杨洋 1991年的 英文名AY
本文代码下载:Download
net framework 类库 | net5 中的替代类库 |
Microsoft.Expression.Interactions System.Windows.Interactivity | Microsoft.Xaml.Behaviors.Wpf |
其他Ay准备升级到net5的纯xaml库
【ay wpf markup】AY XAML应该这样玩【1/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩【2/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-写个计算器【3/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-for循环【4/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-ChangedHandler【5/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-ResourceCollection和ScriptHandler【6/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-ResourceObject【7/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-ScriptHandler组合,也是最常用的【8/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-语法集合【9/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-Tower of Hanoi【10/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-写个简单的移动【11/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-写个复杂的绘图【12/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-写个复杂的颜色环【13/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-获得焦点全选【14/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-把Additional.Operations当资源【15/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-给ListView创建数据【16/18】-WPF-aaronyang技术分享 (ayjs.net)
【ay wpf markup】AY XAML应该这样玩-和后台ViewModel交互,操作方法【17/18】-WPF-aaronyang技术分享 (ayjs.net)
默认代码模板
Window
<Window x:Class="Features.CrossPlatform.Views.ShellView" 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" xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro.Platform" mc:Ignorable="d" Title="ShellView" Height="450" Width="800"> <Grid> </Grid> </Window>
Page
<Page x:Class="Features.CrossPlatform.Views.MenuView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Title=""> <Grid> </Grid> </Page>
UserControl
<UserControl x:Class="cm1.Views.FeatureView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro.Platform" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid> </Grid> </UserControl>