MvvmCross: View inside another View (or the equivalent to a CaliburnMicro Conductor)

天涯浪子 提交于 2021-01-21 05:59:11

问题


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. Bindings stop working this way even when the properties value get's set inside the ViewModels 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!