问题
I am pretty new to MvvmCross and the mvvm pattern in general, so I started a small learning project and immidiatly ran into a wall. I based my application on the idea of having a MainView which contains a standard Menu
and a child MvxWpfView
. This ChildView should be a simple ReadMeView first, but on user input it should switch to an other View (the one with actual data on it). I already found a few articles about this issue but none of them worked or i wasn't able to follow.
My setup:
- Core Library (.NET Standard 2.0)
- Wpf app (.NET Core 3.1)
This is my MainViewModel with this users solution still implemented:
using MvvmCross.Commands;
using MvvmCross.ViewModels;
namespace puRGE.Core.ViewModels
{
public class MainViewModel : MvxViewModel
{
#region Fields -------------------------------------------------------------------------------------
private HomeViewModel m_homeViewModel = new HomeViewModel();
#endregion ------------------------------------------------------------------------ Fields endregion
#region Properties ---------------------------------------------------------------------------------
public HomeViewModel Home {
get => m_homeViewModel;
set => SetProperty(ref m_homeViewModel, value);
}
#endregion -------------------------------------------------------------------- Properties endregion
#region Constructors -------------------------------------------------------------------------------
public MainViewModel() { }
#endregion ------------------------------------------------------------------ Constructors endregion
#region Public methods -----------------------------------------------------------------------------
public override void Prepare()
{
Home = new HomeViewModel();
}
#endregion ---------------------------------------------------------------- Public methods endregion
}
}
This is the xaml part located inside my MainView (still part of this users solution):
<Menu>
<!-- Some MenuItems -->
</Menu>
<UserControl DataContext="{Binding Home, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
Vision VS. Reality
image of what I am trying to achieve
I also tried using the MvxContentPresentation
attribute, but to be honest I lost myself somewhere in the MvvmCross Documentation and at this point I am almost stepping on my eye bags.
<local:HomeView/>
This doesn't work either. Binding
s stop working this way even when the properties value get's set inside the ViewModel
s Prepare()
method. I guess calling the View like this breaks some chain of events or something.
How do I place a View inside my MainView? Is this Child then able to navigate to another View and vice versa (following the Navigation Documentation)?
Edit_01102020:
A general Mvvm approach doesn't seem to work so far.
Edit_02102020:
Home can now navigate to SomeOtherViewModel and back. Still no clue how to contain this in my MainView.
回答1:
In your MainView.xaml
:
<Menu>
<!-- Some MenuItems -->
</Menu>
<UserControl DataContext="{Binding Home}">
<UserControl.Resources>
<DataTemplate DataType="{x:Type viewModels:ModelAViewModel}">
<local:ModelAView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:ModelBViewModel}">
<local:ModelBView />
</DataTemplate>
</UserControl.Resources>
<ContentPresenter Content="{Binding}" />
</UserControl>
Remember to Notify your changes in your HomeViewModel
:
public void ActivateModelAViewModel()
{
HomeViewModel = Mvx.IoCProvider.Resolve<ModelAViewModel>();
//In your HomeViewModel property:
//RaisePropertyChanged(() => HomeViewModel);
}
public void ActivateModelBViewModel()
{
HomeViewModel = Mvx.IoCProvider.Resolve<ModelBViewModel>();
//In your HomeViewModel property:
//RaisePropertyChanged(() => HomeViewModel);
}
回答2:
I have also found that the following alternatives also do the job (except for the first one, commented out):
<StackPanel>
<!--<TextBlock FontWeight="Bold">1. ContentPresenter - DataContext</TextBlock>
<ContentPresenter DataContext="{Binding ActiveViewModel}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>-->
<TextBlock FontWeight="Bold">2. ContentPresenter - Content</TextBlock>
<ContentPresenter Content="{Binding ActiveViewModel}" >
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
<TextBlock FontWeight="Bold">3. ContentControl - DataContext</TextBlock>
<ContentControl DataContext="{Binding ActiveViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</ContentControl.Resources>
<ContentPresenter Content="{Binding}" />
</ContentControl>
<TextBlock FontWeight="Bold">4. ContentControl - Content</TextBlock>
<ContentControl Content="{Binding ActiveViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
<TextBlock FontWeight="Bold">5. UserControl - DataContext</TextBlock>
<UserControl DataContext="{Binding ActiveViewModel}">
<UserControl.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</UserControl.Resources>
<ContentPresenter Content="{Binding}" />
</UserControl>
<TextBlock FontWeight="Bold">6. UserControl - Content</TextBlock>
<UserControl Content="{Binding ActiveViewModel}">
<UserControl.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</UserControl.Resources>
</UserControl>
<TextBlock FontWeight="Bold">7. MvxWpfView - DataContext</TextBlock>
<views:MvxWpfView DataContext="{Binding ActiveViewModel}">
<views:MvxWpfView.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</views:MvxWpfView.Resources>
<ContentPresenter Content="{Binding}" />
</views:MvxWpfView>
<TextBlock FontWeight="Bold">8. MvxWpfView - Content</TextBlock>
<views:MvxWpfView Content="{Binding ActiveViewModel}">
<views:MvxWpfView.Resources>
<DataTemplate DataType="{x:Type viewModels:WorkWeekViewModel}">
<local:WorkWeekView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:WorkViewModel}">
<local:WorkView />
</DataTemplate>
</views:MvxWpfView.Resources>
</views:MvxWpfView>
</StackPanel>
Some are just inherited from the others, eg. MvxWpfView : UserControl
; UserControl : ContentControl
, but not sure about ContentPresenter
, which needs not to have the child <ContentPresenter Content="{Binding}" />
inside (since it is itself a ContentPresenter
).
In my case ActiveViewModel
, WorkWeekViewModel
and WorkViewModel
are instances of MvxViewModel
; WorkWeekView
and WorkView
are instances of MvxWpfView
.
来源:https://stackoverflow.com/questions/64156979/mvvmcross-view-inside-another-view-or-the-equivalent-to-a-caliburnmicro-conduc