热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何在WPF/MVVM应用程序中处理依赖项注入?-HowtohandledependencyinjectioninaWPF/MVVMapplication

IamstartinganewdesktopapplicationandIwanttobuilditusingMVVMandWPF.我正在启动一个新的桌面应用程序,我

I am starting a new desktop application and I want to build it using MVVM and WPF.

我正在启动一个新的桌面应用程序,我想使用MVVM和WPF来构建它。

I am also intending to use TDD.

我也打算使用TDD。

The problem is that I don´t know how I should use an IoC container to inject my dependencies on my production code.

´问题是我不知道我应该使用IoC容器注入我依赖我的产品代码。

Suppose I have the folowing class and interface:

假设我有folowing类和接口:

public interface IStorage
{
    bool SaveFile(string content);
}

public class Storage : IStorage
{
    public bool SaveFile(string content){
        // Saves the file using StreamWriter
    }
}

And then I have another class that has IStorage as a dependency, suppose also that this class is a ViewModel or a business class...

然后我有另一个类,它将IStorage作为一个依赖项,假设这个类是一个ViewModel或一个business类……

public class SomeViewModel
{
    private IStorage _storage;

    public SomeViewModel(IStorage storage){
        _storage = storage;
    }
}

With this I can easily write unit tests to ensure that they are working properly, using mocks and etc.

有了这个,我可以很容易地编写单元测试,以确保它们能够正常工作,使用模拟等等。

The problem is when it comes to use it in the real application. I know that I must have an IoC container that links a default implementation for the IStorage interface, but how may I to do it?

问题是当它在实际应用程序中使用时。我知道我必须有一个IoC容器来链接IStorage接口的默认实现,但是我要怎么做呢?

For example, how would it be if I had the following xaml:

例如,如果我有以下的xaml:


   
        
   

How can I correctly 'tell' WPF to inject dependencies in that case?

在这种情况下,如何正确地“告诉”WPF注入依赖项?

Also, suppose I need an instance of SomeViewModel from my cs code, how should I do it?

另外,假设我需要一个来自cs代码的SomeViewModel的实例,我该如何做呢?

I feel I´m completely lost in this, I would appreciate any example or guidance of how is the best way to handle it.

我觉得我´m完全迷失在这,我将不胜感激任何例子或指导的是最好的方法来处理它。

I am familiar with StructureMap, but I´m not an expert. Also, if there is a better/easier/out-of-the-box framework, please let me know.

我熟悉StructureMap,但我´m不是专家。此外,如果有更好的/更容易的/开箱即用的框架,请让我知道。

Thanks in advance.

提前谢谢。

8 个解决方案

#1


63  

I have been using Ninject, and found that it's a pleasure to work with. Everything is set up in code, the syntax is fairly straightforward and it has a good documentation (and plenty of answers on SO).

我一直在使用Ninject,我发现和他一起工作很愉快。所有的东西都是在代码中设置的,语法非常简单,并且有很好的文档(并且有大量的答案)。

So basically it goes like this:

基本上是这样的:

Create the view model, and take the IStorage interface as constructor parameter:

创建视图模型,并以IStorage接口作为构造函数参数:

class UserControlViewModel
{
    public UserControlViewModel(IStorage storage)
    {

    }
}

Create a ViewModelLocator with a get property for the view model, which loads the view model from Ninject:

为视图模型创建一个带有get属性的ViewModelLocator,它将从Ninject加载视图模型:

class ViewModelLocator
{
    public UserControlViewModel UserControlViewModel
    {
        get { return IocKernel.Get();} // Loading UserControlViewModel will automatically load the binding for IStorage
    }
}

Make the ViewModelLocator an application wide resource in App.xaml:

将ViewModelLocator设置为App.xaml中的应用程序范围资源:


    
        
    

Bind the DataContext of the UserControl to the corresponding property in the ViewModelLocator.

将UserControl的DataContext绑定到ViewModelLocator中的相应属性。


    
    

Create a class inheriting NinjectModule, which will set up the necessary bindings (IStorage and the viewmodel):

