У меня проблема с Prism 7.1, настольным WPF-приложением, в котором я использую Navigation для загрузки вида в один регион («Основной») и связанный набор инструментов во второй регион («Инструменты»).Короткая версия состоит в том, что я заново сделал макет окна, и Prism теперь говорит мне, что области «Инструменты» больше нет.
Это приложение, в основном
-----------------------------------------------------
| "Explore" | |
| "Analyze" | ("Main" region. Shows |
| "Configure" | whichever view was selected |
|-------------| on the top left) |
| ("Tools" | |
| region) | |
-----------------------------------------------------
Пользователь нажимает кнопку навигации (например, «Анализ», «Настроить» и т. Д.), И я использую Prism, чтобы перейти в основной регион к соответствующему виду из соответствующего модуля.Эта часть все еще работает.
У меня также есть RegionBehavior, который заставляет «Инструменты» переходить к отдельному представлению, связанному с основным.(Обнаружил этот подход в курсе PluralSight под названием « Проблемы и решения Prism: загрузка зависимых представлений »).
Это работало нормально, когда у меня был уродливый макет с сеткой с парой ContentControls и соответствующими именами регионов.Но сегодня я попытался заменить это на Telerik RadNavigationView.Основной вид по-прежнему хорошо отображается, но вид «Инструменты» теперь не отображается.
Непосредственная причина ясна: у моего RegionBehavior больше нет области «Инструменты», в которую можно поместить представление связанных инструментов.RegionManager говорит, что его там нет.Несмотря на то, что я по-прежнему четко обозначаю его имя в ContentControl, как и раньше.
Но основная причина неясна.Существует еще ContentControl с именем региона «Инструменты».Так почему же Prism не создает (или не добавляет) этот регион?Могу ли я заставить его?
Это старый XAML, который работал:
<Grid Background="{StaticResource GsBackgroundDark}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <!-- Navigation/Tools Panel -->
<ColumnDefinition Width="*"/> <!-- Page Content Region -->
</Grid.ColumnDefinitions>
<!-- Left column has navigation buttons above a Prism region for "tools" -->
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- Navigation Buttons -->
<RowDefinition Height="*"/> <!-- Tools Region -->
</Grid.RowDefinitions>
<!-- Traditional list of category buttons used to navigate ItemTemplate left out (not relevant) -->
<ItemsControl ItemsSource="{Binding AvailablePages, IsAsync=True}"/>
<!-- "Tools" pane Content Control, bottom left-->
<Grid Grid.Row="1">
<ContentControl prism:RegionManager.RegionName="Tool"/>
</Grid>
</Grid>
<!-- Main Content on the right. -->
<ContentControl Grid.Column="1" Grid.Row="1" prism:RegionManager.RegionName="Main"/>
</Grid>
Это новый XAML RadNavigationView, который работает , а не .(Я попытался поместить раздел «Инструменты» в элемент PaneFooter)
<Grid Background="{StaticResource GsBackgroundDark}">
<tk:RadNavigationView x:Name="GridView"Background="Transparent"
ItemsSource="{Binding Items}" SelectedItem="{Binding CurrentItem}">
<tk:RadNavigationView.Content>
<ContentControl prism:RegionManager.RegionName="Main"/>
</tk:RadNavigationView.Content>
<tk:RadNavigationView.PaneFooter>
<ContentControl Grid.Column="0" prism:RegionManager.RegionName="Tool" />
</tk:RadNavigationView.PaneFooter>
</tk:RadNavigationView>
Остальная часть кода (ниже) не изменилась, но я помещаю его здесь, чтобы вы могли увидеть, что он делает.
«Основные» представления определяют связанные виды инструментов с помощью атрибута.Например, вот «AnalyzeView»:
[PageTool(typeof(AnalyzeViewTools))] // Associate AnalyzeViewTools with this view
public partial class AnalyzeView
: UserControl
, IPageView
, ISupportDataContext
{
// blah blah blah....
}
public partial class AnalyzeViewTools : UserControl, ISupportDataContext
{
// blah blah blah...
}
Это атрибут, о котором идет речь:
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true)]
public class PageToolAttribute : Attribute
{
public Type Type { get; }
public PageToolAttribute(Type toolType) { Type = toolType; }
}
И, наконец, это поведение региона, которое я регистрирую во время запуска приложения и котороевыполняет загрузку связанных видов инструментов.Я отметил строку, которая теперь терпит неудачу с «ЭТО СКАЧИ СЕЙЧАС»
public class ToolRegionBehavior : RegionBehavior
{
public const string BehaviorKey = "ToolRegionBehavior";
protected override void OnAttach()
{
// Our behavior monitors the region's ActiveView collection.
if (Region.Name == Regions.Main)
Region.ActiveViews.CollectionChanged += Views_CollectionChanged;
}
// A view has been added or removed. Make the tools panel reflect this
private void Views_CollectionChanged(
object sender,
NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
// For each view now showing (there should be only one), try to
// find a tools view for it. If we find one, inject it into the
// tools region. Views are not required to have associated Tool Panels.
Debug.Assert(e.NewItems.Count == 0 || e.NewItems.Count == 1);
foreach (var view in e.NewItems)
{
var toolList = new List<UserControl>();
// If this view supports a tools panel, it will have an attribute
// So... if you want to add a tool panel to a view, you need
// to specify this same attribute, just as, for example,
// OldAnalyzeViewPanel does.
foreach (var atr in GetCustomAttributes<PageToolAttribute>(view.GetType()))
{
var tool = Activator.CreateInstance(atr.Type) as UserControl;
// If the tool indicates that it wants to share the view's
// data context, then pass it over. (It indicates this
// by supporting an interface.)
if (tool is ISupportDataContext toolCtx && view is ISupportDataContext viewCtx)
toolCtx.DataContext = viewCtx.DataContext;
toolList.Add(tool);
}
// ***************************************
// **** THIS FAILS NOW NO SUCH REGION ***
// ***************************************
if (Region.RegionManager.Regions.ContainsRegionWithName("Tool"))
toolList.ForEach(x => Region.RegionManager.Regions["Tool"].Add(x));
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
// A view was removed from the main region. Remove the
// corresponding tool view we previously injected, if any. At
// most there should be one.
if (!Region.RegionManager.Regions.ContainsRegionWithName("Tool"))
return;
var region = Region.RegionManager.Regions["Tool"];
region.Views.ToList().ForEach(x => region.Remove(x));
}
}
// Helper to get attribute off of views
private static IEnumerable<T> GetCustomAttributes<T>(Type type)
{
return type.GetCustomAttributes(typeof(T), true).OfType<T>();
}
}