首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >两次创建棱镜/WPF视图/视图模型

两次创建棱镜/WPF视图/视图模型
EN

Stack Overflow用户
提问于 2020-06-13 13:23:45
回答 2查看 930关注 0票数 0

我有一个Prism 7/ WPF / MVVM应用程序,在具有视图模型的视图中配置了AutowireViewModel="True“。我的大多数视图模型都有我在Prism统一容器中配置的依赖项,并且这些依赖项被注入到viewmodel结构器中。我没有在任何地方的代码中显式地创建视图/视图模型的实例。我也不设置XAML中的数据上下文,即使用DataContext元素或d:DataContext)。XAML中唯一的引用是视图(即HamburgerMenu控件的一部分)。

除了每个视图/视图模型总是因为某种原因被构造两次之外,所有这些都很正常,不管这是主窗口,还是模块中的视图。我在模块管理器中放置了断点(只被击中一次)--以及视图构造函数和视图模型构造函数,它们都被击中了两次。下面是App类的一些代码,以及在运行时加载而不是按需加载的名为消息传递的模块的代码/view/viewmodel。由于希望尽可能多地使用MVVM模式,所以视图后面的代码非常少。注意:我试着看看这是否仅仅是启动时加载的模块的视图的问题,但是按需加载的模块也存在相同的命运。

App/PrismApplication类全文如下:

代码语言:javascript
复制
public partial class App : PrismApplication
{
    private ILoggerFactory loggerFactory;
    private TaskbarIcon _taskbarIcon;

    protected override Window CreateShell()
    {
        // Register an instance of the Window (used by the dialog service to get a handle on the window when displaying dialogs)
        Container.GetContainer().RegisterInstance(typeof(Window), "MainWindow", Container.Resolve<MainWindow>(), new ContainerControlledLifetimeManager());

        return Container.Resolve<MainWindow>();
    }

    protected override void OnInitialized()
    {
        base.OnInitialized();

        // Create the links to each module for the banner view to display
        var menuService = Container.Resolve<IMenuService>();
        var regionManager = Container.Resolve<IRegionManager>();

        menuService.AddItem("Home", "Home", () => regionManager.RequestNavigate("MainRegion", "HomeMainView"));
        menuService.AddItem("Messaging", "Messaging", () => regionManager.RequestNavigate("MainRegion", "MessagingMainView"));
        menuService.AddItem("Charts", "Charts", () => regionManager.RequestNavigate("MainRegion", "ChartsMainView"));
        menuService.AddItem("Admin", "Admin", () => regionManager.RequestNavigate("MainRegion", "AdminMainView"));

        // Register banner view with region manager and display it
        regionManager.RegisterViewWithRegion("BannerRegion", typeof(BannerView));

        // Load the desired module into the main window on start up
        Container.Resolve<IRegionManager>().RequestNavigate("MainRegion", "HomeMainView");
    }

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        var container = this.ConfigureLogging(containerRegistry);

        // Register types 
        container.RegisterInstance<IDbConnectionFactory>(
            new SqlConnectionFactory(
                ConfigurationManager.ConnectionStrings["Messaging"].ConnectionString,
                loggerFactory));            

        /************************************************************/
        // TODO: Not sure if need singletons or not - to test......
        /************************************************************/
        containerRegistry.RegisterSingleton<IMetroMessageDisplayService, MetroMessageDisplayService>();
        containerRegistry.RegisterSingleton<IUserService, UserService>();
        containerRegistry.RegisterSingleton<IUserStore, UserStore>();
        containerRegistry.RegisterSingleton<IMenuService, MenuService>();
        containerRegistry.Register<ICustomerService, CustomerService>();
        containerRegistry.Register<INotifyIconService, NotifyIconService>();
        containerRegistry.RegisterDialog<DefaultDialog, DefaultDialogViewModel>("Default");
        containerRegistry.RegisterDialog<HtmlDialog, HtmlDialogViewModel>("Html");

        // Get the current user's details - prevent a deadlock in the way we use Task.Run(...).Result
        // Then add to container as we will be injecting into VMs
        var clientUser = Task.Run(GetCurrentUserDetails).Result;

        containerRegistry.RegisterInstance(clientUser);
        containerRegistry.RegisterSingleton<IClientUser, ClientUser>();

        // Add the task bar icon
        _taskbarIcon = (TaskbarIcon)FindResource("NotifyIcon");
        containerRegistry.RegisterInstance(_taskbarIcon);

        // Create a logger instance
        var logger = loggerFactory.CreateLogger<App>();