创建一个继承NinjectModule的类,它将设置必要的绑定(IStorage和viewmodel):

class IocConfiguration : NinjectModule
{
    public override void Load()
    {
        Bind().To().InSingletonScope(); // Reuse same storage every time

        Bind().ToSelf().InTransientScope(); // Create new instance every time
    }
}

Initialize the IoC kernel on application startup with the necessary Ninject modules (the one above for now):

在应用程序启动时,使用必要的Ninject模块(上面的模块)初始化IoC内核:

public partial class App : Application
{       
    protected override void OnStartup(StartupEventArgs e)
    {
        IocKernel.Initialize(new IocConfiguration());

        base.OnStartup(e);
    }
}

I have used a static IocKernel class to hold the application wide instance of the IoC kernel, so I can easily access it when needed:

我使用了一个静态的IocKernel类来保存IoC内核的应用程序范围的实例,所以我可以在需要的时候很容易地访问它:

public static class IocKernel
{
    private static StandardKernel _kernel;

    public static T Get()
    {
        return _kernel.Get();
    }

    public static void Initialize(params INinjectModule[] modules)
    {
        if (_kernel == null)
        {
            _kernel = new StandardKernel(modules);
        }
    }
}

This solution does make use of a static ServiceLocator (the IocKernel), which is generally regarded as an anti-pattern, because it hides the class' dependencies. However it is very difficult to avoid some sort of manual service lookup for UI classes, since they must have a parameterless constructor, and you cannot control the instantiation anyway, so you cannot inject the VM. At least this way allows you to test the VM in isolation, which is where all the business logic is.

这个解决方案确实使用了静态ServiceLocator (IocKernel),它通常被认为是一个反模式,因为它隐藏了类的依赖关系。但是,很难避免UI类的一些手动服务查找,因为它们必须有一个无参数的构造函数,而且无论如何您都无法控制实例化,因此无法注入VM。至少这种方式允许您单独测试VM,这是所有业务逻辑的所在。

If anyone has a better way, please do share.

如果有人有更好的方法,请分享。

EDIT: Lucky Likey provided an answer to get rid of the static service locator, by letting Ninject instantiate UI classes. The details of the answer can be seen here

编辑:Lucky Likey通过让Ninject实例化UI类,提供了摆脱静态服务定位器的答案。详细的答案可以在这里看到

#2


34  

In your question you set the value of the DataContext property of the view in XAML. This requires that your view-model has a default constructor. However, as you have noted, this does not work well with dependency injection where you want to inject dependencies in the constructor.

在您的问题中,您在XAML中设置了视图的DataContext属性的值。这要求您的视图模型有一个默认构造函数。但是,正如您所注意到的,对于要在构造函数中注入依赖项的依赖项注入,这并不能很好地工作。

So you cannot set the DataContext property in XAML. Instead you have other alternatives.

因此不能在XAML中设置DataContext属性。相反,你有其他的选择。

If you application is based on a simple hierarchical view-model you can construct the entire view-model hierarchy when the application starts (you will have to remove the StartupUri property from the App.xaml file):

如果您的应用程序基于简单的层次化视图模型,您可以在应用程序启动时构建整个视图模型层次结构(您必须从App.xaml文件中删除StartupUri属性):

public partial class App {

  protected override void OnStartup(StartupEventArgs e) {
    base.OnStartup(e);
    var cOntainer= CreateContainer();
    var viewModel = container.Resolve();
    var window = new MainWindow { DataCOntext= viewModel };
    window.Show();
  }

}

This is based around an object graph of view-models rooted at the RootViewModel but you can inject some view-model factories into parent view-models allowing them to create new child view-models so the object graph does not have to be fixed. This also hopefully answers your question suppose I need an instance of SomeViewModel from my cs code, how should I do it?

这是基于扎根于RootViewModel的视图模型的对象图,但是您可以将一些视图模型工厂注入到父视图模型中,从而允许它们创建新的子视图模型,这样对象图就不必被修复。这也很有希望回答你的问题假设我需要cs代码中的SomeViewModel实例,我该怎么做呢?

class ParentViewModel {

