Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在WPF中实现MVVM模式的正确方法_C#_.net_Wpf_Xaml_Mvvm - Fatal编程技术网

C# 在WPF中实现MVVM模式的正确方法

C# 在WPF中实现MVVM模式的正确方法,c#,.net,wpf,xaml,mvvm,C#,.net,Wpf,Xaml,Mvvm,我刚开始学习来自JavaSwing和WinForms的WPF。我决定尝试一些新的东西来学习开发程序的其他概念和技术。上次,我介绍了MVC模式的概念。据我所知,这是一种分离UI逻辑、业务逻辑和数据的方法。我发现WPF的关键概念之一是绑定和MVVM模式 下面是我尝试实现MVVM的代码的一部分 MainWindowModel.cs using System; using System.Collections.Generic; using System.ComponentModel; using Sys

我刚开始学习来自JavaSwing和WinForms的WPF。我决定尝试一些新的东西来学习开发程序的其他概念和技术。上次,我介绍了MVC模式的概念。据我所知,这是一种分离UI逻辑、业务逻辑和数据的方法。我发现WPF的关键概念之一是绑定和MVVM模式

下面是我尝试实现MVVM的代码的一部分

MainWindowModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Controls;

namespace DocNanzDCMS.Model
{
    public class MainWindowModel : INotifyPropertyChanged
    {
        private PropertyChangedEventArgs pce;

        public MainWindowModel()
        {
            pce = new PropertyChangedEventArgs("");
        }

        private UserControl userControl;
        #region ControlProperty
        public UserControl ContentProperty {
            get
            {
                return userControl;
            }

            set
            {
                userControl = value;
                PropertyChanged(this, pce);
            }
        }
        #endregion

        private DateTime dateTime;
        #region DateProperty
        public String DateProperty
        {
            get
            {
                return dateTime.ToLongDateString();
            }
            set
            {
                dateTime = DateTime.Parse(value);
                PropertyChanged(this, pce);
            }
        }
        #endregion

        public String TimeProperty
        #region TimeProperty
        {
            get
            {
                return dateTime.ToLongTimeString();
            }
            set
            {
                dateTime = DateTime.Parse(value);
                PropertyChanged(this, pce);
            }
        }
        #endregion

        private String title;
        public String TitleProperty
        #region TitleProperty
        {
            get
            {
                return title;
            }
            set
            {
                title = value;
                PropertyChanged(this, pce);
            }
        }
        #endregion

        public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
    }
}
MainWindowViewModel.cs

using DocNanzDCMS.Model;
using DocNanzDCMS.View;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace DocNanzDCMS.ViewModel
{
    public class MainWindowViewModel
    {
        private MainWindow mainWindow;
        private MainWindowModel mainWindowModel;
        private Thread mainWindowThread;

        private LoginModel loginModel;
        private LoginViewModel loginViewModel;
        private LoginView loginView;

        private String title;

        public MainWindowViewModel(MainWindowModel mainWindowModel, MainWindow mainWindow)
        {
            this.mainWindowModel = mainWindowModel;
            this.mainWindow = mainWindow;
            initialize();
        }

        private void initialize()
        {
            loginModel = new LoginModel();
            loginView = new LoginView();
            loginViewModel = new LoginViewModel(loginModel, loginView);

            mainWindow.DataContext = mainWindowModel;
            mainWindowThread = new Thread(BackgroundProcess);
            mainWindowThread.IsBackground = true;
            mainWindowThread.Start();

            gotoLogin();
        }

        private void BackgroundProcess()
        {
            while(true)
            {
                updateTitle();
                updateTime();
                try
                {
                    Thread.Sleep(100);
                }
                catch(ThreadInterruptedException e)
                {
                }
            }
        }

        public void gotoLogin()
        {
            mainWindowModel.ContentProperty = loginView;
            title = "Login";
        }

        private void updateTime()
        {
            mainWindowModel.DateProperty = DateTime.Now.ToString();
            mainWindowModel.TimeProperty = DateTime.Now.ToString();
        }

        public void updateTitle()
        {
            mainWindowModel.TitleProperty = "Doc Nanz Dental | "+title;
        }
    }
}
MainWindow.cs

using DocNanzDCMS.Model;
using DocNanzDCMS.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DocNanzDCMS
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainWindowModel mainWindowModel;
        private MainWindowViewModel mainWindowViewModel;

        public MainWindow()
        {
            InitializeComponent();
            initializeApp();
        }

        private void initializeApp()
        {
            mainWindowModel = new MainWindowModel();
            mainWindowViewModel = new MainWindowViewModel(mainWindowModel, this);
        }
    }
}
使用DocNanzDCMS.Model;
使用DocNanzDCMS.ViewModel;
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Documents;
使用System.Windows.Input;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;
使用System.Windows.Navigation;
使用System.Windows.Shapes;
名称空间DocNanzDCMS
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
私有MainWindowModel MainWindowModel;
专用MainWindowViewModel MainWindowViewModel;
公共主窗口()
{
初始化组件();
初始化EAPP();
}
private void initializeApp()
{
mainWindowModel=新的mainWindowModel();
mainWindowViewModel=新的mainWindowViewModel(mainWindowModel,此);
}
}
}
MainWindow.xaml