        logger.LogDebug("Finished registering types in App.xaml.cs");
    }

    private async Task<ClientUser> GetCurrentUserDetails()
    {
        var userService = Container.Resolve<IUserService>();
        var data = await userService.GetClientUsersAsync(ConfigurationManager.AppSettings.Get("TempUserName")).ConfigureAwait(true);

        if (!data.Any())
        {
            // log unable to load user from database then return as no point in loading messages for a user that cannot be found!!
            return null;
        }

        return data.FirstOrDefault();
    }

    protected override IModuleCatalog CreateModuleCatalog()
    {
        // We are returning a type that reads the modules from the config file.
        return new ConfigurationModuleCatalog();
    }

    protected override void OnExit(ExitEventArgs e)
    {
        // The icon would clean up automatically, but this is cleaner
        _taskbarIcon.Dispose();

        base.OnExit(e);
    }

    private IUnityContainer ConfigureLogging(IContainerRegistry containerRegistry)
    {
        // Configure logging - Needed Unity.Microsoft.Logging package 
        // see https://github.com/unitycontainer/microsoft-logging and https://github.com/unitycontainer/examples/tree/master/src/Logging/Microsoft.Logging
        var serilogLogger = new LoggerConfiguration()
            .ReadFrom.AppSettings()
            .CreateLogger();

        this.loggerFactory = new LoggerFactory().AddSerilog(serilogLogger);

        var container = containerRegistry.GetContainer();
        container.AddExtension(new LoggingExtension(loggerFactory));

        return container;
    }
}

消息传递模块:

代码语言:javascript
复制
public class MessagingModule : IModule
{
    public void OnInitialized(IContainerProvider containerProvider)
    {
        // Register main view with region manager
        var regionManager = containerProvider.Resolve<IRegionManager>();
        regionManager.RegisterViewWithRegion("MainRegion", typeof(MessagingMainView));
    }

    public void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.RegisterSingleton<IMessageStore, MessageStore>();
        containerRegistry.RegisterSingleton<IMessageService, MessageService>();
        containerRegistry.RegisterSingleton<IChatService, ChatService>();
        containerRegistry.RegisterSingleton<IFileDialogService, FileDialogService>();
        containerRegistry.RegisterDialog<InboxMessageView, InboxMessageViewModel>("HtmlMessage");

        // Here we are loading the config/settings from the app.config for this module so we
        // can register a ChatServiceConfiguration type as it is injected into ChatService
        var filename = Assembly.GetExecutingAssembly().Location;

        var configuration = ConfigurationManager.OpenExeConfiguration(filename);

        if (configuration != null)
        {
            var hubUrl = configuration.AppSettings.Settings["HubUrl"].Value;

            if (string.IsNullOrEmpty(hubUrl))
            {
                throw new ArgumentException("The HubUrl app setting cannot ne null or whitespace.");
            }

            containerRegistry.RegisterInstance(new ChatServiceConfiguration(hubUrl));
            containerRegistry.RegisterSingleton<IChatServiceConfiguration, ChatServiceConfiguration>();
        }
    }
}

MessagingMainView:

代码语言:javascript
复制
<UserControl x:Class="Ascensos.Wpf.Modules.Messaging.Views.MessagingMainView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
         xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
         xmlns:materialDesignConverters="clr-namespace:MaterialDesignThemes.Wpf.Converters;assembly=MaterialDesignThemes.Wpf"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:views="clr-namespace:Ascensos.Wpf.Modules.Messaging.Views"
         xmlns:helpers="clr-namespace:Ascensos.Wpf.Modules.Messaging.Helpers"
         xmlns:prism="http://prismlibrary.com/"
         prism:ViewModelLocator.AutoWireViewModel="True"
         d:DesignHeight="300"
         d:DesignWidth="400"
         mc:Ignorable="d">

</UserControl>

背后的代码:

代码语言:javascript
复制
public sealed partial class MessagingMainView : UserControl
{
    public MessagingMainView()
    {
        this.InitializeComponent();
    }
}

viewmodel (调用基本消息视图模型类):

代码语言:javascript
复制
public sealed class MessagingMainViewModel
{
    public MessagingMainViewModel()
    {            
    }
}

更新:我已经从我的应用程序中删除了代码,所以只有上面的代码在视图和视图模型中。在模块初始化期间,视图构造函数和viewmodel构造函数仍然被击中两次。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-06-13 17:25:34

我发现了这个问题。它是App CreateShell()方法中的一行:

代码语言:javascript
复制
Container.GetContainer().RegisterInstance(typeof(Window), "MainWindow", Container.Resolve<MainWindow>(), new ContainerControlledLifetimeManager());

注释掉这个问题已经解决了问题。再看一遍,我很傻,没有注意到这一点,就像我是新手一样。添加了这段代码,这样我就可以在服务类中访问MainWindow/MetroWindow --但是我需要尝试另一种方法。谢谢你抽出时间@豪金杰。

票数 0
EN

Stack Overflow用户

发布于 2020-06-13 14:29:15

我没有在任何地方(即仅在XAML中)代码中显式地创建视图/视图模型的实例。

这是一个矛盾--在xaml中创建视图模型意味着以与后面或其他任何地方的代码相同的方式创建视图模型。

就像前面说的,别这么做。也从xaml中删除对视图模型构造函数的所有引用(如<DataContext><MyViewViewModel/></DataContext>)。要在xaml中获取intellisense,请使用d:DataContext

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62360352

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档