上一篇了解了简单的Action特性,这篇我们关注Action其它的一些使用场景。
前面的例子是求一个数的平方根,因为我们这里没有对输入进行任何处理,所以当我们输入一个非正数时,Sqrt函数会返回NaN
一般而言,我们可以通过抛出异常的方式进行处理,但是更为友好的方式是在用户输入数值时就进行处理,这里我们就用到了Caliburn的Filter特性,其包含
了PreView,Rescue,以及AsyncAction这3个过滤器,也可以自己定义,下面我们在前面的例子基础上了解其过虑器的使用。
在Extraction类中添加一个PreView过滤器,看看修改过后的类
using Caliburn.PresentationFramework.Filters;
public class Extraction{[Preview("IsValueCanExtrace",AffectsTriggers=true)]public double Extrace(double param){return Math.Sqrt(param);
}public bool IsValueCanExtrace(double param){return param >= 0;
}}
这里我们定义了一个IsValueCanExtrace()验证输入参数的有效性,PreView过滤器指定了IsValueCanExtrace方法,其将在Extrace()执行前执行,
AffectsTriggers默认值是True,使用True值可以使得这个过滤器影响到UI上控件的状态,我们看看效果图:
当我们在文本框中输入-7时,Button会自动被禁用,输入7时,验证可以通过,这种方式比抛出异常进行处理更为友好。
在Caliburn中,关于过滤器有一个命名规范,如果你使用Can{MethodName}这种命名方式,它将自动的将过滤器对应到该方法中,所以上面的代
码我们可以写成这种方式:
public class Extraction{public double Extrace(double param){return Math.Sqrt(param);
}public bool CanExtrace(double param){return param >= 0;
}}
运行之后两者的效果是一样的,也可以把Can{MethodName}定义成属性,它也会被自动触发,所以只有你的命名是另外的方式时才需要用PreView特
性。关于过滤器的功能还有很多,不过这个足以应付一般的操作了,现在我们再来看一看Action的异步操作。
异步操作则用到了AsyncAction过滤器,我们进一步修改代码
using Caliburn.PresentationFramework.Actions;
public class Extraction{[AsyncAction(BlockInteraction = true)]
public double Extrace(double param){System.Threading.Thread.Sleep(2000);return Math.Sqrt(param);
}public bool CanExtrace(double param){return param >= 0;
}}
当Button处于异步操作时,其状态将变为Disable,UI的其它部分仍然可以进行响应,当操作完成时,会将结果输出在文本框中,同时Button状态
会自动变为Enable,这里就是AsyncAction所起的作用,当方法被其修饰时,即表示需要在后台执行,同时将BlockInteraction设为True时,可以控
制源(这里即Button)在异步操作完成前被禁用。
我们也可以在异步方法中指定回调函数,看下其实现:
[AsyncAction(Callback = "ExtraceComplate",BlockInteraction = true)]public double Extrace(double param){System.Threading.Thread.Sleep(2000);return Math.Sqrt(param);
}public double ExtraceComplate(double result){return result * 1000;
}
代码中在AsyncAction特性中指定了一个Callback函数,Caliburn会自动在UI线程上将异步执行的结果作为参数传递给Callback函数,如果回调函数有
关于Rescue过滤器就不细说明了,其可以通过修饰类或方法指向一个未处理的异常,其实这也是我倾向于使用PreView的原因,最后我们再关注一下依赖行为,依赖行为是在前面的标准行为机制基础上增加的一个特性,它可以让Caliburn知道类的方法的执行需要依赖于哪一个属性,我们通过修改Extraction来理解这句话
public class Extraction:INotifyPropertyChanged{[Dependencies("Param")]
public void Extrace(){Result = Math.Sqrt(Param);}public bool CanExtrace(){return Param>=0;
}public double _prarm;public double Param{get
{return _prarm;
}set {
_prarm = value;
if (PropertyChanged != null){this.PropertyChanged(this, new PropertyChangedEventArgs("Param"));}}}public double _result;public double Result{get
{return _result;
}set {
_result = value;
if (PropertyChanged != null){this.PropertyChanged(this, new PropertyChangedEventArgs("Result"));}}}public event PropertyChangedEventHandler PropertyChanged;
这个时候与我们之前的类结构已经大不相同了,在这种方式下,我们不需要再将参数传给Extrace(),因为ViewModel将通过属性的变化维护其所需要的值,
并通过DependenciesAttribute指定了Extrace()所依赖的属性
现在我们看一看UI:
<TextBox Text="{Binding Param,Mode=TwoWay}" /><TextBox Text="{Binding Result,Mode=TwoWay}"/><Button Content="计算" pf:Message.Attach="Extrace" ></Button>
我们将Param属性绑定到输入框,将Result绑定到结果,这种方式是我们在MVVM中熟悉的绑定方式,运行之后所看的效果和我们前面所做的是一样的,
Action部分功能比较丰富,我想即使只掌握了上面这几点,也是可以应付大多数情况的。
代码下载:DependentAction 环境:VS2010+SL3