您的位置:首页 > 其它

Prism应用开发(六)——MVVM高级话题

2016-08-12 09:14 399 查看
一、Commands

Composite Commands

情景:



上述情景中,Submit All Command的逻辑是要调用所有Submit Command的逻辑。

解决方案: Prism中提供了CompositeCommand,这个类持有一组child command,CompositeCommand在执行的时候将会调用每一个child command的Execute方法,可以通过,可以通过RegisterCommand和UnregisterCommand来注册和注销child command。

[csharp]
view plain
copy

print?

commandProxy.SubmitAllOrdersCommand.RegisterCommand(  
orderCompositeViewModel.SubmitCommand );  
commandProxy.CancelAllOrdersCommand.RegisterCommand(  
orderCompositeViewModel.CancelCommand );  



commandProxy.SubmitAllOrdersCommand.RegisterCommand(
orderCompositeViewModel.SubmitCommand );
commandProxy.CancelAllOrdersCommand.RegisterCommand(
orderCompositeViewModel.CancelCommand );


在当前View上执行Command

情景:



在上面的应用中,放大缩小按钮应该只对当前的活动视图(active view)起作用,而对其它视图不起作用。

解决方案: Prism提供了IActiveAware接口,它包含了IsActive属性和IsActiveChanged事件。DelegateCommand实现了这个接口,CompositeCommand下面的构造函数能够使得在执行child command的时候只执行所有的active command。

[csharp]
view plain
copy

print?

public CompositeCommand(bool monitorCommandActivity);  



public CompositeCommand(bool monitorCommandActivity);

集合中的Command

情景:



这个问题的关键是,在每一个Item中点击“Delete”实际上是改变它的parent view中view model的集合,问题的难点在于,每个Item的data context是集合本身的一项,而不是实现了Delete Command的parent view model。

解决方案:

使用ElementName属性指定绑定是相对于它的parent control,而不是相对于data template。

[html]
view plain
copy

print?

<Grid x:Name="root">  
<ListBox ItemsSource="{Binding Path=Items}">  
<ListBox.ItemTemplate>  
<DataTemplate>  
<Button Content="{Binding Path=Name}" Command="{Binding ElementName=root,  
Path=DataContext.DeleteCommand}" />  
</DataTemplate>  
</ListBox.ItemTemplate>  
</ListBox>  
</Grid>  



<Grid x:Name="root">
<ListBox ItemsSource="{Binding Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Path=Name}" Command="{Binding ElementName=root,
Path=DataContext.DeleteCommand}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>


可以使用CommandParameter指明当前应用的item,也可以实现command来获取当前选中的item(通过CollectionView)。

二、交互

在很多时候,应用程序都会通知用户当前状态或者在处理一个请求之前需要用户的确认,在非MVVM模式中,很通用的方式就是在Code-behind文件中使用MessageBox类进行交互,然而在MVVM模式中,这种做法就不合适了,因为这会使得部分view model逻辑放到了view中。

在MVVM模式中,通常有两种方法可以实现这种交互,一种方法是实现一个由view model使用的service来触发用户交互,另一种方法是由view model 触发一个事件来进行交互。

使用Interaction Service

这种方法是使得view model依赖于interaction service进行用户交互,interaction service实现交互的可视化部分。

[csharp]
view plain
copy

print?

var result =  
interactionService.ShowMessageBox(  
"Are you sure you want to cancel this operation?",  
"Confirm",  
MessageBoxButton.OK );  
if (result == MessageBoxResult.Yes)  
{  
CancelRequest();  
}  



var result =
interactionService.ShowMessageBox(
"Are you sure you want to cancel this operation?",
"Confirm",
MessageBoxButton.OK );
if (result == MessageBoxResult.Yes)
{
CancelRequest();
}

使用Interaction Request Object

这种方法是view model将交互请求直接发给view本身,请求对象封装封装请求和回复的所有细节,并且通过event和view通信,view通过behavior绑定到view model提供的request object。

Prism采用这种方式,并且提供了IInteractionRequest接口和InteractionRequest<T>类。

[csharp]
view plain
copy

print?

public interface IInteractionRequest  
{  
event EventHandler<InteractionRequestedEventArgs> Raised;  
}  
public class InteractionRequest<T> : IInteractionRequest  
{  
public event EventHandler<InteractionRequestedEventArgs> Raised;  
public void Raise(T context, Action<T> callback)  
{  
var handler = this.Raised;  
if (handler != null)  
{  
handler(  
this,  
new InteractionRequestedEventArgs(  
context,  
() => callback(context)));  
}  
}  
}  



public interface IInteractionRequest
{
event EventHandler<InteractionRequestedEventArgs> Raised;
}
public class InteractionRequest<T> : IInteractionRequest
{
public event EventHandler<InteractionRequestedEventArgs> Raised;
public void Raise(T context, Action<T> callback)
{
var handler = this.Raised;
if (handler != null)
{
handler(
this,
new InteractionRequestedEventArgs(
context,
() => callback(context)));
}
}
}


Prism同时提供了上下文类,用作交互传递。Notification类是这些类的基类,Confirmation类继承自Notification用于实现类似MessageBox类型的交互请求。

下面的代码显示了view model如何使用InteractionRequest<T>。

[csharp]
view plain
copy

print?

public IInteractionRequest ConfirmCancelInteractionRequest  
{  
get  
{  
return this.confirmCancelInteractionRequest;  
}  
}  
this.confirmCancelInteractionRequest.Raise(  
new Confirmation("Are you sure you wish to cancel?"),  
confirmation =>  
{  
if (confirmation.Confirmed)  
{  
this.NavigateToQuestionnaireList();  
}  
});  
}  



public IInteractionRequest ConfirmCancelInteractionRequest
{
get
{
return this.confirmCancelInteractionRequest;
}
}
this.confirmCancelInteractionRequest.Raise(
new Confirmation("Are you sure you wish to cancel?"),
confirmation =>
{
if (confirmation.Confirmed)
{
this.NavigateToQuestionnaireList();
}
});
}


在view层次,prism提供了InteractionRequestTrigger,这个类能自动连接到IInteractionRequest接口的Raised 事件,

[html]
view plain
copy

print?

<i:Interaction.Triggers>  
<prism:InteractionRequestTrigger  
SourceObject="{Binding ConfirmCancelInteractionRequest}">  
<prism:PopupChildWindowAction  
ContentTemplate="{StaticResource ConfirmWindowTemplate}"/>  
</prism:InteractionRequestTrigger>  
</i:Interaction.Triggers>  
<UserControl.Resources>  
<DataTemplate x:Key="ConfirmWindowTemplate">  
<Grid MinWidth="250" MinHeight="100">  
<TextBlock TextWrapping="Wrap" Grid.Row="0" Text="{Binding}"/>  
</Grid>  
</DataTemplate>  
</UserControl.Resources>  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: