WPF / MVVMアプリケーションで依存性注入を処理する方法


102

新しいデスクトップアプリケーションを開始していますが、MVVMとWPFを使用してそれを構築したいと考えています。

また、TDDを使用するつもりです。

問題は、IoCコンテナーを使用して、プロダクションコードに依存関係を挿入する方法がわからないことです。

次のクラスとインターフェイスがあるとします。

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

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

次にIStorage、依存関係を持つ別のクラスがあります。このクラスがViewModelまたはビジネスクラスであるとします...

public class SomeViewModel
{
    private IStorage _storage;

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

これにより、モックなどを使用して、ユニットテストが適切に機能することを確認するユニットテストを簡単に作成できます。

問題は、実際のアプリケーションで使用することです。IStorageインターフェイスのデフォルト実装をリンクするIoCコンテナが必要であることはわかっていますが、どうすればよいですか?

たとえば、次のxamlがあるとどうなりますか。

<Window 
    ... xmlns definitions ...
>
   <Window.DataContext>
        <local:SomeViewModel />
   </Window.DataContext>
</Window>

その場合、依存関係を挿入するようにWPFに正しく「伝える」にはどうすればよいですか?

また、SomeViewModelC#コードからのインスタンスが必要だとしたら、どうすればよいですか?

私はこれで完全に迷っていると感じています。どのようにそれを処理する最良の方法であるかについての例やガイダンスをいただければ幸いです。

私はStructureMapに精通していますが、専門家ではありません。また、より良い/より簡単/すぐに使えるフレームワークがある場合は、私に知らせてください。


プレビューの.net core 3.0では、いくつかのMicrosoft nugetパッケージでそれを行うことができます。
ベイリーミラー

回答:


87

私はNinjectを使用していて、一緒に作業できて嬉しいです。すべてがコードで設定され、構文はかなり単純で、優れたドキュメントがあります(SOに関する多くの回答があります)。

したがって、基本的には次のようになります。

ビューモデルを作成し、IStorageコンストラクターパラメーターとしてインターフェイスを受け取ります。

class UserControlViewModel
{
    public UserControlViewModel(IStorage storage)
    {

    }
}

ViewModelLocatorNinjectからビューモデルを読み込むビューモデルのgetプロパティを使用してを作成します。

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

作るViewModelLocatorApp.xamlでアプリケーション全体のリソースを:

<Application ...>
    <Application.Resources>
        <local:ViewModelLocator x:Key="ViewModelLocator"/>
    </Application.Resources>
</Application>

バインドDataContextUserControlViewModelLocatorの対応するプロパティに。

<UserControl ...
             DataContext="{Binding UserControlViewModel, Source={StaticResource ViewModelLocator}}">
    <Grid>
    </Grid>
</UserControl>

NinjectModuleを継承するクラスを作成します。これにより、必要なバインディング(IStorageおよびビューモデル)がセットアップされます。

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

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

アプリケーションの起動時に、必要なNinjectモジュール(上記のもの)を使用してIoCカーネルを初期化します。

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

        base.OnStartup(e);
    }
}

IocKernelIoCカーネルのアプリケーション全体のインスタンスを保持するために静的クラスを使用したので、必要なときに簡単にアクセスできます。