  public ParentViewModel(ChildViewModelFactory childViewModelFactory) {
    _childViewModelFactory = childViewModelFactory;
  }

  public void AddChild() {
    Children.Add(_childViewModelFactory.Create());
  }

  ObservableCollection Children { get; private set; }

 }

class ChildViewModelFactory {

  public ChildViewModelFactory(/* ChildViewModel dependencies */) {
    // Store dependencies.
  }

  public ChildViewModel Create() {
    return new ChildViewModel(/* Use stored dependencies */);
  }

}

If your application is more dynamic in nature and perhaps is based around navigation you will have to hook into the code that performs the navigation. Each time you navigate to a new view you need to create a view-model (from the DI container), the view itself and set the DataContext of the view to the view-model. You can do this view first where you pick a view-model based on a view or you can do it view-model first where the view-model determines which view to use. A MVVM framework provides this key functionality with some way for you to hook your DI container into the creation of view-models but you can also implement it yourself. I am a bit vague here because depending on your needs this functionality may become quite complex. This is one of the core functions you get from a MVVM framework but rolling your own in a simple application will give you a good understanding what MVVM frameworks provide under the hood.

如果您的应用程序本质上更动态,并且可能基于导航,那么您将不得不钩入执行导航的代码。每次导航到新视图时,都需要创建视图模型(来自DI容器),视图本身并将视图的DataContext设置为view-model。您可以先在视图中选择视图模型,或者在视图模型确定要使用哪个视图时先进行视图模型。MVVM框架提供了这个关键功能,您可以通过某种方式将DI容器与视图模型的创建关联起来,但您也可以自己实现它。这里我有点模糊,因为根据您的需要,这个功能可能会变得非常复杂。这是MVVM框架的核心功能之一,但是在一个简单的应用程序中滚动自己的功能将使您很好地理解MVVM框架提供的内容。

By not being able to declare the DataContext in XAML you lose some design-time support. If your view-model contains some data it will appear during design-time which can be very useful. Fortunately, you can use design-time attributes also in WPF. One way to do this is to add the following attributes to the element or in XAML:

由于不能在XAML中声明DataContext,您将丢失一些设计时支持。如果您的视图模型包含一些数据,它将在设计时出现,这将非常有用。幸运的是,您还可以在WPF中使用设计时属性。一种方法是将以下属性添加到XAML中的 元素或 :

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DataCOntext="{d:DesignInstance Type=local:MyViewModel, IsDesignTimeCreatable=True}"

The view-model type should have two constructors, the default for design-time data and another for dependency injection:

视图模型类型应该有两个构造函数,默认为设计时数据,另一个为依赖项注入:

class MyViewModel : INotifyPropertyChanged {

  public MyViewModel() {
    // Create some design-time data.
  }

  public MyViewModel(/* Dependencies */) {
    // Store dependencies.
  }

}

By doing this you can use dependency injection and retain good design-time support.

通过这样做,您可以使用依赖注入并保留良好的设计时支持。

#3


12  

I go for a "view first" approach, where I pass the view-model to the view's constructor (in its code-behind), which gets assigned to the data context, e.g.

我采用“视图优先”的方法,将视图模型传递给视图的构造函数(代码隐藏),并将其分配给数据上下文,例如。

public class SomeView
{
    public SomeView(SomeViewModel viewModel)
    {
        InitializeComponent();

        DataCOntext= viewModel;
    }
}

This replaces your XAML-based approach.

这将取代基于xam的方法。

