【问题标题】:New shell/window in Prism/WPF shows wrong viewPrism/WPF 中的新外壳/窗口显示错误视图
【发布时间】:2019-10-13 03:00:42
【问题描述】:

this answer 的启发,我创建了一个像这样的通用 Shell(Prism、WPF):

<Window x:Class="VRMDataLogger.UI.Shell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" Title="My App" Height="450" Width="800">
    <Grid>
        <ContentControl prism:RegionManager.RegionManager="{Binding RegionManager}" prism:RegionManager.RegionName="MainShellRegion" />
    </Grid>
</Window>
public partial class Shell : Window
{
    public Shell(IRegionManager regionManager, Type contentType)
    {
        RegionManager = regionManager;
        InitializeComponent();
        RegionManager.RegisterViewWithRegion("MainShellRegion", contentType);
    }

    public IRegionManager RegionManager { get; }
}

初始 shell 在 App.CreateShell(): 中创建:

protected override Window CreateShell()
{
    return new Shell(Container.Resolve<IRegionManager>(), typeof(StartScreen));
}

这工作正常,正确的视图显示在初始外壳中。

然后我尝试从 StartScreenViewModel 创建第二个 Shell,它显示了不同的视图:

var shell = new Shell(RegionManager.CreateRegionManager(), typeof(MainScreen));
shell.Show();

这会打开一个新窗口,但它会显示与第一个窗口 (StartScreen) 相同的视图,而不是 MainScreen。我在这里做错了什么?

【问题讨论】:

  • 这两个附加属性可能会相互干扰,导致有效使用了错误的区域管理器...只是猜测...您可以尝试从代码隐藏中设置所有内容吗?喜欢这里:stackoverflow.com/questions/41212881/…
  • @Haukinger 感谢您的建议。不幸的是,它没有帮助。我删除了绑定,并将 x:Name 添加到 ContentControl。然后在后面的代码中我使用了 SetRegionName 和 SetRegionManager。但它仍然以与以前相同的方式运行。现在将尝试 mm8 的建议。
  • 问题:如果区域名称无关紧要,而且您只使用一个区域,为什么要使用一个区域?您可以在 shell 视图中放置一个属性 object ContentViewModel { get; } 并将其绑定到内容控件。据我所知,区域的好处是导航和从任何提供一些(通过注册)的模块收集内容。如果两者都不使用,则一开始就不需要该区域。
  • 好问题。我是 Prism 的新手,并尝试使事情尽可能简单(目前)。所以我也在考虑摆脱区域的东西。但我认为这样做会失去将依赖注入到我的视图模型中的好功能 - 还是我错了?
  • 你错了。如果你总是有一个主窗口,你也根本不需要那些 shell 的东西。

标签: wpf mvvm prism prism-7


【解决方案1】:

所以我也在考虑摆脱区域的东西。但我认为这样做会失去将依赖注入到我的视图模型中的好功能

一点也不。事实上,您可以更好地控制视图模型的创建方式。

当采用视图优先时,您的视图模型通常由 ViewModelLocator 在导航时创建,然后传递 NavigationParameters(如果有)。

如果您手动创建视图模型并通过数据模板绑定视图,则您可以完全控制视图模型的创建。最简单的选择是为视图模型注入一个工厂(例如Func&lt;MainScreenViewModel&gt;),然后从容器中获得完全的依赖注入。

internal class StartScreenViewModel
{
    public StartScreenViewModel( Func<MainScreenViewModel> mainScreenViewModelFactory )
    {
        GoToMainScreenCommand = new DelegateCommand( () => new Shell( mainScreenViewModelFactory() ).Show() );
    }

    public DelegateCommand GoToMainScreenCommand { get; }
}

当然,如果需要,您可以使用更复杂的手工工厂(请参阅this answer)。

【讨论】:

    【解决方案2】:

    尝试为每个 shell 使用唯一的区域名称:

    public partial class Shell : Window
    {
        public Shell(IRegionManager regionManager, Type contentType)
        {
            RegionManager = regionManager;
            InitializeComponent();
            MainRegionName = Guid.NewGuid().ToString();
            RegionManager.RegisterViewWithRegion(MainRegionName, contentType);
        }
    
        public string MainRegionName { get; }
        public IRegionManager RegionManager { get; }
    
    }
    

    XAML:

    <ContentControl prism:RegionManager.RegionManager="{Binding RegionManager}"
                    prism:RegionManager.RegionName="{Binding MainRegionName, RelativeSource={RelativeSource AncestorType=Window}}" />
    

    【讨论】:

    • 感谢@mm8 的回答。这让我更进一步。但是有两件事让我感到恼火:(1)如果我们真的为两个 shell 分别设置了一个 IRegionManager,那么(理论上)每个 shell 都不需要使用不同的名称。 (2) 当我在MainScreenViewModel 上实现INavigationAware(以访问导航上下文)时,OnNavigatedTo 处理程序永远不会被触发。我想知道这是否是因为区域经理仍然有一些奇怪的事情发生......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多