C# 正确分离视图和视图模型

C# 正确分离视图和视图模型,c#,wpf,mvvm,C#,Wpf,Mvvm,我是初学者,在设置WPF项目和遵循MVVM模式方面有问题;我不知道如何将视图链接到具有以下组织的viewmodel: 我在名为“Company.App.UI”的项目根目录下设置了3个文件夹:Model、View和ViewModel。 App.xaml和MainWindow.xaml位于项目的根目录下 首先,我希望通过以下方式控制主窗口客户端区域中显示的内容: -将文件夹“View”中的渲染视图作为用户控件,例如“LoginView.xaml” -在文件夹“ViewModel”中具有相应的视图模型

我是初学者,在设置WPF项目和遵循MVVM模式方面有问题;我不知道如何将视图链接到具有以下组织的viewmodel:

我在名为“Company.App.UI”的项目根目录下设置了3个文件夹:Model、View和ViewModel。 App.xaml和MainWindow.xaml位于项目的根目录下

首先,我希望通过以下方式控制主窗口客户端区域中显示的内容: -将文件夹“View”中的渲染视图作为用户控件,例如“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>

LoginView.xaml中更改以下内容:

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

x:Class="Company.App.UI.ViewModel.LoginView"
因为这是一个控件而不是ViewModel

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

使用System.Windows.Controls;
名称空间Company.App.UI.View
{
/// 
///LoginView.xaml的交互逻辑
/// 
公共部分类LoginView:UserControl
{
公共登录视图()
{
初始化组件();
}
}
}

当您掌握了窍门(mvvm)后,我建议您使用用于管道的(无需重新发明轮子)

正是。。。。做伊戈尔告诉你的任何改变。 除此之外,

更改MainWindow.xaml.cs

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

根据我的理解,您只需要将一个标签从用户控件显示到主窗口,并学习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代码(零代码落后)
  • 模型视图。。。(类文件,其中应包含纯连接。) 在视图和模型之间,不应包含任何 视图或模型。它通过绑定进行连接)
我也不知道你创造“ClientArea”的目的是什么。。。您在什么地方定义了它的内容吗?

如果你需要帮助,请告诉我。。。我有一些关于MVVM的示例演示项目

类似目的的帖子也帮助我得到了一些东西:

,

这里有一个极好的主题:

在我发布我的问题后,我发现了另一个好的开始点(…):

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


感谢所有的评论,事情变得越来越清楚。

文件夹结构与此无关。您必须在代码文件中使用适当的名称空间声明,例如,
namespace Company.App.UI.View{…}
“它工作”-什么不工作?您想要工作代码吗?
ClientArea
被声明为
UserControl
(非常糟糕的主意)。然后将名为
LoginViewModel
的内容分配给它。什么是
LoginViewModel
?它是viewmodel还是控件?要绑定到窗口的属性而不是窗口的
DataContext
(保留为空)的属性,请使用相对源/祖先类型绑定:
Content=“{binding clientrea,RelativeSource={RelativeSource AncestorType=window}”
要记住的基本规则。您的ViewModel不使用
System.Windows.Controls名称空间。我从上面的所有评论中看到了我的错误:错误是混淆了后面的xaml代码(.xaml.cs)和另一个.cs的viewmodel。我很高兴它有帮助!!1.
x:Class="Company.App.UI.ViewModel.LoginView"
using System.Windows.Controls;

namespace Company.App.UI.View
{
    /// <summary>
    /// Interaction logic for LoginView.xaml
    /// </summary>
    public partial class LoginView : UserControl
    {
        public LoginView()
        {
            InitializeComponent();
        }
    }
}
 if (_ClientArea == null) { ClientArea = new LoginViewModel(); }
 if (_ClientArea == null) { ClientArea = new LoginView(); }
 <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>