Создание нескольких оболочек - правильная идея. Вам просто нужно позаботиться о деталях.
Когда и как создать новую оболочку
Способ 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"
/>
Все готово!
Теперь вы должны быть готовы к работе.