使用反射在C#中创建菜单

时间:2018-02-09 02:08:42

标签: c# wpf mvvm treeview

我正在尝试使用WPF TreeView控件创建菜单。为此,我创建了一个接口,除了显示一些Read Only属性(菜单标题的一个项目和实际菜单项的一个项目)之外什么都不做,我可以将TreeView控件绑定到。

我创建的每个ViewModel都将实现此接口,并且两个属性的值将在属性的getter中进行硬编码。

是否可以使用反射来获取这些属性的值(在实例化之前),并将它们放入我的TreeView控件可以绑定到的某种形式的列表或数组中?

目标是不必将所有菜单项硬编码到TreeView,而是使用我到目前为止编写的所有ViewModel填充控件(即,每次创建视图模型时,它将“显示”在菜单,当然重新编译程序集后!)。

我可以使用以下方法获取影响界面的类的名称:

foreach (Type mytype in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
              .Where(mytype => mytype.GetInterfaces().Contains(typeof(IInterfaceName))))
        {
            c.Add(mytype);

        }

此代码用于获取实现接口的类的名称,但在此之后我陷入困境。

我想做的甚至可能吗?如果我没有走上正轨,我也会感谢任何其他方法来实现相同的结果。我不想在WPF中硬编码值,也不想在创建新的视图模型时将记录添加到数据库中。

这是我想要创建的内容的模拟: Mockup

1 个答案:

答案 0 :(得分:1)

我强烈建议调查Managed Extensibility Framework(MEF)。 MVVM和MEF非常适合,因为MVVM的目标最终解决了单独的问题,而MEF是使松散耦合变得非常容易的技术。 MVVM关注的是将单独的层解耦,但是将不同的视图模型彼此解耦也是有利的(这基本上就是你要求的)。以下是如何开始使用MEF来实现您的特定问题的一个非常基本的示例。

首先,您需要为子视图模型创建一个接口:

public interface ISubViewModel
{
    string Name { get; }
    IView View { get; }
    //... whatever else you need
}

现在,您将拥有某种父视图或主视图:

[Export]
public class ParentViewModel
{
    [ImportMany] // <- this attribute tells MEF to look for all exports of type ISubViewModel
    public IEnumerable<ISubViewModel> ViewModels { get; set; }

    //... whatever else you need
}

现在您可以根据需要直接删除多个子视图模型,它们将自动显示在ParentViewModel的ViewModels属性中:

[Export(typeof(ISubViewModel))]
public class MySubViewModel1 : ISubViewModel { /* ... */ }

[Export(typeof(ISubViewModel))]
public class MySubViewModel2 : ISubViewModel { /* ... */ }

[Export(typeof(ISubViewModel))]
public class MySubViewModel3 : ISubViewModel { /* ... */ }

唯一剩下的就是设置MEF容器。要使[ImportMany]属性在ParentViewModel中工作,我们必须让MEF构建它。我们将设置容器并向其询问ParentViewModel(也许这将在您的App.xaml.cs中)

public void Startup()
{
    var catalog = new AggregateCatalog();  
    catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
    var container = new CompositionContainer(catalog);
    var parentViewModel = container.GetExportedValue<ParentViewModel>();
    parentViewModel.Show();
}

在幕后,MEF基本上以你在你的例子中尝试的方式使用反射,但是MEF使它变得更容易并且隐藏了你的所有反射丑陋,所有你需要做的就是添加适当的{{ 1}}和[Import]属性。

使用MEF有点像异步/等待它倾向于&#34;入侵&#34;你的整个代码库。您创建的任何类都可以使用[Export][Import](或构造函数注入,请参阅文档),只要它是[ImportMany] - ed并由MEF检索它的实例。有关使用MEF的完整MVVM样式应用程序的一个很好的示例,请查看WAF示例(还有其他MVVM框架使用MEF或其他类型的DI,但我个人最多熟悉WAF)。

在整个应用程序中使用这样的MEF的结果将是一个非常模块化且松散耦合的应用程序,这对于可测试性来说非常可怕。