当我们刚开始使用MVVM模式的时候和传统CodeBehind相比会遇到很多问题,但是肯定是有解决方法,我们应该尽量往这个方向思考,下面我们通过一个例子来演示如何在不同View之间进行切换,这节我们通过一个简单例子来实现导航,基本的项目结构如下:
我们新建一个Common文件夹,创建DelegateCommand和ViewModelBase类两个基础类.
using System;
using System.Windows.Input;
namespace WPF_23_MVVM_SwitchPage.Common
{
public class DelegateCommand : ICommand
{
private Action<object> _execute;
private Func<bool> _canExecute;
public DelegateCommand(Action<object> executeMethod)
{
_execute = executeMethod;
}
public DelegateCommand(Action<object> executeMethod, Func<bool> canExecute)
: this(executeMethod)
{
this._canExecute = canExecute;
}
public event EventHandler? CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_execute?.Invoke(parameter);
}
}
}
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WPF_23_MVVM_SwitchPage.Common
{
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler? PropertyChanged;
public virtual void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
我们定义一个接口IViewModel,分别让三个ViewModel实现该接口
namespace WPF_23_MVVM_SwitchPage
{
public interface IViewModel
{
string Name { get; }
}
}
public class DiscoverViewModel : ViewModelBase, IViewModel
{
public string Name => "Disconver";
}
public class SearchViewModel : ViewModelBase, IViewModel
{
public string Name => "Search";
}
public class ToolsViewModel : ViewModelBase, IViewModel
{
public string Name => "Tool";
}
public class MainFrameViewModel : ViewModelBase
{
private ICommand _changeViewCommand;
private IViewModel _currentViewModel;
private List<IViewModel> _viewModels;
public MainFrameViewModel()
{
_viewModels = new List<IViewModel>();
ViewModels.Add(new SearchViewModel());
ViewModels.Add(new DiscoverViewModel());
ViewModels.Add(new ToolsViewModel());
_changeViewCommand = new DelegateCommand(ChangeView);
_currentViewModel = ViewModels[0];
}
public ICommand ChangeViewCommand
{
get { return _changeViewCommand; }
set { _changeViewCommand = value; }
}
public List<IViewModel> ViewModels
{
get
{
return _viewModels;
}
set
{
_viewModels = value;
}
}
public IViewModel CurrentViewModel
{
get
{
return _currentViewModel;
}
set
{
if (_currentViewModel != value)
{
_currentViewModel = value;
NotifyPropertyChanged("CurrentViewModel");
}
}
}
public void ChangeView(object parameter)
{
var viewModel = (IViewModel)parameter;
if (!ViewModels.Contains(viewModel))
ViewModels.Add(viewModel);
CurrentViewModel = ViewModels.FirstOrDefault(vm => vm == viewModel);
}
}
<Window x:Class="WPF_23_MVVM_SwitchPage.MainFrameView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF_23_MVVM_SwitchPage"
mc:Ignorable="d"
Title="MainFrameView" Height="450" Width="800">
<Window.Resources>
<DataTemplate DataType="{x:Type local:SearchViewModel}">
<local:SearchView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:DiscoverViewModel}">
<local:DiscoverView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ToolsViewModel}">
<local:ToolsView/>
</DataTemplate>
</Window.Resources>
<DockPanel>
<Border DockPanel.Dock="Left" BorderBrush="Black" BorderThickness="0,0,1,0">
<ItemsControl ItemsSource="{Binding ViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangeViewCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"
Margin="5,5" Width="60" Height="34"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
<ContentControl Content="{Binding CurrentViewModel}" />
</DockPanel>
</Window>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainFrameView app = new MainFrameView();
MainFrameViewModel context = new MainFrameViewModel();
app.DataContext = context;
app.Show();
}
}
到此代码基本完成,我们看一下效果: