我是MvvmCross的新手(我正在使用Xamarin.Forms),因此在MvxContentPages之间导航很容易。
但是我想在页面中嵌入的ContentView之间导航,但是找不到使用MvxContentView引用的任何文档。
考虑以下页面
<ContentPage.Content>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackLayout Grid.Column="0">
<Button Text="Content 1" Command="{Binding GotoContent1}"/>
<Button Text="Content 2" Command="{Binding GotoContent2}"/>
<Button Text="Content 3" Command="{Binding GotoContent3}"/>
<Button Text="Content 4" Command="{Binding GotoContent4}"/>
</StackLayout>
<ContentView x:Name="ContentContainer" Grid.Column="1"
HorizontalOptions="Fill"
VerticalOptions="Fill"/>
</Grid>
</ContentPage.Content>
当用户单击其中一个按钮时,我想在ContentContainer中显示一个MvxContentView(或者,如果有其他替代方法,那很好,我只是不想制作4个页面本质上相同,但内容视图占位符中的内容不同。
答案 0 :(得分:0)
Content View只是其下面的一个Layout,因此仅使用1个内容视图,并对所有4个都使用相同的现有ViewModel。并且只需根据单击哪个按钮从ViewModel更改内容视图中内容的值即可。
答案 1 :(得分:0)
我在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; }
}