<Window x:Class="DocNanzDCMS.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DocNanzDCMS"
        mc:Ignorable="d"
        Title="{Binding TitleProperty}" Height="600" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="75"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        <!--Banner-->
        <Grid Grid.Row="0" Background="AliceBlue">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="225"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="200"/>
            </Grid.ColumnDefinitions>
            <!--Date and Time Panel-->
            <Grid Grid.Column="2" Background="Aquamarine">
                <Grid.RowDefinitions>
                    <RowDefinition Height="1.5*"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <!--Date Background-->
                <StackPanel Grid.Row="0" Background="BurlyWood"/>
                <!--Date-->
                <Label Grid.Row="0" Content="{Binding DateProperty}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                <!--Time Background-->
                <StackPanel Grid.Row="1" Background="BlanchedAlmond"/>
                <!--Time-->
                <Label Grid.Row="1" Content="{Binding TimeProperty}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </Grid>
        </Grid>
        <!--Content-->
        <ScrollViewer Grid.Row="1" Content="{Binding ContentProperty}"/>
        <!--Status Bar-->
        <Grid Grid.Row="2">

        </Grid>
    </Grid>
</Window>

我创建了一个模型和视图,并在ViewModel中操纵了它们。我不确定这是否是实现MVVM的正确方法,或者它甚至是MVVM,因为我将其视为MVC模式

维基百科上说:

组件包括:模型、视图、视图模型和活页夹


这部分代码显示一个带有横幅的窗口,横幅最右侧是显示日期和时间的标签。这是可行的,但我担心的是,我的做法是否真的遵循了MVVM模式。

你的问题非常广泛,但这里有一些想法

视图模型不应该知道关于视图的任何信息。您不应将
MainWindowViewModel
的引用注入
MainWindow
,而应将
MainWindow
DataContext
设置为视图模型的实例:

public MainWindow()
{
        InitializeComponent();
        DataContext = new MainWindowViewModel();
}
然后,当视图绑定到视图模型时,主窗口视图模型可以初始化和/或与模型通信


此外,视图模型不应公开任何
ui元素
,例如
UserControl
<代码>UIElements在视图中定义。

为了MVVM的缘故,视图模型不应包含对视图的引用(这被认为是错误的做法)

是了解ViewModel的视图,而不是相反的视图。 视图知道ViewModel,而ViewModel又知道一个或多个模型

INotifyPropertyChanged接口应在ViewModel中实现,以允许视图通过绑定进行自我更新(在某些情况下,在模型上实现接口也是完全合法的)

请记住,可以将ViewModel视为一个适应视图需要的模型,因此,考虑到这一点,我更愿意将模型类作为简单对象,并在ViewModel上编写INotifyPropertyChanged实现

ViewModel成为视图的DataContext(您可以在代码隐藏或xaml中在视图的构造函数中分配DataContext)

要在视图中导航,可以使用(至少)2种方法

您应该决定是使用“视图优先”方法还是“视图模型优先”方法

在“视图优先”方法中,当您想要导航到新页面时,您将创建一个视图,并且一些机制(活页夹)将创建相应的ViewModel(后者反过来创建或获取模型)

在ViewModel first方法中,您将创建一个新的ViewModel(它将创建或获取模型),活页夹将创建相应的视图

根据我告诉你的,这里有一个例子:

视图(MainWindowView.cs),我们分配DataContext:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new MainWindowViewModel()
    }
}
ViewModel(MainWindowViewModel.cs):

模型(MainWindowModel.cs):


此外,我认为您应该研究一些类似或(我更喜欢第一个)的框架,以帮助您正确实现MVVM模式,而不是重新发明轮子(此外,您还将获得一个导航系统,用于在视图之间导航)。

经过几夜的学习,我终于“吸收”了MVVM的概念及其与MVC的区别

模型-大多数时候它们只是具有属性的类。像
用户
产品

查看-用户界面<代码>注册表服务视图,
登录视图
添加产品视图

ViewModel-这是操作发生的地方<代码>视图模型根据需求/规则操作模型,并将其公开给
视图
。但是
ViewModel
不知道
View
的存在

绑定-这是
视图
视图模型
之间的粘合剂

与MVC相比(只是我的观点)

  • MVC
    中的
    View
    是被动的,而
    MVVM
    中的
    View
    是主动的。
    MVC
    中的
    控制器
    决定了什么是
    namespace DocNanzDCMS.ViewModel
    {
        public class MainWindowViewModel : INotifyPropertyChanged
        {
            private MainWindowModel mainWindowModel;
            public Model {get {return mainWindowModel;}}
    
            public MainWindowViewModel()
            {
                this.mainWindowModel = new mainWindowModel();
            }
        }
    }
    
    public class MainWindowModel
    {
            private PropertyChangedEventArgs pce;
    
            public MainWindowModel()
            {
                pce = new PropertyChangedEventArgs("");
            }
    
            private UserControl userControl;
            #region ControlProperty
            public UserControl ContentProperty {
                get
                {
                    return userControl;
                }
    
                set
                {
                    userControl = value;
                    PropertyChanged(this, pce);
                }
            }
            #endregion
    
            private DateTime dateTime;
            #region DateProperty
            public String DateProperty
            {
                get
                {
                    return dateTime.ToLongDateString();
                }
                set
                {
                    dateTime = DateTime.Parse(value);
                    PropertyChanged(this, pce);
                }
            }
            #endregion
    
            public String TimeProperty
            #region TimeProperty
            {
                get
                {
                    return dateTime.ToLongTimeString();
                }
                set
                {
                    dateTime = DateTime.Parse(value);
                    PropertyChanged(this, pce);
                }
            }
            #endregion
    
            private String title;
            public String TitleProperty
            #region TitleProperty
            {
                get
                {
                    return title;
                }
                set
                {
                    title = value;
                    PropertyChanged(this, pce);
                }
            }
            #endregion
    
            public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
     }