C# MVVM解决方案结构

C# MVVM解决方案结构,c#,xaml,mvvm,C#,Xaml,Mvvm,我想了解构建MVVM解决方案的最佳实践 目前,我已经为我的视图和我的ViewModel创建了一个单独的项目。我的视图项目引用我的ViewModel项目。到现在为止,一直都还不错。在实现导航时,我的ViewModel类需要访问根框架才能四处导航,但根框架位于视图项目中的App.xaml中。所以我这里有一个循环依赖性问题 是否有我应该使用的推荐结构?我可以将这一切合并到一个大项目中,但为了将视图和视图模型解耦,我觉得使用单独的项目是一种更好的方法。MVVM没有最佳实践,因为它是一种设计模式,每个人都

我想了解构建MVVM解决方案的最佳实践

目前,我已经为我的视图和我的ViewModel创建了一个单独的项目。我的视图项目引用我的ViewModel项目。到现在为止,一直都还不错。在实现导航时,我的ViewModel类需要访问根框架才能四处导航,但根框架位于视图项目中的App.xaml中。所以我这里有一个循环依赖性问题


是否有我应该使用的推荐结构?我可以将这一切合并到一个大项目中,但为了将视图和视图模型解耦,我觉得使用单独的项目是一种更好的方法。

MVVM没有最佳实践,因为它是一种设计模式,每个人都会根据自己的喜好以不同的方式实现。我见过很多不同的实现,但从未在单独的项目中看到视图和视图模型。我建议将它们保存在同一项目中的不同文件夹中,并将它们放在不同的名称空间中

e、 g.视图模型可以放在ViewModels文件夹中,并位于名称空间MyProject.ViewModels中

您的视图可以放在视图文件夹中,并位于名称空间MyProject.Views中


如果您正在使用MVVM,模型也是如此,MVVM没有最佳实践,因为它是一种设计模式,每个人都会根据自己的喜好以不同的方式实现。我见过很多不同的实现,但从未在单独的项目中看到视图和视图模型。我建议将它们保存在同一项目中的不同文件夹中,并将它们放在不同的名称空间中

e、 g.视图模型可以放在ViewModels文件夹中,并位于名称空间MyProject.ViewModels中

您的视图可以放在视图文件夹中,并位于名称空间MyProject.Views中

如果您正在使用模型,则模型也是如此

在实现导航时,我的ViewModel类需要访问根框架

这是一个错误的假设

您可以使用负责在发布者(ViewModels)和订阅者(负责打开视图的某些对象)之间分发消息的MessageBroker(单个对象)

大多数MVVM框架都有这样的代理

关于依赖关系的信息

经纪人的唯一责任是引发事件。因此,一般来说,它公开了发布者可以调用的两个方法和订阅者可以注册的两个事件

在MVVM中,您可以使用此机制让ViewModel引发事件,表示应打开视图,并让视图管理器订阅此事件。视图管理器应该能够实例化视图并附加正确的视图模型

为了防止ViewManager需要引用所有视图和ViewModels,可以传递到事件逻辑名称(仅一个字符串),并让视图管理器使用反射或配置文件中的静态列表查找匹配的视图(模型)类型

这样,您就不需要任何循环引用。事实上,当您发现需要引用MVVM中适当的依赖项时,首先应该怀疑设置,然后考虑使用视图和/或ViewModels的基类。< /P> 在实现导航时,我的ViewModel类需要访问根框架

这是一个错误的假设

您可以使用负责在发布者(ViewModels)和订阅者(负责打开视图的某些对象)之间分发消息的MessageBroker(单个对象)

大多数MVVM框架都有这样的代理

关于依赖关系的信息

经纪人的唯一责任是引发事件。因此,一般来说,它公开了发布者可以调用的两个方法和订阅者可以注册的两个事件

在MVVM中,您可以使用此机制让ViewModel引发事件,表示应打开视图,并让视图管理器订阅此事件。视图管理器应该能够实例化视图并附加正确的视图模型

为了防止ViewManager需要引用所有视图和ViewModels,可以传递到事件逻辑名称(仅一个字符串),并让视图管理器使用反射或配置文件中的静态列表查找匹配的视图(模型)类型


这样,您就不需要任何循环引用。事实上,当您发现需要引用MVVM中适当的依赖项时,首先应该怀疑设置,然后考虑使用视图和/或ViewModels的基类。< /P> < P>检查瑞秋的好答案。我还喜欢将视图和视图模型分开,因为这样我就知道什么时候我搞砸了MVVM的基本规则

