Очередной вопрос по навигации в WPF. Пытаюсь использовать MVVM Light Toolkit 5.2. Итак, есть MainWindow
и к нему MainViewModel
. MainWindow
Содержит две панельки и Frame
(может быть ContentControl
) для отображения остальных вьюшек. В приложении хочется сделать страничную навигацию, да, желательно, так, чтобы не лезть в code behind.
Поскольку решено пользовать MVVM Light Toolkit, мне подумалось что хорошо бы родить какой-нибудь NavigationService
, который всё будет знать о вью и этими самыми вью будет рулить. Исходя из хотелок, родился вот такой монстр:
public interface INavigationService
{
void NavigateTo(string pageKey);
void RegisterView(string pageKey, Type page);
}
public abstract class NavigationServiceBase<T> : INavigationService
{
private T _currentPage;
public T CurrentPage {
get{
return _currentPage;
}
}
private Dictionary<string,Type> _registeredPages;
public virtual void NavigateTo(string pageKey){
if(string.IsNullOrEmpty(pageKey))
throw new ArgumentNullException("pageKey", "Value can not be null or empty");
Type view;
if(_registeredPages.TryGetValue(pageKey, out view))
_currentPage = (T)Activator.CreateInstance(view);
}
public virtual void RegisterView(string pageKey, Type page)
{
if(string.IsNullOrEmpty(pageKey) || page == null)
throw new ArgumentNullException();
_registeredPages.Add(pageKey, page);
}
public NavigationServiceBase ()
{
_registeredPages = new Dictionary<string, Type>();
}
}
public class PageNavigationService : NavigationServiceBase<Page>{
public PageNavigationService () : base()
{
}
}
public class ViewModelLocator{
static ViewModelLocator(){
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<INavigationService>(() => CreateNavigationService());
}
private static INavigationService CreateNavigationService(){
var navigationService = new PageNavigationService();
navigationService.RegisterView("EmployeesView",typeof(EmployeesView));
return navigationService;
}
}
Однако, после рождения монстра, у меня возникли сомнения в правильности такого решения: предполагалось, что NavigationService
будет инжектиться в основную ViewModel
и "пробросит" туда свойство CurrentPage
, на которое забиндится Content
фрейма. Но, поскольку у INavigationService этого свойства нет и быть не может, смысл этого интерфейса теряется полностью, что не хорошо.
Итак, вопросы:
Есть ли способ внутри NavigationService
получить каким-то образом ссылку на фрейм, не передавая ее через конструктор и не устанавливая свойств сервиса? Чтобы можно было внутри NavigationService
выполнить refToFrame.Content = Activator.CreateInstance(SomeView)
Может быть я вообще не туда смотрю и лучше использовать какой-нибудь Messenger
или другой механизм для этой цели?
Может быть лучше сделать NavigationService
синглтоном и дергать его в нужную ViewModel
по необходимости?
В общем, получилось реализовать задуманное с помощью Мессенджера.
Добавился класс NavigateToMessage
public class NavigateToMessage<T>()
{
public T View {get; private set;}
public NavigateToMessage(T view){
View = view;
}
NaviagtionServiceBase
не изменился. PageNavigationService
Дополнился переопределенным методом NavigateTo()
:
...
public override NavigateTo(string pageKey)
{
base.NavigateTo(pageKey);
Messenger.Default.Send(new NaviagteToMessage<Page>(_currentPage));
}
В главной ViewModel
регистрируемся как получатель сообщения и устанавливаем свойство CurrentPage
, которое биндится на Content фрейма в главном вью.
MessengerInstance.Register<NavigateToMessage<Page>>(this, message =>
{
CurrentPage = message.View;
});
Надеюсь, что решение поможет кому-то ещё, кроме меня.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Мое WinForms приложение может вызывать консольное, которое завершает процесс приложение WinForms и удаляет егоКогда я запускаю консольное приложение...
Есть приведенный ниже код, суть в том, что функции Add(), Read(), Modify(), Remove(), вызываются извне и в хаотичном порядке, с разным периодом во времени