Получить RegionManager в ViewModel

#c# #wpf #mvvm #navigation #prism

Вопрос:

В моем проекте я использую Prism для представлений и ViewModels. Теперь я хочу загрузить другое представление в UserControl в MainWindowView. Я читал, что могу сделать это с помощью этого:

_regionManager.RegisterViewWithRegion("MainRegion", typeof(View));

Но, к сожалению, я понятия не имею, как добраться до экземпляра IRegionManger в моей ViewModel. Во всех примерах, которые я нашел, используются другие переменные, но не показано, откуда они берутся.

Это мое мнение:

 <Window x:Class="PortfolioVisualizer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:PortfolioVisualizer"
        mc:Ignorable="d"
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="15*"/>
        </Grid.ColumnDefinitions>

        <StackPanel Grid.Column="0">
            <Button Command="{Binding NavigateCommand}" CommandParameter="AddAssetView">
                <StackPanel>
                    <Image/>
                    <Label Content="Add Asset"/>
                </StackPanel>
            </Button>
            <Button Command="{Binding NavigateCommand}" CommandParameter="ConfigView">
                <StackPanel>
                    <Image/>
                    <Label Content="Settings"/>
                </StackPanel>
            </Button>
        </StackPanel>

        <Grid Grid.Column="1">
            <ContentControl prism:RegionManager.RegionName="MainRegion"/>
        </Grid>

    </Grid>
</Window>
 

Это моя модель просмотра:

 public class MainWindowViewModel : ViewModelBase
    {
        private readonly IRegionManager _RegionManager;

        public DelegateCommand<string> NavigateCommand;
        

        public MainWindowViewModel(IRegionManager regionManager)
        {
            _RegionManager = regionManager;
            NavigateCommand = new DelegateCommand<string>(ExecuteNavigateCommand);
            _RegionManager.RegisterViewWithRegion("MainRegion", typeof(DashboardView));
        }

        private void ExecuteNavigateCommand(string viewName)
        {
            if (string.IsNullOrWhiteSpace(viewName))
                return;

            _RegionManager.RequestNavigate("ContentRegion", viewName);
        }
    }
 

Это ViewModdelBase

 public class ViewModelBase : BindableBase
    {
        public ViewModelBase()
        {
        
        }
    }
 

(Я знаю, что ViewModelBase просто лишний, но есть кое-что, что придет позже)

Ответ №1:

У вас есть контейнер, который вводит региональный менеджер, как и любую другую зависимость:

 internal class MyViewModel
{
    public MyViewModel( IRegionManager regionManager )
    {
        regionManager.DoSomeStuff(); // or just put it into a field for later use
    }
}
 

Обратите внимание, что это работает только автоматически, если вы не new выполняете модель представления вручную ни в коде, ни в xaml. Вместо этого создайте его с помощью фабрики, которая сама вводится (например Func<MyViewModel> myViewModelFactory ), если вы сначала просматриваете модель (рекомендуется в большинстве случаев), или используйте Prism ViewModelLocator , чтобы создать ее как контекст данных, если вы сначала просматриваете.

Комментарии:

1. ViewModelLocator.AutoWireViewModel=true достаточно @arne — учитывая, что ваши представления находятся в Views пространстве имен и моделях представлений ViewModels , и у них есть общее базовое имя, например MySpecialView , и MySpecialViewModel . Вы также можете зарегистрировать пары view / view model у поставщика view model, если вам не нравится конвенционный подход (хотя это совершенно нормально).

2. Как вы создаете модель представления? Локатор модели представления будет использовать контейнер и предоставлять все параметры. Если вы вручную вызываете свой конструктор, вы должны предоставить их самостоятельно.

3. @arne опубликованный вами xaml — это только открывающий тег — мы не видим <Window.DataContext> , например, есть ли там. <viewModels:MainWindowViewModel/> это тоже вызов конструктора. Также обратите внимание, что представления должны находиться в Views пространстве имен и просматривать модели, ViewModels чтобы работало соглашение по умолчанию.

4. Вы создаете MainWindow с Resolve<MainWindow>() помощью ? Тогда это должно работать с PrismApplication s по умолчанию. ConfigureViewModelLocator Вызывается в вашей настройке, т.Е. Достигнута ли там точка останова?

5. Если ConfigureViewModelLocator не вызывается, и вы не устанавливаете фабрику модели представления вручную, Prism использует Activator.CreateInstance по умолчанию, что не может ничего вводить и объясняет исключение, которое вы наблюдаете. Смотрите код здесь . Какой контейнер, приложение prism, загрузчик и т. Д. используете ли вы?