2015-04-05 36 views
3

最近,我開始將我的一個項目重組爲較小的程序集。在一個步驟中,我將視圖和視圖模型轉移到單獨的程序集中,同時將屬於一個視圖和VM的視圖和VM保留在一個通用程序集中。因此,我的項目結構是這樣的:CaliburnMicro在不同的程序集中找不到視圖模型的視圖

  • 主要
  • 核心
  • 模塊< - 文件夾
    • CharacterPresenter
    • LocationPresenter

命名空間是這樣的:

  • RpgTools
    • 主要
      • 的ViewModels
      • 查看
    • LocationPresenter
      • 的ViewModels
      • 查看
    • 其他項目遵循相同的系統。

「主」 包含引導程序和d簡約VM和視圖選擇的模塊。每位演示者都包含該演示者所需的所有視圖和視圖模型。 「核心」包含文件夾中每個項目使用的資源(例如元數據定義,導出界面等)

現在,在移動之後,Caliburn.Micro無法找到視圖模型的視圖,無論它有多簡單。這裏是一個視圖模型和視圖的例子:

namespace RpgTools.LocationPresenter.ViewModels 
{ 
    using System.ComponentModel.Composition; 
    using RpgTools.Core.Contracts; 

    [RpgModuleMetadata(Name = "Module C")] 
    [Export(typeof(IRpgModuleContract))] 
    public class ModuleCViewModel :IRpgModuleContract 
    { 
    } 
} 

<UserControl x:Class="RpgTools.LocationPresenter.Views.ModuleCView" 
      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" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
      <TextBlock Text="ModuleC" /> 
    </Grid> 
</UserControl> 

我每次加載模塊我得到以下錯誤:

Cannot find view for RpgTools.LocationPresenter.ViewModels.ModuleCViewModel.

如果我移動模型回「主」它工作得很好。由於它可能是引導程序的東西,這裏是它的完整代碼:

namespace RpgTools.Main 
{ 
    using System; 
    using System.Collections.Generic; 
    using System.ComponentModel.Composition; 
    using System.ComponentModel.Composition.Hosting; 
    using System.ComponentModel.Composition.Primitives; 
    using System.Diagnostics.CodeAnalysis; 
    using System.IO; 
    using System.Linq; 
    using System.Reflection; 
    using System.Windows; 

    using Caliburn.Micro; 

    using RpgTools.Core.Contracts; 

    /// <summary>The MEF bootstrapper.</summary> 
    [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")] 
    public class MefBootstrapper : BootstrapperBase 
    { 
     /// <summary>The composition container.</summary> 
     private CompositionContainer compositionContainer; 

     /// <summary>Initialises a new instance of the <see cref="MefBootstrapper"/> class.</summary> 
     public MefBootstrapper() 
     { 
      // this.CheckModuleDirectory(); 

      this.Initialize(); 
     } 

     /// <summary>Override to configure the framework and setup your IoC container.</summary> 
     protected override void Configure() 
     { 
      // Get the modules from the module directory 
      // ToDo: Implement dynamic loading from modules directory. 
      DirectoryCatalog dirCatalog = new DirectoryCatalog(@"."); 

      // Create a combinable catalog 
      // ReSharper disable once RedundantEnumerableCastCall 
      AggregateCatalog catalog = new AggregateCatalog(AssemblySource.Instance.Select(s => new AssemblyCatalog(s)).OfType<ComposablePartCatalog>()); 
      catalog.Catalogs.Add(dirCatalog); 

      // Create a new composition container. 
      // ReSharper disable once RedundantEnumerableCastCall 
      this.compositionContainer = new CompositionContainer(); 

      // Create a new composition container. 
      this.compositionContainer = new CompositionContainer(catalog); 

      CompositionBatch compositionBatch = new CompositionBatch(); 

      // Add window manager to composition batch. 
      compositionBatch.AddExportedValue<IWindowManager>(new ToolsWindowManager()); 

      // Add EventAggregator to composition batch. 
      compositionBatch.AddExportedValue<IEventAggregator>(new EventAggregator()); 

      // Add the container itself. 
      compositionBatch.AddExportedValue(this.compositionContainer); 

      // Compose the container. 
      this.compositionContainer.Compose(compositionBatch); 
     } 

     /// <summary>Override this to provide an IoC specific implementation.</summary> 
     /// <param name="service">The service to locate.</param> 
     /// <param name="key">The key to locate.</param> 
     /// <returns>The located service.</returns> 
     protected override object GetInstance(Type service, string key) 
     { 
      // Check if the contract is null or an empty string, if so return the contract name from the service itself. 
      string contractName = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(service) : key; 

      // Get a collection of exported values with the goven contract name. 
      IList<object> exports = this.compositionContainer.GetExportedValues<object>(contractName).ToList(); 

      if (exports.Any()) 
      { 
       return exports.First(); 
      } 

      throw new Exception(string.Format("Could not locate any instances of contract {0}.", contractName)); 
     } 

     /// <summary>Override this to provide an IoC specific implementation</summary> 
     /// <param name="serviceType">The service to locate.</param> 
     /// <returns>The located services.</returns> 
     protected override IEnumerable<object> GetAllInstances(Type serviceType) 
     { 
      return this.compositionContainer.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType)); 
     } 

