首页 > 学院 > 开发设计 > 正文

Prism4学习笔记(七):State-Based Navigation QuickStart

2019-11-11 05:01:05
字体:
来源:转载
供稿:网友

 本节学习了Navigation的一些基本知识,觉得这节比较难。这里讲学习和理解点的东西记录下来。觉得本节应该弄清楚的问题的关键词

  (1)CallMethodAction用于事件和行为的绑定。

(2)InteractionRequest<T> 在交互请求时协调ViewModel和View

(3)Notification用于交互式单向通知用户,所以ViewModel不能预测用户对Notification中Title和Content的更改

(4)学会自定义行为和操作

(一)在ChatView.xaml,代码如下

View Code复制代码<Grid Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions><!--Send Message按钮行为 在View中直接调用方法(InvokeCommandAction)使用CallMethodAction实现动作响应事件或者触发器,有两种方式获取ViewModel的响应在松散耦合的风格中。(1)你可以用Command来时实现操作(2)你可用行为附加到元素上(附加属性机制或使用Blend SDK中behavior基本类)Interaction.Triggers和Interaction.Behaviors.行为能与事件挂钩CallMethodAction一般用到下面的3个属性(1)TargetObject(2)MethodName(3)IsEnabled PRism中 DelegateCommandBlend SDK中ActonCommand --><Button x:Name="SendMessageButton" Grid.Column="0" Grid.Row="0" Margin="4" VerticalAlignment="Center"AutomationProperties.AutomationId="SendMessageButton"><i:Interaction.Triggers><i:EventTrigger EventName="Click" ><ei:CallMethodAction TargetObject="{Binding DataContext, ElementName=userControl}"MethodName="SendMessage"/></i:EventTrigger></i:Interaction.Triggers>Send Message</Button><GuidanceTools:InfoTipToggleButton VerticalAlignment="Center"Grid.Column="1" Grid.Row="0" Margin="4"><StackPanel MaxWidth="400"><TextBlock TextWrapping="Wrap">This button executes the SendMessage method on the view model,and is only enabled when no other message is being sent. Executing the method causes a child window to be opened to capture the message to send. Accepting the message causes the view modelto send the message to the chat service, which in turnscauses an update on the view model that is represented by showinga progress bar until a confirmation that the message has been sentis issued by the chat service.</TextBlock></StackPanel></GuidanceTools:InfoTipToggleButton><Button Grid.Column="0" Grid.Row="1" Margin="4" Command="{Binding ShowDetailsCommand}" VerticalAlignment="Center"><Button.CommandParameter><sys:Boolean>False</sys:Boolean></Button.CommandParameter>Go Back</Button><GuidanceTools:InfoTipToggleButton VerticalAlignment="Center"Grid.Column="1" Grid.Row="1" Margin="4"><StackPanel MaxWidth="400"><TextBlock TextWrapping="Wrap">This button uses the ShowDetailsCommand, which is only availablewhen a contact has been selected. Executing the command setsone of the 'ShowDetails' and 'ShowContacts' visual states.Transitions to this state are implemented with a flip visual effect.</TextBlock><TextBlock TextWrapping="Wrap">Visual state transitions for the detail visualization mode are triggered by changes in the view model.</TextBlock></StackPanel></GuidanceTools:InfoTipToggleButton ></Grid>复制代码

(二)在ChatViewModel.cs