public static class IocKernel
{
    private static StandardKernel _kernel;

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

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

このソリューションは、クラスの依存関係を隠すため、一般にアンチパターンと見なされる静的ServiceLocator(the IocKernel)を利用します。ただし、UIクラスのパラメーターのないコンストラクターが必要であり、インスタンス化を制御できないため、VMを注入できないため、UIクラスの手動サービスルックアップを回避することは非常に困難です。少なくともこの方法で、VMを分離してテストできます。これは、すべてのビジネスロジックがある場所です。

誰かがより良い方法を持っている場合は、共有してください。

編集:Lucky Likeyは、NinjectがUIクラスをインスタンス化できるようにすることで、静的サービスロケーターを取り除くための回答を提供しました。回答の詳細はこちら


13
依存関係注入は初めてですが、静的なViewModel Locatorを使用しているため、ソリューションの中心にはService LocatorアンチパターンとNinjectを組み合わせています。注入はXamlファイルで行われるため、テストされる可能性は低いと言えます。私にはより良い解決策がなく、おそらくあなたの解決策を使うでしょう-それでも答えでこれを言及することは役立つと思います。
user3141326 2015

あなたのソリューションは素晴らしいです、次の行の「問題」は1つだけですDataContext="{Binding [...]}"。これにより、VS-DesignerはViewModelのコンストラクター内のすべてのプログラムコードを実行します。私の場合、ウィンドウが実行されており、VSとのやり取りをモーダルでブロックしています。おそらく、デザインタイムで「実際の」ViewModelを見つけないようにViewModelLocatorを変更する必要があります。-もう1つの解決策は、「プロジェクトコードを無効にする」ことです。これにより、他のすべてが表示されないようになります。たぶん、あなたはすでにこれに対するきちんとした解決策を見つけました。この場合、それを見せてください。
LuckyLikey

@LuckyLikey d:DataContext = "{d:DesignInstance vm:UserControlViewModel、IsDesignTimeCreatable = True}"を使用してみることができますが、違いがあるかどうかはわかりません。しかし、なぜ/どのようにVMコンストラクターがモーダルウィンドウを起動するのですか?そして、どんな窓?
ゾンダーガード2017

@son実際には理由と方法はわかりませんが、ソリューションエクスプローラーからウィンドウデザイナーを開くと、新しいタブが開いているため、デザイナーによってウィンドウが表示され、モーダルのデバッグと同じウィンドウが表示されます。 VS「Micorosoft Visual Studio XAML Designer」以外の新しいプロセスでホストされます。プロセスがシャットダウンされると、VS-Designerも前述の例外で失敗します。私はあなたの回避策を試すつもりです。新しい情報を検出したら通知します:)
LuckyLikey

1
@sondergard ServiceLocator Anti-Patternを回避して、回答を改善しました。お気軽にご確認ください。
LuckyLikey

52

あなたの質問DataContextでは、XAMLでビューのプロパティの値を設定します。これには、ビューモデルにデフォルトのコンストラクターが必要です。ただし、既に述べたように、これは、コンストラクターに依存関係を注入する必要がある依存関係注入ではうまく機能しません。

したがって、XAMLでプロパティを設定することはできませんDataContext。代わりに、他の選択肢があります。

アプリケーションが単純な階層ビューモデルに基づいている場合は、アプリケーションの起動時にビューモデル階層全体を構築できます(ファイルStartupUriからプロパティを削除する必要がありApp.xamlます)。

public partial class App {

  protected override void OnStartup(StartupEventArgs e) {
    base.OnStartup(e);
    var container = CreateContainer();
    var viewModel = container.Resolve<RootViewModel>();
    var window = new MainWindow { DataContext = viewModel };
    window.Show();
  }

}

これは、をルートとするビューモデルのオブジェクトグラフに基づいてRootViewModelいますが、一部のビューモデルファクトリを親ビューモデルに挿入して、新しい子ビューモデルを作成できるため、オブジェクトグラフを修正する必要がありません。これもうまくいけば、私のコードからのインスタンスが必要だとしたら、どうすればよいですか?SomeViewModelcs

class ParentViewModel {

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

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

  ObservableCollection<ChildViewModel> Children { get; private set; }

 }

class ChildViewModelFactory {

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

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

}

アプリケーションの性質がより動的で、おそらくナビゲーションに基づいている場合は、ナビゲーションを実行するコードにフックする必要があります。新しいビューに移動するたびに、(DIコンテナーから)ビューモデルを作成し、ビュー自体を作成して、ビューのビューをビューモデルに設定する必要DataContextがあります。最初にこのビューを実行し、ビューに基づいてビューモデルを選択するか、またはそれを実行できます。最初のモデルを見ますここで、view-modelは使用するビューを決定します。MVVMフレームワークは、DIコンテナーをビューモデルの作成にフックするためのいくつかの方法でこの重要な機能を提供しますが、自分で実装することもできます。あなたのニーズによっては、この機能がかなり複雑になる可能性があるので、私はここでは少し曖昧です。これはMVVMフレームワークから得られるコア機能の1つですが、単純なアプリケーションで独自にロールバックすると、MVVMフレームワークが内部で提供する機能を十分に理解できます。

宣言できないことにより DataContextXAMLで、設計時のサポートが失われます。ビューモデルにデータが含まれている場合、デザイン時に表示されるため、非常に便利です。さいわい、WPFでもデザイン時属性を使用できます。これを行う1つの方法は、次の属性を<Window>要素または<UserControl>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}"

ビューモデルタイプには、設計時データのデフォルトと依存性注入用の2つのコンストラクターが必要です。

class MyViewModel : INotifyPropertyChanged {

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

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

}

これを行うことで、依存性注入を使用し、優れた設計時サポートを維持できます。


