Ответ 1
Создание нескольких оболочек - правильная идея. Вам просто нужно позаботиться о деталях надлежащим образом.
Когда и как создать новую оболочку
Способ Prism, конечно же, должен иметь DelegateCommand
дескриптор создания новой оболочки. Учитывая, что эта команда не относится строго к какой-либо конкретной ViewModel (я бы сказал, что она имеет область применения), мне лучше иметь public static class ApplicationWideCommands
с статическим свойством CreateNewShellCommand
. Затем вы можете привязать его к XAML с помощью {x:Static}
или выполнить его с помощью кода по мере необходимости.
Эта команда должна позаботиться о двух вещах:
- Создайте новый
Window
(фактически,Shell
) - Создайте новый
IRegionManager
для новой оболочки, чтобы не было конфликтов между именами регионов между областями существующей оболочки и элементами новой оболочки - Попросите регионы в новой оболочке принадлежать новому
IRegionManager
Я займусь этим последним, потому что это проще объяснить.
Предоставление новой оболочке нового RegionManager
При объявлении региона в Prism вы можете объявить менеджера региона для использования в дополнение к имени региона. Обычно вам не нужно это делать, но здесь нам нужно выбрать, какой RegionManager
использовать, потому что имена регионов должны быть уникальными в области одного менеджера регионов. Поскольку имена областей жестко закодированы внутри XAML представлений, и было бы большой болью назначить их другим способом, нам нужно изменить другую половину уравнения: экземпляр менеджера области, используемый каждой оболочкой. Поэтому внутри Shell.xaml
может быть что-то вроде этого:
<ContentControl
regions:RegionManager.RegionManager="{Binding RegionManager}"
regions:RegionManager.RegionName="ExampleRegion"
/>
Это даст указание "WorkspaceRegion" в каждой оболочке, что она принадлежит IRegionManager
, предоставленной привязкой. Поскольку оболочка обычно не имеет DataContext
, мы можем объявить свойство RegionManager
в самом классе оболочки:
public partial class Shell : Window
{
public Shell(IRegionManager regionManager)
{
this.RegionManager = regionManager;
InitializeComponent();
}
public IRegionManager RegionManager { get; private set; }
}
Итак, теперь нам просто нужно убедиться, что каждый экземпляр Shell
получает свой собственный RegionManager
. Для "первой" оболочки это будет выполняться с помощью BootStrapper
. (Код ниже использует контейнер DI для разрешения объектов, а в примерах используется UnityContainer
. Если вы используете MEF для инъекции зависимостей, просто мысленно переводите эквивалентный код.)
protected override DependencyObject CreateShell()
{
// I am assuming you have a reference to the DI container
var regionManager = this.Container.Resolve<IRegionManager>();
return new Shell(regionManager);
}
Для других оболочек это будет сделано с помощью CreateNewShellCommand
:
private static ExecuteCreateNewShellCommand()
{
// I am assuming you have a reference to the DI container
var regionManager = this.Container.Resolve<IRegionManager>();
ver newRegionManager = regionManager.CreateRegionManager();
var shell = new Shell(newRegionManager);
// The rest is easy, for example:
shell.Show();
}
Здесь существует важная оговорка: RegionManager
зарегистрирован в контейнере как однострочный. Это означает, что всякий раз, когда вы разрешаете IRegionManager
, вы получите тот же экземпляр. По этой причине мы создаем новый экземпляр, вызывая метод IRegionManager.CreateRegionManager
(это относится к Prism v4; я не уверен относительно v2).
На этом этапе вы знаете, как создать любое количество новых экземпляров Shell
и соответствующим образом подключить регионы.
Детали композиции пользовательского интерфейса
Последняя деталь, о которой вам нужно позаботиться, состоит в том, что все регионы, размещенные в каждой оболочке, независимо от того, насколько глубоко в ее визуальном дереве, должны привязываться к тому же RegionManager
.
Это означает, что вы должны явно указать менеджер регионов, как это было в примере ContentControl
выше для всех регионов во всех представлениях в вашем приложении. К счастью, это делается довольно легко, потому что:
- Все представления в конечном итоге будут потомками
Shell
в визуальном дереве -
Shell
уже предоставляет правильныйRegionManager
как свойство, поэтому мы можем привязываться к этому
Вы бы сделали так:
<ItemsControl
regions:RegionManager.RegionManager="{Binding RegionManager, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Shell}}}"
regions:RegionManager.RegionName="AnotherRegion"
/>
Все настройки!
Теперь вы должны быть готовы к работе.