I use the Prism framework to handle navigation - when some code requests a particular view be displayed (by "navigating" to it), Prism will resolve that view (internally, using the app's DI framework); the DI framework will in turn resolve any dependencies that the view has (the view model in my example), then resolves its dependencies, and so on.

我使用Prism框架来处理导航——当某些代码请求显示特定视图时(通过“导航”到它),Prism将解析该视图(在内部,使用应用程序的DI框架);DI框架将依次解析视图拥有的任何依赖项(在我的示例中是视图模型),然后解析它的依赖项,依此类推。

Choice of DI framework is pretty much irrelevant as they all do essentially the same thing, i.e. you register an interface (or a type) along with the concrete type that you want the framework to instantiate when it finds a dependency on that interface. For the record I use Castle Windsor.

DI框架的选择几乎是无关紧要的,因为它们基本上都做相同的事情,例如,当框架在该接口上找到依赖项时,您将注册一个接口(或一个类型)以及希望该框架实例化的具体类型。我用温莎城堡作记录。

Prism navigation takes some getting used to but is pretty good once you get your head around it, allowing you to compose your application using different views. E.g. you might create a Prism "region" on your main window, then using Prism navigation you would switch from one view to another within this region, e.g. as the user selects menu items or whatever.

Prism导航需要一些时间来适应,但是一旦你熟悉了它,它就会变得非常好,允许你使用不同的视图来编写应用程序。例如,你可以在你的主窗口上创建一个“区域”棱镜,然后使用“区域”棱镜导航系统,你可以在这个区域内从一个视图切换到另一个视图,例如,当用户选择菜单项或其他内容时。

Alternatively take a look at one of the MVVM frameworks such as MVVM Light. I've got no experience of these so can't comment on what they're like to use.

或者看看MVVM框架中的一个,比如MVVM Light。我没有这些经验,所以不能评论它们的用途。

#4


11  

Install MVVM Light.

安装MVVM光。

Part of the installation is to create a view model locator. This is a class which exposes your viewmodels as properties. The getter of these properties can then be returned instances from your IOC engine. Fortunately, MVVM light also includes the SimpleIOC framework, but you can wire in others if you like.

安装的一部分是创建视图模型定位器。这是一个将视图模型公开为属性的类。然后可以从IOC引擎返回这些属性的getter。幸运的是,MVVM light还包含SimpleIOC框架,但是如果您愿意,也可以连接其他框架。

With simple IOC you register an implementation against a type...

使用简单的IOC,您可以根据类型注册实现……

SimpleIOC.Default.Register(()=> new MyViewModel(new ServiceProvider()), true);

In this example, your view model is created and passed a service provider object as per its constructor.

在本例中,您的视图模型是根据其构造函数创建并传递服务提供者对象的。

You then create a property which returns an instance from IOC.

然后创建一个属性,该属性返回IOC的实例。

public MyViewModel
{
    get { return SimpleIOC.Default.GetInstance; }
}

The clever part is that the view model locator is then created in app.xaml or equivalent as a data source.

聪明的部分是,视图模型定位符然后在app.xaml中创建,或等效为数据源。


You can now bind to its 'MyViewModel' property to get your viewmodel with an injected service.

现在,您可以绑定到它的“MyViewModel”属性,通过注入的服务获得您的viewmodel。

Hope that helps. Apologies for any code inaccuracies, coded from memory on an iPad.

希望有帮助。对任何代码不准确的道歉,在iPad上用记忆编码。

#5


11  

What I'm posting here is an improvement to sondergard's Answer, because what I'm going to tell doesn't fit into a Comment :)

我在这里发布的是对sondergard的回答的改进,因为我要讲的内容不适合评论:

In Fact I am introducing a neat solution, which avoids the need of a ServiceLocator and a wrapper for the StandardKernel-Instance, which in sondergard's Solution is called IocContainer. Why? As mentioned, those are anti-patterns.

事实上,我正在引入一个简洁的解决方案,它避免了标准内核实例(在sondergard的解决方案中称为IocContainer)需要一个ServiceLocator和一个包装器。为什么?如前所述,这些是反模式。

Making the StandardKernel available everywhere

The Key to Ninject's magic is the StandardKernel-Instance which is needed to use the .Get()-Method.

Ninject的神奇之处在于使用. get ()-方法所需的标准内核实例。

Alternatively to sondergard's IocContainer you can create the StandardKernel inside the App-Class.

另外,您也可以在application - class中创建StandardKernel,而不是sondergard的IocContainer。

Just remove StartUpUri from your App.xaml

从App.xaml中删除StartUpUri即可


             ... 

This is the App's CodeBehind inside App.xaml.cs

这是App.xaml.cs里面的应用程序的代码。