12
これはまさに私が探していたものです。「[ yadde-ya ]フレームワークを使うだけだ」という回答を何度も読んだことで不満を感じます。これで十分ですが、最初に自分でロールする方法を正確に知りたいので、実際にどのようなフレームワークが役立つのかを知ることができます。明記していただきありがとうございます。
kmote 2017年

28

私がここに投稿しているのは、sondergardのAnswerの改善です。

ファクトでは、ServiceLocatorおよびStandardKernel-Instanceのラッパーの必要性を回避するきちんとしたソリューションを紹介しています。これは、sondergardのソリューションではと呼ばれていIocContainerます。どうして?述べたように、それらはアンチパターンです。

作るStandardKernelどこでも利用可能

Ninjectの魔法の鍵は、StandardKernel-Methodを使用するために必要な.Get<T>()-Instanceです。

sondergardの代わりに、-Classの内部IocContainerを作成できます。StandardKernelApp

App.xamlからStartUpUriを削除するだけです

<Application x:Class="Namespace.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
             ... 
</Application>

これは、App.xaml.cs内のアプリのCodeBehindです。

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<MainWindow>();
        Current.MainWindow.Show();
    }
}

今から、Ninjectは生きており、戦う準備ができています:)

あなたの注射 DataContext

Ninjectは生きているので、たとえばProperty Setter Injectionや最も一般的なConstructor Injectionなど、あらゆる種類の注入を実行できます。

これは、あなたにあなたのViewModelを注入する方法ですWindowさんDataContext

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

もちろんIViewModel、正しいバインディングを行う場合は、Injectを使用することもできますが、これはこの回答の一部ではありません。

カーネルに直接アクセスする

カーネルで直接メソッドを呼び出す必要がある場合(例:.Get<T>()-Method)、カーネルにそれ自体を挿入させることができます。

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

カーネルのローカルインスタンスが必要な場合は、プロパティとして注入できます。

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

これはかなり便利ですが、そうすることはお勧めしません。この方法で注入されたオブジェクトは、後で注入されるため、コンストラクター内では使用できないことに注意してください。

このリンクによると、IKernel(DIコンテナー)を挿入する代わりに、factory-Extensionを使用する必要があります。

ソフトウェアシステムでDIコンテナーを使用するための推奨されるアプローチは、アプリケーションのコンポジションルートがコンテナーに直接触れる単一の場所になることです。

Ninject.Extensions.Factoryの使用方法もここで赤く表示できます


素敵なアプローチ。このレベルまでNinjectを探索したことはありませんが、私は見逃していることがわかります:)
sondergard 2017

@son thx。あなたの回答の最後にあなたが述べたあなたがより良い方法を誰かが持っているなら、共有してください。これにリンクを追加していただけませんか?
LuckyLikey

誰かがNinject.Extensions.Factoryこれの使い方に興味があるなら、コメントでここにそれを述べてください、そして私はいくつかのより多くの情報を追加します。
LuckyLikey

1
@LuckyLikey:パラメータのないコンストラクタを持たないXAMLを介してウィンドウデータコンテキストにViewModelを追加するにはどうすればよいですか?ServiceLocatorを使用したsondergardのソリューションでは、このような状況が発生する可能性があります。
Thomas Geulen、2018年

添付プロパティで必要なサービスを取得する方法を教えてください。それらは常にバッキングDependencyPropertyフィールドとそのGetおよびSetメソッドの両方で静的です。
springy76 2018年

12

「ビューファースト」アプローチを採用します。ここでは、ビューモデルをビューのコンストラクタ(コードビハインド内)に渡します。これは、データコンテキストに割り当てられます。たとえば、

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

        DataContext = viewModel;
    }
}

これは、XAMLベースのアプローチを置き換えます。

私は、Prismフレームワークを使用してナビゲーションを処理します-一部のコードが特定のビューの表示を(「それにナビゲートする」ことにより)要求すると、Prismはそのビューを(内部的には、アプリのDIフレームワークを使用して)解決します。DIフレームワークは、ビューが持つ依存関係(この例ではビューモデル)を解決し、次に解決します。、その依存関係をします。

DIフレームワークの選択は、基本的に同じことを行うため、ほとんど関係ありません。つまり、フレームワークがそのインターフェースへの依存関係を検出したときにインスタンス化する具体的なタイプとともに、インターフェース(またはタイプ)を登録します。記録では、キャッスルウィンザーを使用します。

Prismナビゲーションは慣れるまでに時間がかかりますが、頭に浮かぶとかなり良いので、さまざまなビューを使用してアプリケーションを作成できます。たとえば、メインウィンドウにPrism "リージョン"を作成し、Prismナビゲーションを使用して、ユーザーがメニュー項目などを選択すると、このリージョン内のビューを別のビューに切り替えることができます。

