Самый простой и легкий способ использования Frame
- создать модель представления для каждой страницы. Затем создайте модель основного вида, которая содержит все страницы и управляет их выбором. ContentControl
будет отображать модели представлений, используя DataTemplate
, назначенный свойству ContentControl.ContentTemplate
, или в многостраничном сценарии либо DataTemplateSelector
, назначенный ContentControl.ContentTemplateSelector
, либо неявные шаблоны, только определяя DataTemplate.DataType
без Key
атрибут:
Представление
MainWindow.xaml
<Window>
<Window.DataContext>
<MainViewModel x:Key="MainViewModel" />
</Window.DataContext>
<Window.Resources>
<!--
The templates for the view of each page model.
Can be moved to dedicated files.
-->
<DataTemplate DataType="{x:Type PageA}">
<Border Background="Coral">
<TextBlock Text="{Binding Title}" />
</Border>
</DataTemplate>
<DataTemplate DataType="{x:Type PageB}">
<Border Background="DeepSkyBlue">
<TextBlock Text="{Binding Title}" />
</Border>
</DataTemplate>
</Window.Resources>
<StackPanel>
<Button Content="Load Page A"
Command="{Binding SelectPageFromIndexCommand}"
CommandParameter="0" />
<Button Content="Load Page B"
Command="{Binding SelectPageFromIndexCommand}"
CommandParameter="1" />
<!-- The actual page control -->
<ContentControl Content="{Binding SelectedPage}" />
</StackPanel>
</Window>
Модель представления
MainViewModel. cs
class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
this.Pages = new ObservableCollection<IPage>() {new PageA() {Title = "Page A"}, new PageB() {Title = "Page B"}};
// Show startup page
this.SelectedPage = this.Pages.First();
}
// Define the Execute and CanExecute delegates for the command
// and pass to constructor
public ICommand SelectPageFromIndexCommand => new SelectPageCommand(
param => this.SelectedPage = this.Pages.ElementAt(int.Parse(param as string)),
param => int.TryParse(param as string, out int index));
private IPage selectedPage;
public IPage SelectedPage
{
get => this.selectedPage;
set
{
if (object.Equals(value, this.selectedPage))
{
return;
}
this.selectedPage = value;
OnPropertyChanged();
}
}
private ObservableCollection<IPage> pages;
public ObservableCollection<IPage> Pages
{
get => this.pages;
set
{
if (object.Equals(value, this.pages))
{
return;
}
this.pages = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
SelectPageCommand.cs
class SelectPageCommand : ICommand
{
public SelectPageCommand(Action<object> executeDelegate, Predicate<object> canExecuteDelegate)
{
this.ExecuteDelegate = executeDelegate;
this.CanExecuteDelegate = canExecuteDelegate;
}
private Predicate<object> CanExecuteDelegate { get; }
private Action<object> ExecuteDelegate { get; }
#region Implementation of ICommand
public bool CanExecute(object parameter) => this.CanExecuteDelegate?.Invoke(parameter) ?? false;
public void Execute(object parameter) => this.ExecuteDelegate?.Invoke(parameter);
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
#endregion
}
Модели страниц
IPage.cs
// Base type for all pages
interface IPage : INotifyPropertyChanged
{
string Title { get; set; }
}
PageA.cs
// IPage implementation.
// Consider to introduce dedicated interface IPageA which extends IPage
class PageA : IPage
{
public string Title { get; set; }
// Implementation of INotifyPropertyChanged
}
PageB.cs
// IPage implementation.
// Consider to introduce dedicated interface IPageB which extends IPage
class PageB : IPage
{
public string Title { get; set; }
// Implementation of INotifyPropertyChanged
}