Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我应该在MVVM项目中使用其他容器吗?_C#_.net_Wpf_Xaml_Mvvm - Fatal编程技术网

C# 我应该在MVVM项目中使用其他容器吗?

C# 我应该在MVVM项目中使用其他容器吗?,c#,.net,wpf,xaml,mvvm,C#,.net,Wpf,Xaml,Mvvm,示例项目的来源: 我在WPF MVVM中做了一个项目。它有三个子项目:WPF应用程序、ViewModels(PCL)和Domain(PCL)。WPF只是一个单一的窗口,有一个框架和两个页面。我将展示代码,但建议在repo中克隆/分叉我准备好的示例 以下是WPF客户端的代码: App.xaml.cs namespace NaviWPFApp { using System.Windows; using NaviWPFApp.Views; using NaviWPFApp.Vi

示例项目的来源:

我在WPF MVVM中做了一个项目。它有三个子项目:WPF应用程序、ViewModels(PCL)和Domain(PCL)。WPF只是一个单一的
窗口
,有一个
框架
和两个
页面
。我将展示代码,但建议在repo中克隆/分叉我准备好的示例

以下是WPF客户端的代码:

App.xaml.cs

namespace NaviWPFApp
{
    using System.Windows;
    using NaviWPFApp.Views;
    using NaviWPFApp.Views.Pages;   

    public partial class App : Application
    {
        public static NavigationService Navigation; 

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);  

            MainWindow mainWindow = new MainWindow();
            mainWindow.Show();  

            Navigation = new NavigationService(mainWindow.MyFrame);
            Navigation.Navigate<FirstPage>();
        }
    }
}
我的业务逻辑是:

public class BusinessLogic
{
    private int counter = 0;

    public bool CountSomething()
    {
        return ++counter > 10;
    }
}
依赖关系很简单:除了自己的操作之外,什么都不知道,视图模型知道域,但对视图和视图却一无所知。。。好吧,这是我的问题-它知道ViewModel,但View应该知道域吗?我会解释我的担忧,但我的意思是:

第一个问题:如您所见,导航都在ViewModel中完成,业务逻辑仅在第二个页面视图模型中使用。SecondPage视图不需要了解逻辑

第二个问题:因为我试图坚持依赖注入,所以我想在程序开始时创建我的域对象(我只需要一个)。因此在
受保护的override void OnStartup(StartupEventArgs e)
中,因此在视图中。我不知道如何将它传递给第二个视图模型,它是在
ViewModelLocator
中创建的

所以我的问题是:如何转换这段代码,使它更加面向ViewModel?我只想将我的域对象注入ViewModel(它所属的位置),而不是视图


谢谢你的建议

简单的回答是,您无法避免它,尤其是当您使用依赖注入/IoC容器时(建议使用该容器来解耦代码并提高可测试性)

您无法避免这种情况的原因是(在使用IoC时)您需要通过构造函数(或者通过属性/方法)注入依赖项。大多数IoC容器都要求这些是公共的

由于以这种方式注入的大多数类型不在ViewModel PCL中,而是在模型(域)中,并且是公开可见的,因此需要对程序集的引用,即使您没有手动初始化ViewModels

