正确分离视图和视图模型

时间:2017-06-12 13:48:15

标签: c# wpf mvvm

我是初学者,在设置WPF项目和遵循MVVM模式时遇到问题;我没有看到如何将视图链接到viewmodel与下面的组织:

我在名为“Company.App.UI”的项目的根目录中设置了3个文件夹:Model,View和ViewModel。 App.xaml和MainWindow.xaml是项目的根源。

从这开始,我希望通过以下方式控制MainWindow客户区中显示的内容: - 将“View”文件夹中的渲染视图作为UserControls,例如“LoginView.xaml” - 在“ViewModel”文件夹中具有相应的视图模型,例如“LoginView.xaml.cs”

然后我在MainWindow.xaml中所做的是:

<Window x:Class="Company.App.UI.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewmodel="clr-namespace:Company.App.UI.ViewModel"
        xmlns:view="clr-namespace:Company.App.UI.View" <!-- does not work, not a namespace -->
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate DataType="{x:Type viewmodel:LoginViewModel}">
            <view:LoginView/> <!-- does not work -->
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <ContentControl Content="{Binding ClientArea}"/>
        </StackPanel>
    </Grid>        
</Window>

在MainWindow.xaml.cs:

using System.Windows;
using System.Windows.Controls;
using Company.App.UI.ViewModel;

namespace Company.App.UI
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
  {
    private UserControl _ClientArea = null;

    public UserControl ClientArea
    {
      get { return _ClientArea; }
      set { _ClientArea = value; }
    }

    public MainWindow()
    {
      if (_ClientArea == null) { ClientArea = new LoginViewModel(); }
      InitializeComponent();
    }
  }
}

LoginView是一个带有一个Label的简单UserControl,只是为了看它是什么。 如果我将LoginView.xaml放在项目的根目录下,在MainWindow.xaml旁边,它可以工作...... 我做错了什么/错过了什么? 我不想使用任何框架(PRISM等)来实现这一点。 如果我的帖子是重复但我在搜索时也找不到它,我很抱歉。 谢谢,

更新

我使用VS2013和0更新/补丁/等 一切都在同一个项目中。

错误输出是:

  1. 类型或命名空间名称“View”不存在于 namespace'Company.App.UI'(您是否缺少程序集引用?)
  2. 命名空间中不存在名称“LoginView”     “CLR-名称空间:Company.App.UI.View”
  3. 找不到类型'视图:LoginView'。验证您是否缺少程序集引用,并且已构建所有引用的程序集。
  4. LoginView.xaml:

    <UserControl x:Class="Company.App.UI.ViewModel.LoginViewModel"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
            <Label>User control login</Label>
        </Grid>
    </UserControl>
    

    LoginViewModel.cs:

    using System.Windows.Controls;
    
    namespace Company.App.UI.ViewModel
    {
      public partial class LoginViewModel : UserControl
      {
        public LoginViewModel()
        {
    
        }
      }
    }
    

3 个答案:

答案 0 :(得分:0)

LoginView.xaml 中更改此内容:

x:Class="Company.App.UI.ViewModel.LoginViewModel"   

到这个

x:Class="Company.App.UI.ViewModel.LoginView"

因为这是一个控件而不是ViewModel

此外, LoginView.xaml.cs 应该是这样的(没有看到您的实现):

using System.Windows.Controls;

namespace Company.App.UI.View
{
    /// <summary>
    /// Interaction logic for LoginView.xaml
    /// </summary>
    public partial class LoginView : UserControl
    {
        public LoginView()
        {
            InitializeComponent();
        }
    }
}

当你掌握它的时候(mvvm)我会建议使用mvvm light toolkit来管道(没有必要重新发明轮子)

答案 1 :(得分:0)

完全......做任何改变伊戈尔告诉你的事。 与此同时,

更改您的MainWindow.xaml.cs

 if (_ClientArea == null) { ClientArea = new LoginViewModel(); }

 if (_ClientArea == null) { ClientArea = new LoginView(); }

另外根据我的理解,你只想从用户控件到主窗口显示一个标签,并想学习MVVM概念。所以这里是你的例子的解释,可以帮助你

 <Grid>
        <!--connect to viewmodel-->
        <Grid.DataContext>
         <viewmodel:LoginViewModel></viewmodel:LoginViewModel>
        </Grid.DataContext>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!--import user control-->
        <view:LoginView Grid.Row="0"></view:LoginView>

        <StackPanel Grid.Row="1" Orientation="Horizontal">
            <ContentControl Content="{Binding ClientArea}"/>
        </StackPanel>

    </Grid>

注意 - 尝试在后面的任何代码中保留零代码。这是主要的  MVVM的目的。它应该只有

  • 模型......(应该纯粹只是属性的类文件)
  • 查看...(usercontrols,xaml,窗口文件应该只包含
    带有零代码的xaml代码)
  • Modelview ...(应该包含纯连接的类文件 视图和模型之间,不应包含任何对象 视图或模型。它通过绑定连接)

我也不知道你创建'ClientArea'的目的是什么......你在某个地方定义了它的内容吗?  如果您需要任何帮助,请告诉我......我在MVVM上有一些示例演示项目。

答案 2 :(得分:0)

具有类似目的的帖子也帮助我做事:

Binding a ContentControl to UserControl, and reuse same instance

这里有一个很好的主题:How to preserve the full state of the View when navigating between Views in an MVVM application?

在我发布问题(...)之后发现的另一个好处:https://msdn.microsoft.com/en-us/library/gg405484(v=pandp.40).aspx

基本上我想要实现的是在一个窗口内管理内容区域,而不管任何框架,更精确地管理“交易”,即在用户交互时从一个屏幕切换到另一个屏幕。

感谢所有评论,事情越来越清晰。