5

скажите, как лучше организовать постраничную навигацию, если используется mvvm light? предполагается главное окно, страница по умолчанию и еще несколько, все в главном окне

andreycha
  • 25,167
  • 4
  • 46
  • 82
bmo
  • 346
  • 1
  • 12
  • 1
    На вопрос дан хороший ответ, можно оставить открытым. Хотя в будущем следует явно описывать возникшие трудности. – Kyubey Dec 02 '15 at 16:58

2 Answers2

10

Объявляем интерфейс:

public interface INavigationService
{
    void Navigate(Type type);
    void Navigate(Type type, object parameter);
    void EnsureNavigated(Type pageType, object parameter);

    bool CanGoBack { get; }
    bool CanGoForward { get; }
    void GoBack();
    void GoForward(); 

    IView CurrentView { get; }
}

Реализуем этот интерфейc:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;

public class NavigationService : INavigationService
{
    private readonly Frame _frame;

    public NavigationService(Frame frame)
    {
        _frame = frame;
        _frame.Navigated += OnFrameNavigated;
    }

    private void OnFrameNavigated(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
    {
        var view = e.Content as IView;
        if (view == null)
            return;

        var navMsg = new NavigationMessage()
        {
            Sender = this,
            NewView = view,
            Parameter = e.Parameter,
            NavigationMode = (int)e.NavigationMode
        };

        EventManager.Current.Publish(navMsg);

        var viewModel = view.ViewModel;
        if (viewModel != null)
            viewModel.Initialise(e.Parameter);
    }

    public void Navigate(Type pageType)
    {
        DisposePreviousView();
        _frame.Navigate(pageType);
    }

    public void Navigate(Type pageType, object parameter)
    {
        DisposePreviousView();
        _frame.Navigate(pageType, parameter);
    }

    private void DisposePreviousView()
    {
        var currentView = this.CurrentView;
        var currentViewDisposable = currentView as IDisposable;
        if (currentViewDisposable != null)
        {
            currentViewDisposable.Dispose();
            currentViewDisposable = null;
        }
    }

    public void EnsureNavigated(Type pageType, object parameter)
    {
        var currentView = this.CurrentView;
        if (currentView == null || currentView.GetType() != pageType)
        {
            Navigate(pageType, parameter);
        }
    }

    public IView CurrentView
    {
        get { return _frame.Content as IView; }
    }


    public bool CanGoBack
    {
        get { return _frame != null && _frame.CanGoBack; }
    }

    public void GoBack()
    {
        if (_frame != null && _frame.CanGoBack) _frame.GoBack();
    }

    public bool CanGoForward
    {
        get { return _frame != null && _frame.CanGoForward; }
    }

    public void GoForward()
    {
        if (_frame != null && _frame.CanGoForward) _frame.GoForward();
    }

}

IView:

public interface IView : IDisposable
{
    IViewModel ViewModel { get; }
    void Refresh();
}

IViewModel:

public interface IViewModel : INotifyPropertyChanged, IDisposable
{
    void Initialise(object parameter);
    string ViewTitle { get; }
    void Refresh();
}

В ХАМЛе добавить фрейм элемент: <Frame x:Name="ContentFrame" />

В заднике: var _navigationService = new NavigationService(this.ContentFrame);

Т.е. например так:

public HomePage()
{
    this.InitializeComponent();

    var _navigationService = new NavigationService(this.ContentFrame);

    DataContext = new HomePageViewModel(_navigationService);

}

Еще рекомендую почитать эту статью.

  • огромное спасибо за подробный ответ! – bmo Nov 16 '15 at 16:55
  • 1
    @bmo если ответ вам помог решить вашу проблему, то нажмите галочку напротив моего ответа. – Мстислав Павлов Nov 16 '15 at 16:58
  • я бы с удовольствием плюсанул, но карма не позволяет ( – bmo Nov 16 '15 at 17:00
  • 1
    @bmo я не про плюсование, а про пометку ответа правильным :) – Мстислав Павлов Nov 16 '15 at 17:01
  • vs 2015 не может найти Windows.UI.Xaml.Controls – bmo Nov 16 '15 at 17:21
  • @bmo установите ReSharper, он поможет вам автоматически подключать необходимые библиотеки. – Мстислав Павлов Nov 16 '15 at 17:27
  • скачать ReSharper оказалось довольно сложно ) вопрос поиска библиотеки остается открытым ) – bmo Nov 16 '15 at 17:57
  • DataContext = new HomePageViewModel(_navigationService) мне не совсем понятно. я думал ViewModel создается актоматически. какой конструктор мне реализовать во ViewModel? – bmo Nov 16 '15 at 17:59
  • .GetFor в самом конце ответа - опечатка? – bmo Nov 16 '15 at 18:01
  • совсем не понятно как реализовать методы и поля интерфейсов IView и IViewModel. и как осуществлять навигацию (например NavigationUIVisibility="Hidden" и управлять своими кнопками) – bmo Nov 16 '15 at 18:15
  • 1
    Как выяснилось, код приведенный мною несколько устарел для актуальных версий студии. Воспользуйтесь ссылкой в конце, там более актуальный пример. – Мстислав Павлов Nov 16 '15 at 22:00
-1

нашёл такое решение:

xaml

    xmlns:viewModels="clr-namespace:iim.ViewModels"
    xmlns:views="clr-namespace:iim.Views"

    <Window.DataContext>
        <viewModels:MainViewModel x:Name="xxx"/>
    </Window.DataContext>
    <Window.Resources>
        <DataTemplate DataType="{x:Type viewModels:GridViewModel}">
            <views:GridVieww />
    </DataTemplate>
    </Window.Resources>

    <DockPanel>
    <DockPanel.Resources>
        <viewModels:MainViewModel x:Key="xxx" />
        <viewModels:BoolToVis x:Key="b" />
    </DockPanel.Resources>
    <StackPanel DockPanel.Dock="Top">
        <Button Content="Excel" Command="{Binding ShowExcelView}"></Button> 
    </StackPanel> 
    <ContentControl x:Name="Viewss" DockPanel.Dock="Bottom" Content="{Binding SelectedViewModel}"/>

MainViewModel.cs

    using GalaSoft.MvvmLight;
    using GalaSoft.MvvmLight.Command;

    public class MainViewModel : ViewModelBase
    {
        private object selectedViewModel;
        public object SelectedViewModel
        {
            get
            {
                return selectedViewModel;
            }
            set
            {
                selectedViewModel = value;
                RaisePropertyChanged(() => SelectedViewModel);
            }
        }

        private ICommand _showGridView;
        public ICommand ShowGridView
        {
            get
            {
                return _showGridView ?? (_showGridView = new RelayCommand(() =>
                {
                    SelectedViewModel = new GridVieww();
                }));
            }
        }
    }
bmo
  • 346
  • 1
  • 12