如何在我的 MVVM 应用程序中利用 MEF?

发布于 2025-01-07 10:51:06 字数 540 浏览 5 评论 0原文

任何人都可以给我一个使用 mef 并遵循 mvvm 模式的简单 wpf 应用程序。我在互联网上查了很多,但发现的例子很少,而且这些例子很难理解。一些示例是 wpf、mef,但不遵循 mvvm 模式。

这就是我正在尝试做的事情。

将有一个主要的 wpf 应用程序。这将加载所有模块(插件)并将其显示给用户。一个模块将包含 2 或 3 个页面,带有下一个后退按钮(用于导航)。现在,当在主应用程序中我选择一个模块时,模块会打开,或者您可以说它会替换当前窗口,并且在按钮导航上它会更改模块的视图。

主窗口 ->模块 1 ->第1页

<前><代码> 第 2 页 第3页 模块2->第1页 第2页 第3页

现在看起来很干净。模块 1 是一个单独的项目,模块 2 是一个单独的项目。主窗口从 dll 读取模块并显示它们。单击模块将浏览其页面。

Can anybody give me a simple wpf application using mef and following mvvm pattern. I have looked a lot on the internet but i found very few examples and those example are very complex to understand. some examples are wpf, mef but dont follow mvvm pattern.

here is what i am trying to do.

There will a main wpf application. This will load all the modules (plugins) and show it to user. A module will contain 2 or 3 pages with next back buttons (used for navigation). Now when in main application i select a module, module opens or what you can say it replaces current window and on button navigation it changes views of the module.

Main Window -> Module 1 -> Page 1

                       Page 2

                       Page 3

           Module 2 -> Page 1

                       Page 2

                       Page 3

So it look clean now. Module 1 is a seperate project, module 2 is a seperate project. main window reads modules from dll and show them. clicking a module will go through its pages.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

╭⌒浅淡时光〆 2025-01-14 10:51:06

Microsoft 有一些参考实现,您可能会发现它们很有用。它们是 MVVM / MEF 和 WPF 的良好展示。 这里第一篇关于 StockTrader RI 实现的博客,下载链接指向 此处。 Microsoft 对 StockTrader RI 和 MVVM RI 实现的概述为 这里,和这里是专门的 StockTrader RI 实现。嗯。

Microsoft has a few reference implementations lying around that you may find useful. they are a good showcase of MVVM / MEF and WPF. here's the very first blog about the StockTrader RI implementation with the download link pointing here. the Microsoft overview of the StockTrader RI and MVVM RI implementations are here, and here's the StockTrader RI implementation specifically. hth.

风吹雨成花 2025-01-14 10:51:06

这些天我做了两个项目,它们可以满足你的需求。我所做的就是建立一个主项目,它的作用只是通过 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
}

Modul 示例

[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
}

或视图模型导出 --> (如果你这样做,你必须将数据模板导出到主应用程序,如果你愿意,我可以显示这个)

[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
}

i did 2 projects these days which do that what you want. what i have done is to set up a main project which does nothing more than collecting the modules via MEF and handle the selection of the module. you also need a component project where you set up the interfaces and export attributes.

here some sample code pieces:

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
}

Modul example

[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
}

or viewmodel export --> (if you do this you have to export a datatemplate to the mainapp, i can show this if you want)

[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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文