Я написал оболочку над ContentPage и ContentView, чтобы включить первую навигацию по ViewModel.
Это довольно просто: вы помещаете MvxNestableContentView внутрь MvxNestableContentPage и присваиваете ему имя.
Затем в вашей ViewModel (которая является производной от MvxNestableViewModel) вы просто вызываете SetContent (typeof (viewmodel));
public interface INestedViewModelEventArgs
{
string ContainerName { get; set; }
IMvxNestableViewModel ViewModel { get; set; }
bool SuppressAppearing { get; set; }
}
public interface IMvxNestableViewModel : IMvxViewModel
{
event EventHandler SetNestedViewModel;
IMvxNestableViewModel SetContent(Type tViewModel, string containerName, bool suppressAppearing = false);
}
public interface IMvxNestableContentView
{
void OnAppearing();
void OnDisappearing();
}
public interface IMvxNestableContentPage
{
}
public class MvxNestableContentView : MvxContentView, IMvxNestableContentView
{
public MvxNestableContentView()
{
}
protected override void OnViewModelSet()
{
if (ViewModel is IMvxNestableViewModel vm)
{
vm.SetNestedViewModel += VmOnSetNestedViewModel;
}
ViewModel?.ViewCreated();
}
public virtual void OnAppearing()
{
ViewModel?.ViewAppearing();
ViewModel?.ViewAppeared();
foreach (var v in _nestedContentViews)
{
v.OnAppearing();
}
}
public virtual void OnDisappearing()
{
if (ViewModel is IMvxNestableViewModel vm)
{
vm.SetNestedViewModel -= VmOnSetNestedViewModel;
}
foreach (var v in _nestedContentViews)
{
v.OnDisappearing();
}
ViewModel?.ViewDisappearing();
ViewModel?.ViewDisappeared();
ViewModel?.ViewDestroy();
}
private readonly List<MvxNestableContentView> _nestedContentViews = new List<MvxNestableContentView>();
private void VmOnSetNestedViewModel(object sender, EventArgs e)
{
if (!(e is NestedViewModelEventArgs args)) return;
if (string.IsNullOrWhiteSpace(args.ContainerName) || args.ViewModel == null) return;
var contentView = this.FindByName<MvxNestableContentView>(args.ContainerName);
if (contentView == null)
{
throw new Exception("MvxNestableContentView : MvxNestableContentView named " + args.ContainerName + " not found");
}
var viewLookup = Mvx.IoCProvider.Resolve<IMvxViewsContainer>();
var viewType = viewLookup.GetViewType(args.ViewModel.GetType());
var viewObject = Mvx.IoCProvider.IoCConstruct(viewType);
if (!(viewObject is MvxNestableContentView view))
{
throw new Exception("MvxNestableContentView : view is not MvxNestableContentView");
}
view.ViewModel = args.ViewModel;
var existingContent = contentView.Content as MvxNestableContentView;
if (!args.SuppressAppearing) view.OnAppearing();
_nestedContentViews.Add(view);
contentView.Content = view;
if (existingContent == null) return;
existingContent.OnDisappearing();
_nestedContentViews.Remove(existingContent);
}
}
public class MvxNestableContentView<TViewModel> : MvxNestableContentView, IMvxElement<TViewModel>
where TViewModel : class, IMvxViewModel
{
public new TViewModel ViewModel
{
get => (TViewModel)base.ViewModel;
set => base.ViewModel = value;
}
}
public class MvxNestableContentPage : MvxContentPage, IMvxNestableContentPage
{
public MvxNestableContentPage()
{
}
protected override void OnViewModelSet()
{
if (ViewModel is IMvxNestableViewModel vm)
{
vm.SetNestedViewModel += VmOnSetNestedViewModel;
}
base.OnViewModelSet();
}
protected override void OnAppearing()
{
base.OnAppearing();
foreach (var v in _nestedContentViews)
{
v.OnAppearing();
}
}
protected override void OnDisappearing()
{
if (ViewModel is IMvxNestableViewModel vm)
{
vm.SetNestedViewModel -= VmOnSetNestedViewModel;
}
foreach (var v in _nestedContentViews)
{
v.OnDisappearing();
}
base.OnDisappearing();
}
private readonly List<MvxNestableContentView> _nestedContentViews = new List<MvxNestableContentView>();
private void VmOnSetNestedViewModel(object sender, EventArgs e)
{
if (!(e is NestedViewModelEventArgs args)) return;
if (string.IsNullOrWhiteSpace(args.ContainerName) || args.ViewModel == null) return;
var contentView = this.FindByName<MvxNestableContentView>(args.ContainerName);
if (contentView == null)
{
throw new Exception("MvxNestableContentPage : MvxNestableContentView named " + args.ContainerName + " not found");
}
var viewLookup = Mvx.IoCProvider.Resolve<IMvxViewsContainer>();
var viewType = viewLookup.GetViewType(args.ViewModel.GetType());
var viewObject = Mvx.IoCProvider.IoCConstruct(viewType);
if (!(viewObject is MvxNestableContentView view))
{
throw new Exception("MvxNestableContentPage : view is not MvxNestableContentView");
}
view.ViewModel = args.ViewModel;
var existingContent = contentView.Content as MvxNestableContentView;
if (!args.SuppressAppearing) view.OnAppearing();
_nestedContentViews.Add(view);
contentView.Content = view;
if (existingContent == null) return;
existingContent.OnDisappearing();
_nestedContentViews.Remove(existingContent);
}
}
public class MvxNestableContentPage<TViewModel> : MvxNestableContentPage, IMvxPage<TViewModel>
where TViewModel : class, IMvxViewModel
{
public new TViewModel ViewModel
{
get => (TViewModel)base.ViewModel;
set => base.ViewModel = value;
}
}
public abstract class MvxNestableViewModel : MvxViewModel, IMvxNestableViewModel
{
public event EventHandler SetNestedViewModel;
public virtual IMvxNestableViewModel SetContent(Type viewModelType, string containerName, bool suppressAppearing = false)
{
if (!(Mvx.IoCProvider.IoCConstruct(viewModelType) is IMvxNestableViewModel viewModel))
{
return null;
}
viewModel.Start();
viewModel.Prepare();
viewModel.Initialize();
SetNestedViewModel?.Invoke(this, new NestedViewModelEventArgs
{
ContainerName = containerName,
ViewModel = viewModel,
SuppressAppearing = suppressAppearing
});
return viewModel;
}
}
public abstract class MvxNestableViewModel<TParameter> : MvxNestableViewModel, IMvxViewModel<TParameter>, IMvxNestableViewModel
{
public abstract void Prepare(TParameter parameter);
}
public abstract class MvxNestableViewModelResult<TResult> : MvxNestableViewModel, IMvxViewModelResult<TResult>, IMvxNestableViewModel
{
public TaskCompletionSource<object> CloseCompletionSource { get; set; }
public override void ViewDestroy(bool viewFinishing = true)
{
if (viewFinishing && CloseCompletionSource != null && !CloseCompletionSource.Task.IsCompleted && !CloseCompletionSource.Task.IsFaulted)
CloseCompletionSource?.TrySetCanceled();
base.ViewDestroy(viewFinishing);
}
}
public abstract class MvxNestableViewModel<TParameter, TResult> : MvxNestableViewModelResult<TResult>, IMvxViewModel<TParameter, TResult>, IMvxNestableViewModel
{
public abstract void Prepare(TParameter parameter);
}
public class NestedViewModelEventArgs : EventArgs, INestedViewModelEventArgs
{
public string ContainerName { get; set; }
public IMvxNestableViewModel ViewModel { get; set; }
public bool SuppressAppearing { get; set; }
}