0x07交互#
[7.1updated]无变化
这是这个系列的最后一篇了,主要介绍了Prism中为我们提供几种弹窗交互的方式。
Notification通知式#
Prism通过InteractionRequest 来实现弹窗交互,它是一个泛型接口,不同的类型对应不同类型的弹窗方式。
在使用InteractionRequest
的时候需要在,xaml中需要注册一个Trigger:
1 2 3 4 5
| <i:Interaction.Triggers> <prism:InteractionRequestTrigger SourceObject="{Binding NotificationRequest}"> <prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" /> </prism:InteractionRequestTrigger> </i:Interaction.Triggers>
|
Interaction
这里用到了Interaction
,他是i
命名空间里的东西,那么i
是什么呢?
interactivity
这个是微软内置的类库,他提供了一组用户交互的类,比如我们这里用到的EventTrigger
可以用来执行事件触发的操作。
在使用的时候,先引入xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
或者xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
,然后在xaml中使用他:
1 2 3 4 5
| <i:Interaction.Triggers> <i:EventTrigger>
</i:EventTrigger> </i:Interaction.Triggers>
|
而 prism:PopupWindowAction 的 IsModal=True意味着弹框不被关闭的时候,父窗体无法使用。我刚搜索了一下,这个词的翻译竟然“模态”。
模态对话框(Modal Dialogue Box,又叫做模式对话框),是指在用户想要对对话框以外的应用程序进行操作时,必须首先对该对话框进行响应。 如单击【确定】或【取消】按钮等将该对话框关闭。
好,接着,我们在code-behind中声明,使用INotification
类型:
1
| public InteractionRequest<INotification> NotificationRequest { get; set; }
|
在command的回调函数中就可以使用NotificationRequest:
1
| NotificationRequest.Raise(new Notification { Content = "Notification Message", Title = "Notification" }, r => Title = "Notified");
|
最后通过ConfirmationRequest.Raise()
方法来实现调用弹窗,这里将Title
修改为“Notified”。
Confirmation 确认式#
跟Notification的使用方法一样,先注册Trigger:
1 2 3
| <prism:InteractionRequestTrigger SourceObject="{Binding ConfirmationRequest}"> <prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True" /> </prism:InteractionRequestTrigger>
|
然后在使用InteractionRequest的时候使用IConfirmation类型:
1
| public InteractionRequest<IConfirmation> ConfirmationRequest { get; set; }
|
callback:
1 2 3 4
| ConfirmationRequest.Raise(new Confirmation { Title = "Confirmation", Content = "Confirmation Message" }, r => Title = r.Confirmed ? "Confirmed" : "Not Confirmed");
|
原本一直好奇为什么r
能获取confirmation
的confirmed
属性,后来才发现,自学这个东西,急于求成是不行的。
看下prism的 ConfirmationRequest.Raise()方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")] public void Raise(T context, Action<T> callback) { var handler = this.Raised; if (handler != null) { handler(this, new InteractionRequestedEventArgs(context, () => { if(callback != null) callback(context); } )); } }
|
上面的通知和提示窗体,都是内置的,很多时候,我们需要自制一些弹窗来满足更复杂的使用场景,比如我们通过弹窗来传递一些信息,贴心的Prism同样为我们准备了一个接口IInteractionRequestAware
:
1 2 3 4 5 6 7 8 9
|
INotification Notification { get; set; }
Action FinishInteraction { get; set; }
|
蛤蛤,Notification
正是我们需要的东西,再看看他是什么鬼
1 2 3 4 5 6 7 8
|
string Title { get; set; }
object Content { get; set; }
|
原来这个被用来传递的东西,也有标准,需要一个名字和一个内容,内容是object
,也就是,我们可以用他来装下任何东西。
FinishInteraction
用invoke
来关闭交互界面,这个很简单,具体他怎么关闭的暂时不看了。接下来,我们大概有一个思路了:
首先,先定义好我们需要数据载体类实现INotification,再设计一个usercontrole,他的vm实现IInteractionRequestAware
接口,然后在NotificationRequest.Raise
的时候使用usercontrole,美滋滋!!!😆
我们来通过客制化弹窗,实现从一个字符串列表中选择一个字符串,返回给父窗体:
先设计Notification,他并没有直接实现INotification
,而是实现了IConfirmation
,IConfirmation
在INotification
的基础上,添加了一个Confirmed
属性,来获取弹窗返回状态,是布尔型的(布尔型只有两种状态,很多时候,我需要有战斗机一般多的按钮的时候,他就不够用了,到时候得重新设计一个枚举类型的),这里,我们就直接实现IConfirmation
(_为什么先是搞了一个接口呢?当然是为了依赖注入啊!依赖注入很难讲,以前我也看了很多大佬的资料,但是没有懂,后来去问大佬,大佬说,你看懂了吗?我说似懂非懂,他说,那就去看代码吧,慢慢的就懂了。😂_):
1 2 3 4 5 6 7 8 9
| using Prism.Interactivity.InteractionRequest;
namespace UsingPopupWindowAction.Notifications { public interface ICustomNotification : IConfirmation { string SelectedItem { get; set; } } }
|
接着是我们的实现类(一个list(源),一个string(目标))继承 Confirmation
实现我们的接口ICustomNotification
,继承 Confirmation
是因为他继承自Notification
,而Notification
是实现了INotification
的,这样,我们就在我们的类里不用去实现INotification
了,其实也可以不用继承·Confirmation
·,完全可以自己实现ICustomNotification
他所有的接口(话说若干年前我怎么记得接口不可以被继承只能被实现呢?记错了?):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| using Prism.Interactivity.InteractionRequest; using System.Collections.Generic;
namespace UsingPopupWindowAction.Notifications { public class CustomNotification : Confirmation, ICustomNotification { public IList<string> Items { get; private set; }
public string SelectedItem { get; set; }
public CustomNotification() { this.Items = new List<string>(); this.SelectedItem = null;
CreateItems(); }
private void CreateItems() { } } }
|
如果不继承Confirmation
,则需要添加部分实现:
1 2 3 4
| public bool Confirmed { get ; set ; } public string Title { get ; set ; } public object Content { get ; set ; }
|
接下来设计我们的弹窗(一个列表(显示源),两个按钮,一个取消一个提交(获取目标)):
1 2 3 4 5 6 7 8 9 10 11 12
| <TextBlock Margin="10" TextWrapping="Wrap" FontWeight="Bold">Please select an item:</TextBlock> <ListBox SelectionMode="Single" Margin="10,0" Height="100" ItemsSource="{Binding Notification.Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}"></ListBox>
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions>
<Button AutomationProperties.AutomationId="ItemsSelectButton" Grid.Column="0" Margin="10" Command="{Binding SelectItemCommand}">Select Item</Button> <Button AutomationProperties.AutomationId="ItemsCancelButton" Grid.Column="1" Margin="10" Command="{Binding CancelCommand}">Cancel</Button> </Grid>
|
弹窗的ViewModel,实现IInteractionRequestAware
接口,这里设置了一个_notification
来接收我们用来传递的那个类,这很像MVC里的Model,他只是个数据的载体,在每一个命令最后都需要关闭窗体,并且之前对confirmed和我们的SelectedItem进行赋值:
依旧省去了大部分代码,只看与我们有关的部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class ItemSelectionViewModel : BindableBase, IInteractionRequestAware { public string SelectedItem { get; set; } private void CancelInteraction() { _notification.SelectedItem = null; _notification.Confirmed = false; FinishInteraction?.Invoke(); }
private void AcceptSelectedItem() { _notification.SelectedItem = SelectedItem; _notification.Confirmed = true; FinishInteraction?.Invoke(); }
public Action FinishInteraction { get; set; }
private ICustomNotification _notification;
public INotification Notification { get { return _notification; } set { SetProperty(ref _notification, (ICustomNotification)value); } } } }
|
最后就是在Shell里调用这个客制化弹窗啦,跟之前的就一毛一样了,将INotification
或者IConfirmation
替换成我们的ICustomNotification
,然后在new的时候使用CustomNotification
,代码看上去应该是这个样子的:
xaml:
1 2 3 4 5 6 7
| <prism:InteractionRequestTrigger SourceObject="{Binding CustomNotificationRequest}"> <prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True"> <prism:PopupWindowAction.WindowContent> <views:ItemSelectionView /> </prism:PopupWindowAction.WindowContent> </prism:PopupWindowAction> </prism:InteractionRequestTrigger>
|
viewmodel:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public InteractionRequest<ICustomNotification> CustomNotificationRequest { get; set; } public DelegateCommand CustomNotificationCommand { get; set; }
public MainWindowViewModel() { CustomNotificationRequest = new InteractionRequest<ICustomNotification>(); CustomNotificationCommand = new DelegateCommand(RaiseCustomInteraction); } private void RaiseCustomInteraction() { CustomNotificationRequest.Raise(new CustomNotification { Title = "Custom Notification" }, r => { if (r.Confirmed && r.SelectedItem != null) Title = $"User selected: { r.SelectedItem}"; else Title = "User cancelled or didn't select an item"; }); }
|
最后一篇了!我会持续修正之前文章里理解偏颇的地方。谢谢大家!