任何人都可以使用mef和mvvm模式给我一个简单的wpf应用程序。我在互联网上看了很多,但我发现很少的例子,这些例子很难理解。一些例子是wpf,mef但不遵循mvvm模式。
这是我想要做的。
将有一个主要的wpf应用程序。这将加载所有模块(插件)并将其显示给用户。一个模块将包含2或3页,后面有后退按钮(用于导航)。现在,当在主应用程序中我选择一个模块,模块打开或你可以说它取代当前窗口和按钮导航时它会改变模块的视图。
主窗口 - >模块1 - >第1页
Page 2 Page 3 Module 2 -> Page 1 Page 2 Page 3
现在看起来很干净。模块1是一个单独的项目,模块2是一个单独的项目。主窗口从dll读取模块并显示它们。单击模块将浏览其页面。
答案 0 :(得分:3)
微软有一些参考实现,你可能会发现它们很有用。它们是MVVM / MEF和WPF的良好展示。 here's关于StockTrader RI实施的第一篇博客,下载链接指向here。 StockTrader RI和MVVM RI实施的Microsoft概述具体为here和here's StockTrader RI实施。第h
答案 1 :(得分:3)
这几天我做了2个项目,这样做你想要的。我所做的就是建立一个主项目,除了通过MEF收集模块并处理模块的选择之外什么都不做。您还需要一个组件项目,您可以在其中设置接口和导出属性。
这里有一些示例代码件:
MainProject app.xaml.cs
public partial class App : Application
{
[ImportMany]
private IEnumerable<Lazy<IComponent, IComponentMetadata>> _components;
private CompositionContainer _mefcontainer;
protected override void OnStartup(StartupEventArgs e)
{
ShutdownMode = ShutdownMode.OnExplicitShutdown;
//i do login stuff here
//i use task.factory here and dynamic splashscreen here
this.MefContainer.ComposeParts(rahmen, this);
foreach (var component in _components)
{
//check metadata and fill modules collection
}
//add modules collection to mainwindowviewmodel
ShutdownMode = ShutdownMode.OnMainWindowClose;
this.MainWindow.Show();
}
}
Component.dll
public interface IComponent//Marker interface
{
bool HasChanges { get; }
}
public interface IComponentMetadata
{
string Displayname { get; }
int SortIndex { get; }
string ImagePath { get; }
string IconPath { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ComponentExportAttribute : ExportAttribute, IComponentMetadata
{
private const string DEFAULTICON = "pack://application:,,,/MyComponent;Component/Images/Default.png";
public ComponentExportAttribute(string displayname, int sortindex): base(typeof(IComponent))
{
this.Displayname = displayname;
this.SortIndex = sortindex;
this.ImagePath = DEFAULTICON;
this.IconPath = DEFAULTICON;
}
public ComponentExportAttribute(string displayname, int sortindex, string imagepath, string iconpath): base(typeof(IComponent))
{
this.Displayname = displayname;
this.SortIndex = sortindex;
this.ImagePath = String.IsNullOrWhiteSpace(imagepath) ? DEFAULTICON : imagepath;
this.IconPath = String.IsNullOrWhiteSpace(iconpath) ? DEFAULTICON : iconpath;
}
#region Implementation of IComponentMetadata
public string Displayname { get; private set; }
public int SortIndex { get; private set; }
public string ImagePath { get; private set; }
public string IconPath { get; private set; }
#endregion
}
模块示例
[ComponentExport("Test1", 150
, "pack://application:,,,/TestProject;Component/Test/Logo1.png"
, "pack://application:,,,/TestProject;Component/Test/Icon1.png")]
public partial class Test1MainWindow : UserControl, IComponent
{
[ImportingConstructor]//if you want to do DI
public Test1MainWindow ()
{
InitializeComponent();
this.DataContext = this;
}
#region Implementation of IComponent
public bool HasChanges
{
get { return false; }
}
#endregion
}
或viewmodel export - &gt; (如果你这样做,你必须将数据模板导出到mainapp,如果你愿意,我可以显示这个)
[ComponentExport("Test2", 500
, "pack://application:,,,/TestProject;Component/Test/Logo2.png"
, "pack://application:,,,/TestProject;Component/Test/Icon2.png")]
public class Test2: INPCBase, IComponent
{
[ImportingConstructor]
public Test2()
{
}
#region Implementation of IKabuComponent
public bool HasChanges
{
get { return false; }
}
#endregion
}