または、MVVM LightなどのMVVMフレームワークの1つを見てください。私はこれらの経験がないので、彼らがどのように使用するのかについてコメントすることはできません。


1
どのようにコンストラクター引数を子ビューに渡しますか?私はこのアプローチを試しましたが、親ビューで例外が発生し、子ビューにはデフォルトのパラメーターなしのコンストラクターがないことがわかります
Doctor Jones

10

MVVM Lightをインストールします。

インストールの一部は、ビューモデルロケーターの作成です。これは、ビューモデルをプロパティとして公開するクラスです。これらのプロパティのゲッターは、IOCエンジンからインスタンスを返すことができます。幸い、MVVM lightにはSimpleIOCフレームワークも含まれていますが、必要に応じて他のフレームワークに接続することもできます。

単純なIOCを使用して、型に対して実装を登録します...

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

この例では、ビューモデルが作成され、コンストラクターに従ってサービスプロバイダーオブジェクトが渡されます。

次に、IOCからインスタンスを返すプロパティを作成します。

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

賢い部分は、ビューモデルロケーターがデータソースとしてapp.xamlまたは同等のものに作成されることです。

<local:ViewModelLocator x:key="Vml" />

これで、「MyViewModel」プロパティにバインドして、注入されたサービスでビューモデルを取得できます。

お役に立てば幸いです。iPadのメモリからコード化されたコードの誤りについての謝罪。


アプリケーションのブートストラップGetInstanceまたはそのresolve外部にあるべきではありません。それがDIのポイントです!
ソレイユ-MathieuPrévot19年

起動時にプロパティ値を設定できることに同意しますが、遅延インスタンス化を使用することはDIに反することを示唆するのは間違っています。
キッズショー

@kishaw私はしませんでした。
ソレイユ-MathieuPrévot19年

3

Canonic DryIocケース

古い投稿に答えDryIocますが、これを実行し、DIとインターフェイスの適切な使用法(具象クラスの最小限の使用法)を実行するとします。

  1. WPFアプリの出発点はです。App.xamlそこで、使用する初期ビューを教えます。これは、デフォルトのxamlの代わりにコードビハインドで行います。
  2. StartupUri="MainWindow.xaml"App.xamlで削除
  3. 分離コード(App.xaml.cs)でこれを追加しますoverride OnStartup

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        DryContainer.Resolve<MainWindow>().Show();
    }

それが出発点です。それresolveは呼ばれるべき唯一の場所でもあります。

  1. 構成ルート(.NETのMark Seemanの本のDependencyインジェクションによると、具体的なクラスが言及されるべき唯一の場所)は、コンストラクター内の同じ分離コード内にあります。

    public Container DryContainer { get; private set; }
    
    public App()
    {
        DryContainer = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient());
        DryContainer.Register<IDatabaseManager, DatabaseManager>();
        DryContainer.Register<IJConfigReader, JConfigReader>();
        DryContainer.Register<IMainWindowViewModel, MainWindowViewModel>(
            Made.Of(() => new MainWindowViewModel(Arg.Of<IDatabaseManager>(), Arg.Of<IJConfigReader>())));
        DryContainer.Register<MainWindow>();
    }

備考といくつかの詳細

  • ビューでのみ具体クラスを使用しましたMainWindow
  • XAMLデザイナーにはデフォルトのコンストラクターが必要であり、インジェクション付きのコンストラクターは実際にアプリケーションに使用されるコンストラクターであるため、ViewModelに使用するコンストラクター(DryIocでそれを行う必要があります)を指定する必要がありました。

DIを備えたViewModelコンストラクタ:

public MainWindowViewModel(IDatabaseManager dbmgr, IJConfigReader jconfigReader)
{
    _dbMgr = dbmgr;
    _jconfigReader = jconfigReader;
}

設計のViewModelデフォルトコンストラクタ:

public MainWindowViewModel()
{
}

ビューの分離コード:

public partial class MainWindow
{
    public MainWindow(IMainWindowViewModel vm)
    {
        InitializeComponent();
        ViewModel = vm;
    }

    public IViewModel ViewModel
    {
        get { return (IViewModel)DataContext; }
        set { DataContext = value; }
    }
}

そして、ViewModelでデザインインスタンスを取得するためにビュー(MainWindow.xaml)に必要なもの:

d:DataContext="{d:DesignInstance local:MainWindowViewModel, IsDesignTimeCreatable=True}"

結論