public partial class App
{
    private IKernel _iocKernel;

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

        _iocKernel = new StandardKernel();
        _iocKernel.Load(new YourModule());

        Current.MainWindow = _iocKernel.Get();
        Current.MainWindow.Show();
    }
}

From now on, Ninject is alive and ready to fight :)

从现在开始,Ninject还活着,准备战斗

Injecting your DataContext

As Ninject is alive, you can perform all kinds of injections, e.g Property Setter Injection or the most common one Constructor Injection.

因为Ninject是活的,你可以进行各种注射。属性Setter注入或最常见的一个构造函数注入。

This is how you inject your ViewModel into your Window's DataContext

这就是如何将ViewModel注入到窗口的DataContext中。

public partial class MainWindow : Window
{
    public MainWindow(MainWindowViewModel vm)
    {
        DataCOntext= vm;
        InitializeComponent();
    }
}

Of course you can also Inject an IViewModel if you do the right bindings, but that is not a part of this answer.

当然,如果您做了正确的绑定,也可以注入IViewModel,但这不是这个答案的一部分。

Accessing the Kernel directly

If you need to call Methods on the Kernel directly (e.g. .Get()-Method), you can let the Kernel inject itself.

如果需要直接调用内核上的方法(例如,get ()-方法),可以让内核自己注入。

    private void DoStuffWithKernel(IKernel kernel)
    {
        kernel.Get();
        kernel.Whatever();
    }

If you would need a local instance of the Kernel you could inject it as Property.

如果需要内核的本地实例,可以将其作为属性注入。

    [Inject]
    public IKernel Kernel { private get; set; }

Allthough this can be pretty useful, I would not recommend you to do so. Just note that objects injected this way, will not be available inside the Constructor, because it's injected later.

虽然这很有用,但我不建议你这样做。请注意,以这种方式注入的对象在构造函数中不可用,因为稍后将注入。

According to this link you should use the factory-Extension instead of injecting the IKernel (DI Container).

根据这个链接,您应该使用工厂扩展而不是注入IKernel (DI容器)。

The recommended approach to employing a DI container in a software system is that the Composition Root of the application be the single place where the container is touched directly.

在软件系统中使用DI容器的推荐方法是,应用程序的组合根是直接接触容器的惟一位置。

How the Ninject.Extensions.Factory is to be used can also be red here.

Ninject.Extensions。工厂在这里也可以用红色。

#6


3  

Use the Managed Extensibility Framework.

使用托管的可扩展性框架。

[Export(typeof(IViewModel)]
public class SomeViewModel : IViewModel
{
    private IStorage _storage;

    [ImportingConstructor]
    public SomeViewModel(IStorage storage){
        _storage = storage;
    }

    public bool ProperlyInitialized { get { return _storage != null; } }
}

[Export(typeof(IStorage)]
public class Storage : IStorage
{
    public bool SaveFile(string content){
        // Saves the file using StreamWriter
    }
}

//Somewhere in your application bootstrapping...
public GetViewModel() {
     //Search all assemblies in the same directory where our dll/exe is
     string currentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
     var catalog = new DirectoryCatalog(currentPath);
     var cOntainer= new CompositionContainer(catalog);
     var viewModel = container.GetExport();
     //Assert that MEF did as advertised
     Debug.Assert(viewModel is SomViewModel); 
     Debug.Assert(viewModel.ProperlyInitialized);
}

In general, what you would do is have a static class and use the Factory Pattern to provide you with a global container (cached, natch).

通常,您要做的是拥有一个静态类,并使用Factory模式为您提供一个全局容器(缓存的natch)。

As for how to inject the view models, you inject them the same way you inject everything else. Create an importing constructor (or put a import statement on a property/field) in the code-behind of the XAML file, and tell it to import the view model. Then bind your Window's DataContext to that property. Your root objects you actually pull out of the container yourself are usually composed Window objects. Just add interfaces to the window classes, and export them, then grab from the catalog as above (in App.xaml.cs... that's the WPF bootstrap file).

至于如何注入视图模型,您的注入方式与注入其他所有内容的方式相同。在XAML文件的代码后面创建一个导入构造函数(或在属性/字段上放置一个导入语句),并告诉它导入视图模型。然后将窗口的DataContext绑定到该属性。实际上从容器中取出的根对象通常是由窗口对象组成的。只需向窗口类添加接口,并导出它们,然后从上面的目录中抓取(在app .xam .cs中……)这是WPF的引导文件)。