你的困惑来自“观点”。在本例中,您的WPF项目有多个角色

  • 它用所有视图(XAML文件)表示视图层
  • 此外,应用程序代码位于同一项目/程序集中。应用程序代码类似于
    NavigationService
    implementation(
    INavigationService
    接口属于ViewModel组件)

  • 虽然您的视图不需要任何对域类的引用,但您的应用程序需要(组合根目录、DI/IoC容器)。

    简而言之,您无法避免它,尤其是如果您使用依赖项注入/IoC容器(建议将代码解耦并提高可测试性)

    您无法避免这种情况的原因是(在使用IoC时)您需要通过构造函数(或者通过属性/方法)注入依赖项。大多数IoC容器都要求这些是公共的

    由于以这种方式注入的大多数类型不在ViewModel PCL中,而是在模型(域)中,并且是公开可见的,因此需要对程序集的引用,即使您没有手动初始化ViewModels

    你的困惑来自“观点”。在本例中,您的WPF项目有多个角色

  • 它用所有视图(XAML文件)表示视图层
  • 此外,应用程序代码位于同一项目/程序集中。应用程序代码类似于
    NavigationService
    implementation(
    INavigationService
    接口属于ViewModel组件)

  • 虽然您的视图不需要对域类进行任何引用,但您的应用程序确实需要(合成根,DI/IoC容器)。

    您无法避免这种依赖关系,因为
    App.OnStartup
    是合成根,这意味着
    App.OnStartup
    知道一切。 但是,你可以避免的是应用程序中的这个全局道具:
    公共静态导航服务导航。您可以简单地将它注入到需要它的对象中

    第一个问题:正如您所看到的,导航都是在中完成的 ViewModel,业务逻辑仅在第二个页面视图模型中使用。 SecondPage视图不需要了解逻辑

    SecondPage不必了解业务对象。应用程序必须知道。所以,您可以将对象注入定位器,定位器可以在时机成熟时将此对象注入特定的ViewModel

    第二个问题:因为我正努力坚持依赖注入, 我想创建我的域对象(我只需要一个) 节目开始了。因此,在受保护的覆盖无效 启动时(StartupEventArgs e),因此在视图中。我也不知道该怎么做 将其传递给在ViewModelLocator中创建的第二个视图模型

    依赖注入

    我是这样做的:

    public class ViewModelLocator
    {
        private NavigationService navigationService;
        private BusinessLogic businessLogic;
        public void InjectNavigationService(NavigationService navigation)
        {
            navigationService = navigation;
        } 
        public void InjectBusinessLogic(BusinessLogic logic)
        {
            businessLogic = logic;
        } 
    
        public FirstPageViewModel FirstPageViewModel => new FirstPageViewModel(navigationService);
        public SecondPageViewModel SecondPageViewModel => new SecondPageViewModel(navigationService, businessLogic);
    }
    
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
    
            // Create/resolve all your objects in Comoposition Root:
            var businessLogic = new BusinessLogic();
    
            // Here you will have locator created already, but mainWindow has not been created yet
            // Retrive your locator
            ViewModelLocator locator = Resources.Values.OfType<ViewModelLocator>().FirstOrDefault();
            if (locator == null)
                throw new NoNullAllowedException("ViewModelLocator cannot be null.");
    
            MainWindow mainWindow = new MainWindow();
            var navigation = new NavigationService(mainWindow.MyFrame);
    
            // Inject your logic and navigation into locator
            locator.InjectBusinessLogic(businessLogic);
            locator.InjectNavigationService(navigation);
    
            // Set up first page
            navigation.Navigate<FirstPage>();
    
            // and show the window
            mainWindow.Show();
        }
    }
    
    公共类ViewModelLocator
    {
    私人导航服务导航服务;
    私有业务逻辑;
    公共导航服务(导航服务导航)
    {
    导航服务=导航;
    } 
    公共业务逻辑(BusinessLogic逻辑)
    {
    业务逻辑=逻辑;
    } 
    public FirstPageViewModel FirstPageViewModel=>新的FirstPageViewModel(导航服务);
    public SecondPageViewModel SecondPageViewModel=>new SecondPageViewModel(导航服务、业务逻辑);
    }
    公共部分类应用程序:应用程序
    {
    启动时受保护的覆盖无效(StartupEventArgs e)
    {
    基础。启动时(e);
    //在根目录中创建/解析所有对象:
    var businessLogic=new businessLogic();
    //这里有定位器crea
    
    namespace NaviWPFApp
    {
        using NaviWPFApp.ViewModels.Pages;  
    
        public class ViewModelLocator
        {
            public FirstPageViewModel FirstPageViewModel => new FirstPageViewModel(App.Navigation);
            public SecondPageViewModel SecondPageViewModel => new SecondPageViewModel(App.Navigation);
        }
    }   
    
    namespace NaviWPFApp
    {
        using System;
        using System.Linq;
        using System.Reflection;
        using System.Windows.Controls;
        using NaviWPFApp.ViewModels.Common; 
    
        public class NavigationService : INavigationService
        {
            readonly Frame frame;   
    
            public NavigationService(Frame frame)
            {
                this.frame = frame;
            }   
    
            public void GoBack()
            {
                frame.GoBack();
            }   
    
            public void GoForward()
            {
                frame.GoForward();
            }   
    
            public bool Navigate(string page)
            {
                var type = Assembly.GetExecutingAssembly().GetTypes().SingleOrDefault(a => a.Name.Equals(page));
                if (type == null) return false; 
    
                var src = Activator.CreateInstance(type);
                return frame.Navigate(src);
            }
    
            public bool Navigate<T>(object parameter = null)
            {
                var type = typeof(T);
                return Navigate(type, parameter);
            }
    
            public bool Navigate(Type source, object parameter = null)
            {
                var src = Activator.CreateInstance(source);
                return frame.Navigate(src, parameter);
            }
        }
    }
    
    public interface INavigationService
    {
        void GoForward();
        void GoBack();
        bool Navigate(string page);
    }
    
    
    namespace NaviWPFApp.ViewModels
    {
        public class FirstPageViewModel : MyObservableObject
        {
            private readonly INavigationService navigationService;
    
            public FirstPageViewModel(INavigationService navigationService)
            {
                this.navigationService = navigationService;
            }
    
            public MyCommand GoToSecondPageCommand
            {
                get { return new MyCommand(x => navigationService.Navigate("SecondPage")); }
            }
        }
    }   
    
    namespace NaviWPFApp.ViewModels
    {
        public class SecondPageViewModel : MyObservableObject
        {
            private readonly INavigationService navigationService;
            private readonly BusinessLogic businessLogic;   
    
            public SecondPageViewModel(INavigationService navigationService, BusinessLogic businessLogic = null)
            {
                this.navigationService = navigationService;
                this.businessLogic = businessLogic;
            }   
    
            public MyCommand BackToFirstPageCommand
            {
                get { return new MyCommand(x => navigationService.Navigate("FirstPage")); }
            }   
    
            public MyCommand CountSomethingCommand
            {
                get { return new MyCommand(x => businessLogic?.CountSomething()); }
            }
        }
    }
    
    public class BusinessLogic
    {
        private int counter = 0;
    
        public bool CountSomething()
        {
            return ++counter > 10;
        }
    }
    
    public class ViewModelLocator
    {
        private NavigationService navigationService;
        private BusinessLogic businessLogic;
        public void InjectNavigationService(NavigationService navigation)
        {
            navigationService = navigation;
        } 
        public void InjectBusinessLogic(BusinessLogic logic)
        {
            businessLogic = logic;
        } 
    
        public FirstPageViewModel FirstPageViewModel => new FirstPageViewModel(navigationService);
        public SecondPageViewModel SecondPageViewModel => new SecondPageViewModel(navigationService, businessLogic);
    }
    
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
    
            // Create/resolve all your objects in Comoposition Root:
            var businessLogic = new BusinessLogic();
    
            // Here you will have locator created already, but mainWindow has not been created yet
            // Retrive your locator
            ViewModelLocator locator = Resources.Values.OfType<ViewModelLocator>().FirstOrDefault();
            if (locator == null)
                throw new NoNullAllowedException("ViewModelLocator cannot be null.");
    
            MainWindow mainWindow = new MainWindow();
            var navigation = new NavigationService(mainWindow.MyFrame);
    
            // Inject your logic and navigation into locator
            locator.InjectBusinessLogic(businessLogic);
            locator.InjectNavigationService(navigation);
    
            // Set up first page
            navigation.Navigate<FirstPage>();
    
            // and show the window
            mainWindow.Show();
        }
    }