したがって、ビューとビューモデルの設計インスタンスを可能な限り維持しながら、DryIocコンテナーとDIを使用したWPFアプリケーションの非常にクリーンで最小限の実装を得ました。


2

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<IViewModel>();
     //Assert that MEF did as advertised
     Debug.Assert(viewModel is SomViewModel); 
     Debug.Assert(viewModel.ProperlyInitialized);
}

一般的には、静的クラスを用意し、ファクトリパターンを使用してグローバルコンテナ(キャッシュ、ナッチ)を提供します。

ビューモデルを注入する方法については、他のすべてを注入するのと同じ方法でビューモデルを注入します。XAMLファイルの分離コードでインポートコンストラクターを作成(またはプロパティ/フィールドにインポートステートメントを配置)し、ビューモデルをインポートするように指示します。次に、あなたWindowのをバインドしますDataContextそのプロパティに。自分で実際にコンテナから取り出したルートオブジェクトは、通常は合成Windowオブジェクトです。ウィンドウクラスにインターフェイスを追加してエクスポートし、上記のようにカタログから取得します(App.xaml.csで...これはWPFブートストラップファイルです)。


DIの重要なポイントが1つありません。それは、を使用したインスタンスの作成を回避することnewです。
ソレイユ-MathieuPrévot19年

0

私はViewModelを使用することをお勧めします-最初のアプローチ https://github.com/Caliburn-Micro/Caliburn.Micro

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

Castle WindsorIOCコンテナーとして使用します。

規約について

Caliburn.Microの主な機能の1つは、一連の規則に従って動作することにより、ボイラープレートコードの必要性を排除する能力に現れています。慣習が好きな人もいれば嫌いな人もいます。そのため、CMの規則は完全にカスタマイズ可能であり、必要でない場合は完全にオフにすることもできます。規則を使用する場合、それらがデフォルトでオンになっているので、それらの規則が何であり、どのように機能するかを知っておくとよいでしょう。それがこの記事の主題です。ビューの解像度(ViewModel-First)

基本

CMを使用するときに最初に遭遇する可能性が高い規則は、ビューの解像度に関連しています。この規則は、アプリケーションのViewModel-First領域に影響します。ViewModel-Firstには、画面にレンダリングする必要のある既存のViewModelがあります。これを行うために、CMは単純な命名パターンを使用して、ViewModelにバインドして表示する必要があるUserControl1を見つけます。それで、そのパターンは何ですか?ViewLocator.LocateForModelTypeを見てみましょう。

public static Func<Type, DependencyObject, object, UIElement> 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);
};

最初は「コンテキスト」変数を無視しましょう。ビューを導出するために、VMの名前に「ViewModel」というテキストを使用していることを前提としているため、「Model」という単語を削除することで、見つかったすべての場所で「View」に変更します。これには、型名と名前空間の両方を変更する効果があります。したがって、ViewModels.CustomerViewModelはViews.CustomerViewになります。または、機能ごとにアプリケーションを整理している場合:CustomerManagement.CustomerViewModelはCustomerManagement.CustomerViewになります。うまくいけば、それはかなり簡単です。名前を取得したら、その名前のタイプを検索します。AssemblySource.Instance.2を介して検索可能なものとして、CMに公開したすべてのアセンブリを検索します。タイプが見つかった場合は、インスタンスを作成し(または、IoCコンテナーが登録されている場合はそれを取得し)、呼び出し元に返します。タイプが見つからない場合は、

さて、その「コンテキスト」値に戻ります。これは、CMが同じViewModelで複数のビューをサポートする方法です。コンテキスト(通常は文字列または列挙型)が提供されている場合は、その値に基づいて名前をさらに変換します。この変換では、末尾から「View」という単語を削除し、代わりにコンテキストを追加することにより、さまざまなビューのフォルダー(名前空間)があることを効果的に想定しています。したがって、「マスター」のコンテキストが与えられると、ViewModels.CustomerViewModelはViews.Customer.Masterになります。


2
あなたの投稿全体が意見です。
John Peters、

-1

app.xamlからスタートアップURIを削除します。

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);
    }
}

これで、IoCクラスを使用してインスタンスを構築できます。

MainWindowView.xaml.cs

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

        //Do other configuration            

        DataContext = mainWindowViewModel;

        InitializeComponent();
    }

}

外部のapp.xaml.csのコンテナーGetInstanceは 必要ありませんresolve。DIのポイントを失います。また、ビューの分離コードでxamlビューに言及することは、ちょっと複雑です。純粋なc#でビューを呼び出し、コンテナーでこれを実行するだけです。
ソレイユ-MathieuPrévot19年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.