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