     /// <summary>Override this to provide an IoC specific implementation.</summary> 
     /// <param name="instance"> The instance to perform injection on.</param> 
     protected override void BuildUp(object instance) 
     { 
      this.compositionContainer.SatisfyImportsOnce(instance); 
     } 

     /// <summary>Override this to add custom behaviour to execute after the application starts.</summary> 
     /// <param name="sender">The sender.</param> 
     /// <param name="e">The args.</param> 
     protected override void OnStartup(object sender, StartupEventArgs e) 
     { 
      this.DisplayRootViewFor<IShell>(); 
     } 

     /// <summary>Checks if the modules directory exists and if not create it.</summary> 
     private void CheckModuleDirectory() 
     { 
      if (!Directory.Exists(@".\Modules")) 
      { 
       Directory.CreateDirectory(@".\Modules"); 
      } 
     } 
    } 
} 

我可能會添加模塊發現工作正常。我ShellView模型顯示我加精每一個項目每一個模塊的意見只是裝不一樣,如果認爲位於不同的裝配比「主」


通過重寫工作,我解決原有問題SelectAssemblies()方法用下面的代碼:

protected override IEnumerable<Assembly> SelectAssemblies() 
{ 
    var assemblies = Directory.GetFiles(ModuleDirectory, "*.dll", SearchOption.AllDirectories).Select(Assembly.LoadFrom).ToList(); 
    assemblies.Add(Assembly.GetExecutingAssembly()); 
    return assemblies; 
} 

但是現在我所有的模塊都被加載了兩次!這是我所做的代碼中的唯一更改。我做錯了什麼?

回答

7

你需要重寫的BootstrapperSelectAssemblies包括包含您的意見彙編。默認情況下,卡利科技將只包括Bootstrapper中定義的彙編

documentation

So, what is AssemblySource.Instance? This is the place that Caliburn.Micro looks for Views. You can add assemblies to this at any time during your application to make them available to the framework, but there is also a special place to do it in the Bootstrapper. Simply override SelectAssemblies like this:

protected override IEnumerable<Assembly> SelectAssemblies() 
{ 
    return new[] { 
     Assembly.GetExecutingAssembly() 
    }; 
} 

All you have to do is return a list of searchable assemblies. By default, the base class returns the assembly that your Application exists in. So, if all your views are in the same assembly as your application, you don’t even need to worry about this. If you have multiple referenced assemblies that contain views, this is an extension point you need to remember.

+0

即使包含的ViewModels的組件還包含了看法? – Ruhrpottpatriot 2015-04-05 17:24:49

+0

@Ruhrpottpatriot是的。如果我沒有記錯的話,給框架一個視圖模型,它的默認定位器使用它來查找視圖。它通過名稱空間執行此操作並搜索註冊的程序集。 – 2015-04-05 17:33:51

+0

這個過程是否可以與目錄目錄一起工作?或者我必須通過'Assembly.Load()'加載所有程序集? – Ruhrpottpatriot 2015-04-05 17:50:02

相關問題