复制代码ublic class ChatViewModel : ViewModel{private readonly IChatService chatService;//InteractionRequest<T> 在交互请求时协调ViewModel和View//(1)Raise方法允许ViewModel初始化交互和指定一个对象上下文(类型为T),并且回调方法在交互完成后被调用// 上下文对象允许ViewModel传递数据和状态到View上在用交互期间//(2)如果回调方法被指定,上下文对象将被传递回ViewModel,this允许交互期间用户的任何改变都可以回传到ViewModelprivate readonly InteractionRequest<SendMessageViewModel> sendMessageRequest;private readonly InteractionRequest<ReceivedMessage> showReceivedMessageRequest;private readonly ObservableCollection<Contact> contacts;private readonly PagedCollectionView contactsView;private readonly ShowDetailsCommandImplementation showDetailsCommand;private bool showDetails;private bool sendingMessage;public ChatViewModel(IChatService chatService){this.contacts = new ObservableCollection<Contact>();this.contactsView = new PagedCollectionView(this.contacts);this.sendMessageRequest = new InteractionRequest<SendMessageViewModel>();this.showReceivedMessageRequest = new InteractionRequest<ReceivedMessage>();this.showDetailsCommand = new ShowDetailsCommandImplementation(this);this.contactsView.CurrentChanged += this.OnCurrentContactChanged;this.chatService = chatService;this.chatService.Connected = true;this.chatService.ConnectionStatusChanged += (s, e) => this.RaisePropertyChanged(() => this.ConnectionStatus);this.chatService.MessageReceived += this.OnMessageReceived;this.chatService.GetContacts(result =>{if (result.Error == null){foreach (var item in result.Result){this.contacts.Add(item);}}});}public ObservableCollection<Contact> Contacts{get { return this.contacts; }}public ICollectionView ContactsView{get { return this.contactsView; }}public IInteractionRequest SendMessageRequest{get { return this.sendMessageRequest; }}public IInteractionRequest ShowReceivedMessageRequest{get { return this.showReceivedMessageRequest; }}public string ConnectionStatus{get{return this.chatService.Connected ? "Available" : "Unavailable";}set{this.chatService.Connected = value == "Available";}}public Contact CurrentContact{get{return this.contactsView.CurrentItem as Contact;}}public bool ShowDetails{get{return this.showDetails;}set{if (this.showDetails != value){this.showDetails = value;this.RaisePropertyChanged(() => this.ShowDetails);}}}public bool SendingMessage{get{return this.sendingMessage;}private set{if (this.sendingMessage != value){this.sendingMessage = value;this.RaisePropertyChanged(() => this.SendingMessage);}}}public ICommand ShowDetailsCommand{get { return this.showDetailsCommand; }}//SendMessage绑定到Send Message按钮public void SendMessage(){var contact = this.CurrentContact;this.sendMessageRequest.Raise(new SendMessageViewModel(contact, this),sendMessage =>{if (sendMessage.Result.HasValue && sendMessage.Result.Value){this.SendingMessage = true;this.chatService.SendMessage(contact,sendMessage.Message,result =>{this.SendingMessage = false;});}});}private void OnCurrentContactChanged(object sender, EventArgs a){this.RaisePropertyChanged(() => this.CurrentContact);this.showDetailsCommand.RaiseCanExecuteChanged();}private void OnMessageReceived(object sender, MessageReceivedEventArgs a){this.showReceivedMessageRequest.Raise(a.Message);}#region 类ShowDetailsCommandImplementationprivate class ShowDetailsCommandImplementation : ICommand{private readonly ChatViewModel owner;public ShowDetailsCommandImplementation(ChatViewModel owner){this.owner = owner;}public event EventHandler CanExecuteChanged;public bool CanExecute(object parameter){return this.owner.ContactsView.CurrentItem != null;}public void Execute(object parameter){this.owner.ShowDetails = (bool)parameter;}public void RaiseCanExecuteChanged(){var handler = this.CanExecuteChanged;if (handler != null){handler(this, EventArgs.Empty);}}}#endregion}复制代码

(三)在SendMessageModel.cs

复制代码//Notification介绍//(1)Notification类支持普通交互请求服务//(2)Notification类是作为对象上下文最基本得类//(3)用于交互请求时通知用户。//(4)提供了两个属性Title和Content被显示给用户//(5)通常,通知是单向的,所以Notification在交互期间不能预测用户将会改变Title和Content//(6)Confirmation类继承自Notification类和添加了第三个属性Cofirmed--被用于表示用户已经确认或者拒绝操作//(7)Confirmation类用于实现MessageBox样式交互,当用户想获取yes/no相应从呼呼那里。//(8)你自定一个上下文类继承自Notification封装成无论是支持交互的数据还是状态你需要public class SendMessageViewModel : Notification, INotifyPropertyChanged{private readonly Contact contact;private readonly ChatViewModel parent;private bool? result;private string message;public SendMessageViewModel(Contact contact, ChatViewModel parent){this.contact = contact;this.parent = parent;}public Contact Contact{get { return this.contact; }}public string Message{get{return this.message;}set{if (value != this.message){this.message = value; RaisePropertyChanged(() => this.Message);}}}public bool? Result{get{return this.result;}set{if (value != this.result){this.result = value;RaisePropertyChanged(() => this.Result);}}}public event PropertyChangedEventHandler PropertyChanged;protected virtual void OnPropertyChanged(string propertyName){PropertyChangedEventHandler handler = PropertyChanged;if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));}private void RaisePropertyChanged<T>(Expression<Func<T>> lambda){var name = PropertySupport.ExtractPropertyName<T>(lambda);OnPropertyChanged(name);}}复制代码

(四)在Infrastructure文件夹下的ViewModel.cs代码如下:

复制代码/// <summary>/// Base class for view models./// </summary>/// <remarks>/// This class provides basic support for implementing the <see cref="INotifyPropertyChanged"/> interface./// </remarks>public class ViewModel : INotifyPropertyChanged{/// <summary>/// Raised when a property on this object has a new value./// </summary>public event PropertyChangedEventHandler PropertyChanged;/// <summary>/// Raises this object's PropertyChanged event./// </summary>/// <typeparam name="T">The type of the property that has a new value</typeparam>/// <param name="propertyExpresssion">A Lambda expression representing the property that has a new value.</param>protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpresssion){var propertyName = PropertySupport.ExtractPropertyName(propertyExpresssion);this.RaisePropertyChanged(propertyName);}/// <summary>/// Raises this object's PropertyChanged event./// </summary>/// <param name="propertyName">The property that has a new value.</param>protected virtual void RaisePropertyChanged(string propertyName){var handler = this.PropertyChanged;if (handler != null){handler(this, new PropertyChangedEventArgs(propertyName));}}protected void ExecuteOnUIThread(Action action){var dispatcher = Deployment.Current.Dispatcher;if (dispatcher.Checkaccess()){action();}else{dispatcher.BeginInvoke(action);}}}复制代码

(五)在Infrastructure文件夹下的Behavior文件夹下,有自己定义行为(Behavior)和操作(Action)

(1) RelocatePopupBehavior行为类

复制代码//该自定义行为:确保弹出串口定位在父视图的右下角/// <summary>/// Behavior that ensures a popup is located at the bottom-right corner of its parent./// </summary>public class RelocatePopupBehavior : Behavior<Popup>{protected override void OnAttached(){base.OnAttached();this.AssociatedObject.Opened += this.OnPopupOpened;this.AssociatedObject.Closed += this.OnPopupClosed;}protected override void OnDetaching(){this.AssociatedObject.Opened -= this.OnPopupOpened;this.AssociatedObject.Closed -= this.OnPopupClosed;this.DetachSizeChangeHandlers();base.OnDetaching();}private void OnPopupOpened(object sender, EventArgs e){this.UpdatePopupOffsets();this.AttachSizeChangeHandlers();}private void OnPopupClosed(object sender, EventArgs e){this.DetachSizeChangeHandlers();}private void AttachSizeChangeHandlers(){var child = this.AssociatedObject.Child as FrameworkElement;if (child != null){child.SizeChanged += this.OnChildSizeChanged;}var parent = this.AssociatedObject.Parent as FrameworkElement;if (parent != null){parent.SizeChanged += this.OnParentSizeChanged;}}private void DetachSizeChangeHandlers(){var child = this.AssociatedObject.Child as FrameworkElement;if (child != null){child.SizeChanged -= this.OnChildSizeChanged;}var parent = this.AssociatedObject.Parent as FrameworkElement;if (parent != null){parent.SizeChanged -= this.OnParentSizeChanged;}}private void OnChildSizeChanged(object sender, EventArgs e){this.UpdatePopupOffsets();}private void OnParentSizeChanged(object sender, EventArgs e){this.UpdatePopupOffsets();}private void UpdatePopupOffsets(){if (this.AssociatedObject != null){var child = this.AssociatedObject.Child as FrameworkElement;var parent = this.AssociatedObject.Parent as FrameworkElement;if (child != null && parent != null){var anchor = new Point(parent.ActualWidth, parent.ActualHeight);this.AssociatedObject.HorizontalOffset = anchor.X - child.ActualWidth;this.AssociatedObject.VerticalOffset = anchor.Y - child.ActualHeight;}}}}复制代码

(2) ShowNotificationAction.cs定义了行为

复制代码/行为是功能单元容器。有两种类型的行为//(1)不具有调用概念的行为,以附加的方式添加到对象上//(2)触发器和动作更接近调用模型//你可以重复利用事件的句柄或者粗发起到UI上。namespace StateBasedNavigation.Infrastructure.Behaviors{//这个自定义行为允许ViewModel推一个通知到目标元素UI上,通过用户接受在在右下角处 public class ShowNotificationAction : TargetedTriggerAction<FrameworkElement>{//注册依赖属性NotificationTimeoutPropertypublic static readonly DependencyProperty NotificationTimeoutProperty =DependencyProperty.Register("NotificationTimeout", typeof(TimeSpan), typeof(ShowNotificationAction), new PropertyMetadata(newTimeSpan(0, 0, 5)));private ObservableCollection<object> notifications;public ShowNotificationAction(){ this.notifications = new ObservableCollection<object>();}public TimeSpan NotificationTimeout{get { return (TimeSpan)GetValue(NotificationTimeoutProperty); }set { SetValue(NotificationTimeoutProperty, value); }}protected override void OnTargetChanged(FrameworkElement oldTarget, FrameworkElement newTarget){base.OnTargetChanged(oldTarget, newTarget);if (oldTarget != null){this.Target.ClearValue(FrameworkElement.DataContextProperty);}if (newTarget != null){this.Target.DataContext = this.notifications;}}protected override void Invoke(object parameter){var args = parameter as InteractionRequestedEventArgs;if (args == null){return;}var notification = args.Context;this.notifications.Insert(0, notification);var timer = new DispatcherTimer { Interval = this.NotificationTimeout };EventHandler timerCallback = null;timerCallback =(o, e) =>{timer.Stop();timer.Tick -= timerCallback;this.notifications.Remove(notification);};timer.Tick += timerCallback;timer.Start();args.Callback();}}}复制代码

(七 )项目组织结构及运行截图

    


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表