我已经为我的应用程序做了一个根AppView,一个根AppViewModel作为所有东西的容器。在应用程序视图中,我有一个TabControl,每个选项卡都有自己的任务要做。一个标签用于导入数据,一个标签用于发布,一个标签用于管理等:
App_View[Model] // root
{
TabTask1_View[Model], TabTask2_View[Model], TabTask3_View[Model] // tab items
}
1)在MVVM中,我将整个视图和视图模型分组到主应用程序视图和应用程序模型视图中是否标准?
2)在MVVM中,应该为每个视图实现模型;虚拟机?或者,如果我将整个模型实现到一个或两个类文件中并在它们之间共享模型,这是标准的吗?我个人认为模型部分不是特定于某个视图的,就像类'student'可以在代码中的任何地方使用,并且不限于某个视图。基于此,如果模型是通用和共享的,那么遵循命名约定Class + 'Model'是否合适?喜欢StudentModel吗?像我说的那样,在一般或共享类名称之后添加"模型"是否有帮助/必要?
3)在WPF中,实现视图的最佳方式是什么?我想编辑和设计非常容易,没有任何限制,它应该是标准的,足以满足未来的需求。有4个东西可以使用:Window, Page, UserControl和DataTemplate。哪一个是你最好的选择?用户控制还是页面?
4)在WPF中,我如何在运行时基于MVVM方法动态加载tabItem中的UserControl/Page(View) ?
你在作弊。一共4个问题!
1)
关于如何对视图和视图模型进行分组,我看到有人将视图和视图模型放在同一个命名空间/文件夹中,而其他人则根据功能将它们分离到不同的文件夹中。你的最佳选择是适合你/你的团队的。没有"正确"的方法。
2)
保持干燥-所以不要重复自己。重用代码是非常明智的。如果你有共同的类,保持它们共同。至于命名,类的名称应该有助于解释它的功能:我确信你能够弄清楚类NavigationService, NavigationMenuItem和NavigationMenuView做了什么,并且可能可以将它们如何关联的良好心智模型放在一起。所以-如果命名一个类BlahViewModel或BlahModel是有用的,做它。
3)实现视图:
窗口总是独立显示。页面用于导航应用程序(通常带有后退和前进按钮,例如Internet Explorer)。页面必须托管在NavigationWindow或Frame中。如果你想动态添加/删除内容,添加内容到ItemsControls (TabControl等),那么你会想要创建用户控件。你可以把用户控件放到页面和窗口对象中,放到其他控件中,等等,它是WPF开发人员的主力。
4)
这里有多个选项:
1)快速而肮脏的方法是创建DataTemplate,在给定类型为X的ViewModel时,加载并将ViewModel应用于其数据上下文。这将允许你将ViewModel直接注入到控件中,并获得正确的View渲染。
一个例子:
View.xaml
<ContentControl Content="{Binding Error, Mode=OneWay}" />
ViewModel:
private void ReceiveError(ErrorViewModel errorModel)
{
//if (errorModel.AcceptCommand==null || errorModel.AcceptCommand is NoOpCommand)
errorModel.AcceptCommand = new DelegateCommand(ClearError);
Error = errorModel;
}
public ErrorViewModel Error
{
get { return _error; }
set
{
_error = value;
_propertyChangedHelper.NotifyPropertyChanged(this, () => Error);
}
}
风格。Xaml (ResourceDictionary)
<DataTemplate DataType="{x:Type vm:ErrorViewModel}">
<DataTemplate.Resources>
<conv:CustomisableBooleanToVisibilityConverter x:Key="VisibilityConverter" TrueValue="Visible" FalseValue="Collapsed" />
</DataTemplate.Resources>
<Popup AllowsTransparency="True" PopupAnimation="Fade" Placement="Center" StaysOpen="True"
PlacementTarget="{Binding Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:ModuleView}}}"
IsOpen="True" Width="400" SnapsToDevicePixels="True"/>
所以你可以看到我把我的视图模型直接注入到内容控件中它使用绑定到视图模型类型的数据模板来为它找到一个视图
2)一个更好的选择是使用DataTemplateSelector。这基本上允许您指定哪些模板可用于控件,然后使用您编写的逻辑来确定要使用哪个数据模板。你可以在这里找到一个例子。
3)
使用抽象UI控件的框架。微软有一个名为Prism的框架(免费)来做这件事。基本上,不是将你的用户控件直接添加到TabControl、ItemsControl等,而是将你的控件添加到一个名为"Region"的控件中。该区域被映射到一个底层控件,并放置一个适配器来管理如何在您要求时添加/删除usercontrol。您可以在这里找到对此的深入讨论。但是要注意,Prism是一个应用程序框架,因此实现它不是3个小时的工作。
这不是一个答案,这是我的经验,我将向你解释我如何处理MVVM。3个月前,我开始使用WPF,并且我能处理它。
-
对于每个新的主题/菜单/选项,我创建一个新的项目文件,其中包含ViewModels和Views。所有的业务类都收集在一个项目文件中,因为我可能不得不在多个ViewModel中使用它。
-
是的,它是帮助我作为初学者命名类…ViewModel和..View。它使我很容易区分差异,也更容易向其他人解释你的类(例如,如果你对你的编码有问题)
-
我使用UserControls为我们的不同的视图,我加载它们到ContentControls和TabControls没有任何问题。
-
看看Prism的mvvm模式。
点1:
视情况而定。AFAIK有两种广泛使用的方法。首先,正如您所说,将构成相同Window
的所有VM与直接依赖关系分组,以形成显示实际程序结构的类结构。第二种是使用EventAggregator
(Prism)/Messenger
(MVVM Light)松散地连接VM,而不是直接依赖。
两种方法都有各自的优点
- 用第一种方法很容易识别你的程序结构,因为你的VM依赖关系清楚地显示出来,这在第二种方法中不那么清晰可见。
- 第二种方法在单元测试VM时帮助你很多,因为你不需要模拟或绕过所有依赖的VM,它也有助于在改变项目结构时重构代码(想想"Plug in"类)
哦,这些^^绝不是排他的。你可以把这些混合在一起。
点2:
模型与视图/VM之间没有任何推荐的1 <-> 1关系,就像视图与VM之间的关系一样。模型只是保存您的业务逻辑。我有的应用程序有时根本不支持Model。有些东西只有一个模型被整个应用程序使用(当后端是一个c++库,你只是用c++/CLI模块与它接口)。保持命名约定,在Model类名后面加上"Model"
3
所有的呢?在合适的地方使用它们。不要偏袒任何一方。当一个视图由多个其他部分组成,这些部分本身就是一个带有VM的视图时,我会有一个DataTemplate
和数据UserControl
。你的应用几乎总是使用一个窗口和Page
是有用的基于导航的应用程序,我认为。我想Page
是我用得最少的。
点4
这是教程的问题。举一些例子,看看它是如何实现的,对它进行推理,然后选择你的方法。如果你使用VS2010得到MVVM在盒子里(这是伟大的。没有第二条路。真的希望这可以得到更新VS2012,如果它还没有)。对于VS2012,请查看Two Views MVVM CodeProject,其中显示了该概念,然后您可以将其应用于您选择的任何ItemsControl
。
最后,至少在启动时,PLEASE从使用MVVM辅助库开始。我更喜欢MVVM Light <这个链接有几个视频,由库的作者展示了一些用法,你可以在SO上找到关于它的大量帮助。如果你想自己做一些事情,那就从中学习基础知识,然后自己实现它。如果你从第一天开始就走高的道路,那只是一个更长的学习曲线(这只是我的观点)>