#7


0  

I would suggest to use the ViewModel - First approach https://github.com/Caliburn-Micro/Caliburn.Micro

我建议使用ViewModel - First方法https://github.com/calibury - micro/caliburn.micro。

see: https://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Conventions

参见:https://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Conventions

use Castle Windsor as IOC container.

使用温莎城堡作为IOC容器。

All About Conventions

关于约定

One of the main features of Caliburn.Micro is manifest in its ability to remove the need for boiler plate code by acting on a series of conventions. Some people love conventions and some hate them. That’s why CM’s conventions are fully customizable and can even be turned off completely if not desired. If you are going to use conventions, and since they are ON by default, it’s good to know what those conventions are and how they work. That’s the subject of this article. View Resolution (ViewModel-First)

这是Caliburn的一个主要特点。通过一系列的惯例,微观的能力可以消除对锅炉板代码的需求。有些人喜欢习俗,有些人讨厌习俗。这就是为什么CM的约定是完全可定制的,如果不需要,甚至可以完全关闭。如果您打算使用约定,并且由于它们是默认的,那么了解这些约定是什么以及它们是如何工作的很好。这就是本文的主题。视图解析(ViewModel-First)

Basics

基础知识

The first convention you are likely to encounter when using CM is related to view resolution. This convention affects any ViewModel-First areas of your application. In ViewModel-First, we have an existing ViewModel that we need to render to the screen. To do this, CM uses a simple naming pattern to find a UserControl1 that it should bind to the ViewModel and display. So, what is that pattern? Let’s just take a look at ViewLocator.LocateForModelType to find out:

使用CM时可能遇到的第一个约定与视图解析有关。此约定影响应用程序的任何ViewModel-First区域。在ViewModel- first中,我们有一个现有的ViewModel,需要呈现给屏幕。为此,CM使用一个简单的命名模式来查找应该绑定到ViewModel和display的UserControl1。那么,这个模式是什么呢?让我们来看看ViewLocator。LocateForModelType找出:

public static Func LocateForModelType = (modelType, displayLocation, context) =>{
    var viewTypeName = modelType.FullName.Replace("Model", string.Empty);
    if(context != null)
    {
        viewTypeName = viewTypeName.Remove(viewTypeName.Length - 4, 4);
        viewTypeName = viewTypeName + "." + context;
    }

    var viewType = (from assmebly in AssemblySource.Instance
                    from type in assmebly.GetExportedTypes()
                    where type.FullName == viewTypeName
                    select type).FirstOrDefault();

    return viewType == null
        ? new TextBlock { Text = string.Format("{0} not found.", viewTypeName) }
        : GetOrCreateViewType(viewType);
};

Let’s ignore the “context” variable at first. To derive the view, we make an assumption that you are using the text “ViewModel” in the naming of your VMs, so we just change that to “View” everywhere that we find it by removing the word “Model”. This has the effect of changing both type names and namespaces. So ViewModels.CustomerViewModel would become Views.CustomerView. Or if you are organizing your application by feature: CustomerManagement.CustomerViewModel becomes CustomerManagement.CustomerView. Hopefully, that’s pretty straight forward. Once we have the name, we then search for types with that name. We search any assembly you have exposed to CM as searchable via AssemblySource.Instance.2 If we find the type, we create an instance (or get one from the IoC container if it’s registered) and return it to the caller. If we don’t find the type, we generate a view with an appropriate “not found” message.

