标签:style blog class code c java
Navigation可以很方便的在页面间进行切换,但是在MVVM模式下,使用Naviation会有一个问题,切换的逻辑需要在ViewModel层完成,但是Navigation需要知道页面的实例或者Uri才能进行切换,那我们如何在ViewModel与UI分离的情况下,用Navigation完成页面的切换呢?
假如有一个程序如下所示,点击Switch之后会从Summary Page切换到另一个页面Detail Page:
在MVVM中,我们需要有三个ViewModel,一个是SummaryViewModel对应SummaryPage, 一个是DetailViewModel对应DetailPage,再加上一个ControlViewModel负责通过改变CurrentPageViewModel来实现逻辑数据的切换并将其反应到UI,如下所示:
public class SummaryViewModel { public ObservableCollection<SummaryModel> Summaries { get; set; } public SummaryViewModel() { Summaries = new ObservableCollection<SummaryModel>(); } }
public class DetailViewModel { public ObservableCollection<DetailModel> Details { get; set; } public DetailViewModel() { Details = new ObservableCollection<DetailModel>(); } }
public class NavigationControlViewModelBase : ViewModelBase { private object currentPageViewModel; public object CurrentPageViewModel { get { return currentPageViewModel; } set { currentPageViewModel = value; RaisePropertyChanged(() => CurrentPageViewModel); } } } public class ControlViewModel : NavigationControlViewModelBase { private SummaryViewModel summary; public SummaryViewModel Summary { get { return summary; } set { summary = value; RaisePropertyChanged(() => Summary); } } private DetailViewModel detail; public DetailViewModel Detail { get { return detail; } set { detail = value; RaisePropertyChanged(() => Detail); } } public ControlViewModel() { SwitchCommand = new RelayCommand(Switch); Summary = new SummaryViewModel(); Detail = new DetailViewModel(); CurrentPageViewModel = Summary; GenerateData(); } public ICommand SwitchCommand {get;set;} private void Switch() { if (CurrentPageViewModel == Summary) { CurrentPageViewModel = Detail; } else { CurrentPageViewModel = Summary; } } private void GenerateData() { var ran = new Random(); Summary.Summaries.Clear(); Detail.Details.Clear(); for (int i = 0; i < 100; i++) { Summary.Summaries.Add(new SummaryModel() { ID = ran.Next(0, 100) }); } for (int i = 0; i < 100; i++) { Detail.Details.Add( new DetailModel() { ID = i, Data1 = Guid.NewGuid().ToString().Substring(0, 4), Data2 = Guid.NewGuid().ToString().Substring(0, 4), Data3 = Guid.NewGuid().ToString().Substring(0, 4), Data4 = Guid.NewGuid().ToString().Substring(0, 4), Data5 = Guid.NewGuid().ToString().Substring(0, 4), }); } } }
添加一个类NavigationControlFrame继承Frame负责控制Navigation, 在这个类里有一个依赖属性CurrentPageObject,在XAML中会将它与ControlViewModel的CurrentPageViewModel绑定,CurrentPageViewMdoel改变时,触发OnCurrentPageObjectChanged。通过XAML里定义的ViewModel类型和Page Uri对应关系找到相应的页面进行切换:
class NavigationControlFrame : Frame { public NavigationControlFrame() { Navigated += navigationFrame_Navigated; } public static readonly DependencyProperty CurrentPageObjectProperty = DependencyProperty.Register("CurrentPageObject", typeof(object), typeof(NavigationControlFrame), new PropertyMetadata(default(object), OnCurrentPageObjectChanged)); private static void OnCurrentPageObjectChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { var navigationFrame = (NavigationControlFrame)dependencyObject; var newValue = dependencyPropertyChangedEventArgs.NewValue; if (newValue == null) { navigationFrame.Navigate(null); return; } var pageUri = (string)navigationFrame.TryFindResource(newValue.GetType()); navigationFrame.Navigate(new Uri(pageUri, UriKind.Relative), newValue); } static void navigationFrame_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e) { if (e.ExtraData != null) { var control = e.Content as Page; control.DataContext = e.ExtraData; } } public object CurrentPageObject { get { return GetValue(CurrentPageObjectProperty); } set { SetValue(CurrentPageObjectProperty, value); } } }
在XAML中在Resource中定义ViewModel与Page
Uri的对应关系,添加NavigtaionControlFrame,并将CurrentPageObject绑定到CurrentPageViewModel,这样ControlViewModel中的CurrentPageViewModel变化时,对应的页面也会进行切换:
<Window x:Class="NavigationApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:navigationApp="clr-namespace:NavigationApp" xmlns:viewModels="clr-namespace:ViewModels;assembly=ViewModels" xmlns:sys="clr-namespace:System;assembly=mscorlib" Title="MainWindow" Height="600" Width="800"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Grid.Resources> <viewModels:ControlViewModel x:Key="Cvm1"></viewModels:ControlViewModel> <sys:String x:Key="{x:Type viewModels:DetailViewModel}">/DetailPage.xaml</sys:String> <sys:String x:Key="{x:Type viewModels:SummaryViewModel}">/SummaryPage.xaml</sys:String> </Grid.Resources> <StackPanel Grid.Row="0" Grid.Column="0" DataContext="{StaticResource Cvm1}" Background="LightGreen"> <navigationApp:NavigationControlFrame CurrentPageObject="{Binding CurrentPageViewModel}"> </navigationApp:NavigationControlFrame> <Button Content="Switch" Command="{Binding SwitchCommand}"></Button> </StackPanel> </Grid> </Window>
WPF: 在MVVM中使用Navigtaion,布布扣,bubuko.com
标签:style blog class code c java
原文地址:http://www.cnblogs.com/nofireice/p/3250725.html