2016-05-04 51 views
2

私はWPFアプリケーションでPrism 6とUnityのDIを使用してビューモデルを解決しようとしています。しかし、どのビューをどのビューモデルとマージするべきかをフレームワークに伝える方法はわかりません。Prism 6 with Unity - 名前解決規約なしのビューのビューモデルを解決する

ViewModelsとViewsの名前空間、クラスViewAとViewAViewModelを使用すると、すべての機能が動作しますが、クラスの名前と構成に柔軟性を持たせたいと思っています。フレームワークはどのビューがどのビューモデルに関係するかを明示的に示します。私は多くのことを試みましたが、実際には何も動作しません。現在の「解決策」はアプリを実行させますが、ビューモデルは設定されません。

ここ

コードである:

ViewA.xaml

<UserControl x:Class="WPFDITest.Views.ViewA" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:prism="http://prismlibrary.com/" 
      prism:ViewModelLocator.AutoWireViewModel="True" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <StackPanel> 
     <TextBlock Text="{Binding ViewAMessage}"/> 
     <TextBox Text="{Binding ViewAMessage, UpdateSourceTrigger=PropertyChanged}"/> 
    </StackPanel> 
</UserControl> 

MainWindow.xaml

<UserControl x:Class="WPFDITest.Views.ViewA" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:prism="http://prismlibrary.com/" 
      prism:ViewModelLocator.AutoWireViewModel="True" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <StackPanel> 
     <TextBlock Text="{Binding ViewAMessage}"/> 
     <TextBox Text="{Binding ViewAMessage, UpdateSourceTrigger=PropertyChanged}"/> 
    </StackPanel> 
</UserControl> 

ViewAVM.cs

public class ViewAVM : BindableBase 
{ 
    private string viewAMessage; 

    public ViewAVM(IModelA model) 
    { 
     viewAMessage = model.HelloMsgA(); 
    } 

    public string ViewAMessage 
    { 
     get { return viewAMessage; } 
     set { SetProperty(ref viewAMessage, value); } 
    } 
} 

Model.cs

ここ
public interface IModelA 
{ 
    string HelloMsgA(); 
} 

public class ModelA : IModelA 
{ 
    public string HelloMsgA() 
    { 
     return "Hello from A!"; 
    } 
} 

App.xaml.cs

public partial class App 
{ 
    protected override void OnStartup(StartupEventArgs e) 
    { 
     base.OnStartup(e); 

     var bootstraper = new Bootstrapper(); 
     bootstraper.Run(); 
    } 
} 

Bootstrapper.cs

public class Bootstrapper : UnityBootstrapper 
{ 
    protected override DependencyObject CreateShell() 
    { 
     return Container.Resolve<MainWindow>(); 
    } 

    protected override void InitializeShell() 
    { 
     Application.Current.MainWindow.Show(); 
    } 

    protected override void ConfigureContainer() 
    { 
     base.ConfigureContainer(); 
     Container.RegisterType<IModelA, ModelA>(new ContainerControlledLifetimeManager()); 
     Container.RegisterType<object, ViewAVM>("ViewA"); 
    } 

    protected override void ConfigureViewModelLocator() 
    { 
     ViewModelLocationProvider.SetDefaultViewModelFactory(type => Container.Resolve(type)); 
    } 
} 

答えて

4

プリズムの情報源を掘り出した後、私は自分のやりたいことを見つけました。私はViewModelLocationProvider.Registerで各ビューを登録し、ビューモデルのファクトリメソッドで渡すことができます。私は便利な構文で、まさにそれを行い、指定された型のビューモデルを解決するための容器を使用する方法作成:

public void BindViewModelToView<TViewModel, TView>() 
{ 
    ViewModelLocationProvider.Register(typeof(TView).ToString(),() => Container.Resolve<TViewModel>()); 
} 

をそして私は同じシングルトンインスタンスを使用してViewAViewBの両方にViewAVMをバインドするためにそれを使用する方法があります。ところで

public class Bootstrapper : UnityBootstrapper 
{ 
    protected override DependencyObject CreateShell() 
    { 
     return Container.Resolve<MainWindow>(); 
    } 

    protected override void InitializeShell() 
    { 
     Application.Current.MainWindow.Show(); 
    } 

    protected override void ConfigureContainer() 
    { 
     base.ConfigureContainer(); 
     Container.RegisterType<IModelA, ModelA>(new ContainerControlledLifetimeManager()); 
     Container.RegisterType<ViewAVM>(new ContainerControlledLifetimeManager()); 
    } 

    protected override void ConfigureViewModelLocator() 
    { 
     BindViewModelToView<ViewAVM, ViewA>(); 
     BindViewModelToView<ViewAVM, ViewB>(); 
    } 
} 

は、私の知る限りソースによって言うことができるように、それは工場を登録することによって、またはそのまたはカスタム規則を使用してViewModelLocatorでモデルを通じ表示するビューを関連付けることしかできない、のために見ていませんいくつかのDI魔法。

1

ViewModelLocatorにブライアンのブログへのリンクであり、セクションは(それらの淫乱表記を変更します)が含まあなたが望むなら、慣習を無効にする方法について。個人的に

Getting Started with Prism’s new ViewModelLocator

ビューはモジュール内のコンテナに登録されます後、私は、コンストラクタで、ユーザーコントロールの背後にあるコードで私のDataContextを設定します。大会は間に合わない! :)

+1

私はそのポストとはるかに多くのものを見ましたが、まだ、私は慣習を望んでいません。私はあなたのアプローチも試みましたが、 'ViewA'が' ViewAVM'をパラメータとして 'DataContext'を設定すると、' InitializeComponent'メソッドの 'MainWindow'コンストラクタで' NullReferenceException'が発生するという問題があります。 –

+0

このレポをクローンすることができますhttps://github.com/lukaszwawrzyk/wpf-prism-di-test.gitと参照してください。 –

+0

私はGitをインストールしていません。これを私がやるようにしたいのであれば、モジュールとブートストラップのCreateModuleCatalogのオーバーライドが必要です。 CreateModuleCatalogは、IModuleインターフェイスを実装するモジュールを登録する場所です。モジュールのInitializeメソッドで、ビューをコンテナに登録します。コンテナはViewにViewModelが必要であると判断し、ViewModelを提供します。これは、あなたが望む、または必要以上のものかもしれません。あなたはDataContext = new ViewAVM();と一緒に行くことができます。あなたはGitHubのPrismLibraryの例を見ましたか? –

関連する問題