让我们先忽略“上下文”变量。为了导出视图,我们假设您在vm的命名中使用了文本“ViewModel”,因此我们只需将其更改为“view”(通过删除“Model”一词找到的所有地方)。这可以改变类型名和名称空间。所以视图模型。CustomerViewModel将成为Views.CustomerView。或者,如果您正在按特性组织应用程序:CustomerManagement。CustomerViewModel变得CustomerManagement.CustomerView。希望这是非常直接的。一旦我们有了这个名字,我们就会搜索这个名字的类型。我们将通过assembly . instance搜索您向CM公开的任何程序集。如果我们找到了该类型,我们将创建一个实例(或者从IoC容器中获取一个实例,如果它已注册)并将其返回给调用者。如果我们没有找到该类型,我们将生成一个带有适当“not found”消息的视图。

Now, back to that “context” value. This is how CM supports multiple Views over the same ViewModel. If a context (typically a string or an enum) is provided, we do a further transformation of the name, based on that value. This transformation effectively assumes you have a folder (namespace) for the different views by removing the word “View” from the end and appending the context instead. So, given a context of “Master” our ViewModels.CustomerViewModel would become Views.Customer.Master.

现在,回到“上下文”值。这就是CM在同一视图模型上支持多个视图的方式。如果提供了上下文(通常是字符串或枚举),我们将根据该值对名称进行进一步的转换。这种转换有效地假设您有一个文件夹(名称空间)用于不同的视图,方法是从末尾删除单词“View”,然后添加上下文。因此,在“掌握”我们的视图模型的上下文中。CustomerViewModel将成为Views.Customer.Master。

#8


0  

Remove the startup uri from your app.xaml.

从app.xaml中删除启动uri。

App.xaml.cs

App.xaml.cs

public partial class App
{
    protected override void OnStartup(StartupEventArgs e)
    {
        IoC.Configure(true);

        StartupUri = new Uri("Views/MainWindowView.xaml", UriKind.Relative);

        base.OnStartup(e);
    }
}

Now you can use your IoC class to construct the instances.

现在可以使用IoC类来构造实例。

MainWindowView.xaml.cs

MainWindowView.xaml.cs

public partial class MainWindowView
{
    public MainWindowView()
    {
        var mainWindowViewModel = IoC.GetInstance();

        //Do other configuration            

        DataCOntext= mainWindowViewModel;

        InitializeComponent();
    }

}

推荐阅读
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 近期,某用户在重启RAC一个节点的数据库实例时,发现启动速度非常慢。同时业务部门反馈连接RAC存活节点的业务也受影响。通过对日志的分析, ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • 本文分析了Wince程序内存和存储内存的分布及作用。Wince内存包括系统内存、对象存储和程序内存,其中系统内存占用了一部分SDRAM,而剩下的30M为程序内存和存储内存。对象存储是嵌入式wince操作系统中的一个新概念,常用于消费电子设备中。此外,文章还介绍了主电源和后备电池在操作系统中的作用。 ... [详细]
  • 本文介绍了关系型数据库和NoSQL数据库的概念和特点,列举了主流的关系型数据库和NoSQL数据库,同时描述了它们在新闻、电商抢购信息和微博热点信息等场景中的应用。此外,还提供了MySQL配置文件的相关内容。 ... [详细]
  • 本文介绍了解决mysql 5.1启动问题的方法,通过修改my.ini文件中的相关配置,包括innodb_data_home_dir和skip-innodb等,可以解决启动问题。同时还介绍了如何调整内存池来存储metadata信息。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 通过Anaconda安装tensorflow,并安装运行spyder编译器的完整教程
    本文提供了一个完整的教程,介绍了如何通过Anaconda安装tensorflow,并安装运行spyder编译器。文章详细介绍了安装Anaconda、创建tensorflow环境、安装GPU版本tensorflow、安装和运行Spyder编译器以及安装OpenCV等步骤。该教程适用于Windows 8操作系统,并提供了相关的网址供参考。通过本教程,读者可以轻松地安装和配置tensorflow环境,以及运行spyder编译器进行开发。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • 本文介绍了使用C++Builder实现获取USB优盘序列号的方法,包括相关的代码和说明。通过该方法,可以获取指定盘符的USB优盘序列号,并将其存放在缓冲中。该方法可以在Windows系统中有效地获取USB优盘序列号,并且适用于C++Builder开发环境。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
author-avatar
飘雪2502923303
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有