ViewModel不应包含对视图的任何引用,但视图必须包含对ViewModel的引用。例如,我的自定义溅屏工厂(两条重要的线是“<强> VAR VIEWSMODE…<强>”和“<强> VAR溅屏…<强>”):

工厂项目同时引用了MyCompany.ViewModels和MyCompany.Views。视图项目仅引用了MyCompany.ViewModels

我们首先从调用方启动ViewModel(在本例中,从SplashScreenFactory启动;如果需要,也可以从App.xaml.cs启动;出于讨论之外的原因,我更喜欢使用自己的引导程序类)

然后,我们通过将ViewModel引用传递到视图的构造函数中来初始化视图。这就是所谓的。您可能还需要为Window类编写一个行为,以便从ViewModel关闭窗口。现在,我可以从引导程序类中执行以下操作:

/// <summary>
/// Called from this project's App.xaml.cs file, or from the Deals Main Menu
/// </summary>
public class Bootstrapper
{
    private SplashScreenViewModel _splashScreenVM;

    public Bootstrapper()
    {
        // Display SplashScreen
        _splashScreenVM = SplashScreenFactory.CreateSplashScreen(
            "MyCompany Deals", "Planning Grid", "Creating Repositories...", 200);

        // Overwrite GlobalInfo parameters and prepare an AuditLog to catch and log errors
        ApplicationFactory.AuditedDisplay(
            Assembly.GetExecutingAssembly().GetName(),
            () =>
            {
                // Show overwritten version numbers from GlobalInfo on SplashScreen
                _splashScreenVM.VersionString = string.Format("v{0}.{1}.{2}",
                    GlobalInfo.Version_Major, GlobalInfo.Version_Minor, GlobalInfo.Version_Build);

                // Initiate ViewModel with new repositories
                var viewModel = new PlanningGridViewModel(new MyCompany.Repositories.PlanningGridHeadersRepository(),
                    new MyCompany.Repositories.PlanningGridLinesRepository(),
                    _splashScreenVM);

                // Initiate View with ViewModel as the DataContext
                var view = new PlanningGridView(viewModel);

                // Subscribe to View's Activated event
                view.Activated += new EventHandler(Window_Activated);

                // Display View
                view.ShowDialog();
            });
    }

    /// <summary>
    /// Closes SplashScreen when the Window's Activated event is raised.
    /// </summary>
    /// <param name="sender">The Window that has activated.</param>
    /// <param name="e">Arguments for the Activated event.</param>
    private void Window_Activated(object sender, EventArgs e)
    {
        _splashScreenVM.ClosingView = true;
    }
//
///从该项目的App.xaml.cs文件或fr调用
/// <summary>
/// Called from this project's App.xaml.cs file, or from the Deals Main Menu
/// </summary>
public class Bootstrapper
{
    private SplashScreenViewModel _splashScreenVM;

    public Bootstrapper()
    {
        // Display SplashScreen
        _splashScreenVM = SplashScreenFactory.CreateSplashScreen(
            "MyCompany Deals", "Planning Grid", "Creating Repositories...", 200);

        // Overwrite GlobalInfo parameters and prepare an AuditLog to catch and log errors
        ApplicationFactory.AuditedDisplay(
            Assembly.GetExecutingAssembly().GetName(),
            () =>
            {
                // Show overwritten version numbers from GlobalInfo on SplashScreen
                _splashScreenVM.VersionString = string.Format("v{0}.{1}.{2}",
                    GlobalInfo.Version_Major, GlobalInfo.Version_Minor, GlobalInfo.Version_Build);

                // Initiate ViewModel with new repositories
                var viewModel = new PlanningGridViewModel(new MyCompany.Repositories.PlanningGridHeadersRepository(),
                    new MyCompany.Repositories.PlanningGridLinesRepository(),
                    _splashScreenVM);

                // Initiate View with ViewModel as the DataContext
                var view = new PlanningGridView(viewModel);

                // Subscribe to View's Activated event
                view.Activated += new EventHandler(Window_Activated);

                // Display View
                view.ShowDialog();
            });
    }

    /// <summary>
    /// Closes SplashScreen when the Window's Activated event is raised.
    /// </summary>
    /// <param name="sender">The Window that has activated.</param>
    /// <param name="e">Arguments for the Activated event.</param>
    private void Window_Activated(object sender, EventArgs e)
    {
        _splashScreenVM.ClosingView = true;
    }