Jak poruszać się po oknach za pomocą MVVM Light for WPF?
Właśnie rozpocząłem nowy projekt, w którym warstwę prezentacyjną wykonają WPF i MVVM Light firmy GalaSoft.
Potrzebuję dużo widoków i nie jest dla mnie jasne, jak zarządzać nawigacją przez windows.
Przede wszystkim szablony oferowane w MVVM Light do tworzenia nowego "widoku WPF MVVM" tworzą nowy Window
, którego nie można użyć do nawigacji po ramce (chodzi mi o umieszczenie ramki w mainView
i zmianę ścieżki źródłowej na nawigować).
Czy po prostu muszę zmienić Window
na Page
dla wszystkich widoków, które tworzę za pomocą szablonów?
A może istnieje inny sposób wykonywania nawigacji w WPF za pomocą zestawu narzędzi MVVM Light?
3 answers
Zwykle używam ContentControl
do wyświetlania dynamicznej zawartości. To Content
właściwość jest zwykle związana z CurrentViewModel
właściwością w rodzicu ViewModel
, a {[4] } są używane do informowania WPF, jak narysować dziecko ViewModels
.
Aby zmienić widok, po prostu zmień właściwość CurrentViewModel
w rodzicu ViewModel
Możesz znaleźć przykład na Ten mój artykuł
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-15 13:39:06
W końcu zrobiłem to w ten sposób.
Podążając za ideą o_q, stworzyłem NavigationWindow jako MainWindow i zmieniłem wszystkie widoki na stronę.
Potem stworzyłem inteface i klasę, która używając nawigacji:
public interface INavigationService
{
event NavigatingCancelEventHandler Navigating;
void NavigateTo(Uri pageUri);
void GoBack();
}
public class NavigationService : INavigationService
{
private NavigationWindow _mainFrame;
#region Implementation of INavigationService
public event NavigatingCancelEventHandler Navigating;
public void NavigateTo(Uri pageUri)
{
if (EnsureMainFrame())
{
_mainFrame.Navigate(pageUri);
}
}
public void GoBack()
{
if (EnsureMainFrame()
&& _mainFrame.CanGoBack)
{
_mainFrame.GoBack();
}
}
#endregion
private bool EnsureMainFrame()
{
if (_mainFrame != null)
{
return true;
}
_mainFrame = System.Windows.Application.Current.MainWindow as NavigationWindow;
if (_mainFrame != null)
{
// Could be null if the app runs inside a design tool
_mainFrame.Navigating += (s, e) =>
{
if (Navigating != null)
{
Navigating(s, e);
}
};
return true;
}
return false;
}
}
Następnie, w viewmodellocatorze stworzyłem cały łańcuch const nedded do przechowywania ścieżek do moich widoków:
public class ViewModelLocator
{
#region Views Paths
public const string FrontendViewPath = "../Views/FrontendView.xaml";
public const string BackendViewPath = "../Views/BackendView.xaml";
public const string StartUpViewPath = "../Views/StartUpView.xaml";
public const string LoginViewPath = "../Views/LoginView.xaml";
public const string OutOfOrderViewPath = "../Views/OutOfOrderView.xaml";
public const string OperativeViewPath = "../Views/SubViews/OperativeView.xaml";
public const string ConfigurationViewPath = "../Views/SubViews/ConfigurationView.xaml";
#endregion
}
W Aplikacji.cs, w application_startup event handler, przy pomocy Unity IOC zarejestrowałem singleton z NavigationService:
public partial class App : System.Windows.Application
{
private static IUnityContainer _ambientContainer;
public static IServiceLocator AmbientLocator { get; private set; }
...
private void Application_Startup(object sender, System.Windows.StartupEventArgs e)
{
_ambientContainer =
new UnityContainer();
_ambientContainer.RegisterType<INavigationService, NavigationService>(new ContainerControlledLifetimeManager());
AmbientLocator = new UnityServiceLocator(_ambientContainer);
ServiceLocator.SetLocatorProvider(() => AmbientLocator);
Teraz, moim zdaniem, mogę zarejestrować komunikat "Galasoft", aby wychwycić wszystkie zdarzenia i przejść do strony; w konstruktorze Mam:
public ViewModelLocator()
{
CreateMain();
CreateFrontend();
CreateBackend();
CreateStartUp();
CreateOperative();
CreateLogin();
CreateConfiguration();
CreateOutOfOrder();
// Set Startup Page...
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(StartUpViewPath, UriKind.Relative));
Messenger.Default.Register<MoveToViewMessage>(this, message =>
{
switch (message.StateInfo.StateType)
{
case StateType.StartUpState:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(StartUpViewPath,UriKind.Relative));
break;
case StateType.LoginState:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(LoginViewPath, UriKind.Relative));
break;
case StateType.OperativeState:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(OperativeViewPath, UriKind.Relative));
break;
case StateType.ConfigurationState:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(ConfigurationViewPath, UriKind.Relative));
break;
case StateType.ClosedState:
case StateType.OutOfOrderState:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(OutOfOrderViewPath, UriKind.Relative));
break;
default:
ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(StartUpViewPath, UriKind.Relative));
break;
}
});
}
W ten sposób zachowuję wszystkie viewmodele "ignorantami"... nie wiedzą nic o nawigacji, a ja nie mam kodu.
Jeśli muszę nawigować za pomocą przycisku z widoku, mogę rozwiązać NavigationService z połączonego modelu widoku i przejść do strony, której potrzebuję.
Oraz, najważniejsze, że działa!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-24 18:39:43
W przypadku aplikacji nawigacyjnej, widok startowy powinien być NavigationWindow
zamiast Window
<NavigationWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MainWindow"
Title="My Application Title"
Height="300"
Width="400" />
Kod za:
using System.Windows.Navigation;
public partial class MainWindow : NavigationWindow
{
public MainWindow()
{
InitializeComponent();
}
}
Szablony widoku świetlnego MVVM używają Window
, ale jak się domyślasz, możesz to po prostu zmienić. Jeśli chcesz mieć możliwość nawigowania do i z tego widoku, zrób z niego Page
.
Tak się nawiguje:
<Page
x:Class="Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1">
<Grid>
<!-- this button will navigate to another page -->
<Button
Content="Go to Page 2"
Click="Button_Click" />
</Grid>
</Page>
Kod Za:
using System.Windows;
using System.Windows.Controls;
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// the Page class has a property "NavigationService" which allows you to navigate.
// you can supply the "Navigate" method with a Uri or an object instance of the page
base.NavigationService.Navigate(new Page2());
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-16 01:06:58