百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

C#编程技巧:MVVM模式文件组织方式

liuian 2025-03-05 17:58 11 浏览


在WPF中使用MVVM模式开发时,合理管理文件和代码结构非常重要。以下是一个常见的文件组织和代码安排建议:

1. 项目结构

假设项目包括主窗口、菜单、工具栏、状态栏和3个嵌入式窗口,建议按功能或模块组织项目结构,例如:

MyWpfApp/
├── Models/
│   ├── SomeModel.cs
├── ViewModels/
│   ├── MainWindowViewModel.cs
│   ├── MenuViewModel.cs
│   ├── ToolbarViewModel.cs
│   ├── StatusBarViewModel.cs
│   ├── EmbeddedWindow1ViewModel.cs
│   ├── EmbeddedWindow2ViewModel.cs
│   ├── EmbeddedWindow3ViewModel.cs
├── Views/
│   ├── MainWindow.xaml
│   ├── MenuView.xaml
│   ├── ToolbarView.xaml
│   ├── StatusBarView.xaml
│   ├── EmbeddedWindow1View.xaml
│   ├── EmbeddedWindow2View.xaml
│   ├── EmbeddedWindow3View.xaml
├── Services/
│   ├── SomeService.cs
├── Resources/
│   ├── Styles.xaml
│   ├── Icons/
├── App.xaml
├── App.xaml.cs

2. View和ViewModel的绑定

通常通过DataContext将View与ViewModel绑定,可以在XAML或代码中完成。

XAML绑定


    
        
    
    

代码绑定

using System.Windows;
using MyWpfApp.ViewModels;

namespace MyWpfApp.Views
{
    public partial class MainWindow : Window
    {
         // 通过构造函数注入 MainWindowViewModel。
        public MainWindow(MainWindowViewModel viewModel)
        {
            InitializeComponent();
            DataContext = viewModel; // 设置 DataContext
        }
    }
}

3. 主窗口与嵌入式窗口的协调

主窗口的ViewModel可以管理其他ViewModel,并通过命令或事件协调它们。

public class MainWindowViewModel : INotifyPropertyChanged
{
    public MenuViewModel MenuViewModel { get; set; }
    public ToolbarViewModel ToolbarViewModel { get; set; }
    public StatusBarViewModel StatusBarViewModel { get; set; }
    public EmbeddedWindow1ViewModel EmbeddedWindow1ViewModel { get; set; }
    public EmbeddedWindow2ViewModel EmbeddedWindow2ViewModel { get; set; }
    public EmbeddedWindow3ViewModel EmbeddedWindow3ViewModel { get; set; }

    public MainWindowViewModel()
    {
        MenuViewModel = new MenuViewModel();
        ToolbarViewModel = new ToolbarViewModel();
        StatusBarViewModel = new StatusBarViewModel();
        EmbeddedWindow1ViewModel = new EmbeddedWindow1ViewModel();
        EmbeddedWindow2ViewModel = new EmbeddedWindow2ViewModel();
        EmbeddedWindow3ViewModel = new EmbeddedWindow3ViewModel();
    }

    // INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

4. 依赖注入

使用依赖注入(如
Microsoft.Extensions.DependencyInjection)可以更好地管理ViewModel和服务。在 App.xaml.cs 中配置依赖注入容器,并注册你的 ViewModel 和服务。

using Microsoft.Extensions.DependencyInjection;
using System;
using System.Windows;
using MyWpfApp.ViewModels;
using MyWpfApp.Services;

namespace MyWpfApp
{
    public partial class App : Application
    {
        private IServiceProvider _serviceProvider;

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            // 配置服务
            var serviceCollection = new ServiceCollection();
            ConfigureServices(serviceCollection);

            // 构建 ServiceProvider
            _serviceProvider = serviceCollection.BuildServiceProvider();

            // 显示主窗口
            var mainWindow = _serviceProvider.GetRequiredService();
            mainWindow.Show();
        }

        private void ConfigureServices(IServiceCollection services)
        {
            // 注册 ViewModel
            services.AddSingleton();
            services.AddSingleton();
            services.AddSingleton();
            services.AddSingleton();
            services.AddSingleton();
            services.AddSingleton();
            services.AddSingleton();

            // 注册服务
            services.AddSingleton();

            // 注册 View
            services.AddTransient();
        }
    }
}

在需要依赖服务的ViewModel中,通过构造函数注入。

示例:MenuViewModel 使用 IDataService

using MyWpfApp.Services;

namespace MyWpfApp.ViewModels
{
    public class MenuViewModel
    {
        private readonly IDataService _dataService;

        public MenuViewModel(IDataService dataService)
        {
            _dataService = dataService;
        }

        public void SomeMethod()
        {
            var data = _dataService.GetData();
            // 执行逻辑
        }
    }
}

5. 资源管理

将样式、模板等放在Resources/Styles.xaml中,并在App.xaml中引用。


    
        
            
        
    

6. 命令和事件

使用ICommand实现命令模式,处理用户交互。

public class RelayCommand : ICommand
{
    private readonly Action _execute;
    private readonly Func _canExecute;

    public RelayCommand(Action execute, Func canExecute = null)
    {
        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter) => _canExecute == null || _canExecute();

    public void Execute(object parameter) => _execute();

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}

7. 测试

为ViewModel编写单元测试,确保逻辑正确。

[TestClass]
public class MainWindowViewModelTests
{
    [TestMethod]
    public void TestSomeMethod()
    {
        var vm = new MainWindowViewModel();
        vm.SomeMethod();
        Assert.IsTrue(vm.SomeProperty);
    }
}

总结

通过合理的文件组织、依赖注入、命令模式等,可以更好地管理WPF MVVM项目,确保代码的可维护性和可扩展性。

相关推荐

使用Assembly打包和部署Spring Boot工程

SpringBoot项目的2种部署方式目前来说,SpringBoot项目有如下2种常见的部署方式一种是使用docker容器去部署。将SpringBoot的应用构建成一个docke...

java高级用法之:调用本地方法的利器JNA

简介JAVA是可以调用本地方法的,官方提供的调用方式叫做JNI,全称叫做javanativeinterface。要想使用JNI,我们需要在JAVA代码中定义native方法,然后通过javah命令...

Linux中如何通过Shell脚本来控制Spring Boot的Jar包启停服务?

SpringBoot项目在为开发者带来方便的同时,也带来了一个新的问题就是Jar包如何启动?在一般情况下我们都是采用了最为经典的java-jar命令来进行启动。然后通过ps命令找到对应的应用线程通...

牛逼!自己手写一个热加载(人民币手写符号一个横还是两个横)

热加载:在不停止程序运行的情况下,对类(对象)的动态替换JavaClassLoader简述Java中的类从被加载到内存中到卸载出内存为止,一共经历了七个阶段:加载、验证、准备、解析、初始化、使用、...

java 错误: 找不到或无法加载主类?看看怎么解决吧!

问题扫述:项目名称调整,由原来的com.mp.qms.report.biz调整为com.mp.busicen.mec.qms.report.biz后。项目在IDEA直接运行,但打包部署到服务器...

如何将 Spring Boot 工程打包成独立的可执行 JAR 包

导语:通过将SpringBoot项目打包成独立的可执行JAR包,可以方便地在任何支持Java环境的机器上运行项目。本文将详细介绍如何通过Maven构建插件将SpringBoot...

class 增量发包改造为 jar 包方式发布

大纲class增量发包介绍项目目录结构介绍jar包方式发布落地方案class增量发包介绍当前项目的迭代修复都是通过class增量包来发版本的将改动的代码class增量打包,如下图cla...

Jar启动和IDE里启动Sprintboot的区别

想聊明白这个问题,需要补充一些前提条件,比如Fatjar、类加载机制等1、Fatjar我们在开发业务程序的时候,经常需要引用第三方的jar包,最终程序开发完成之后,通过打包程序,会把自己的代码和三...

Java 20年,以后将往哪儿走?(java还能流行多久)

在今年的Java20周年的庆祝大会中,JavaOne2015的中心议题是“Java的20年”。甲骨文公司Java平台软件开发部的副总裁GeorgesSaab的主题演讲就将关注点放在了java...

Spring Boot Jar 包秒变 Docker 镜像实现多环境部署

你是否在互联网大厂后端开发工作中,遇到过这样的困扰?当完成一个SpringBoot项目开发,准备将Jar包部署到不同环境时,却发现各个环境依赖不同、配置复杂,部署过程繁琐又容易出错,不仅耗费...

从0开始,让你的Spring Boot项目跑在Linux服务器

1搭建Linux服务器1.1购买阿里云服务器或安装虚拟机这里建议是CentOS7.X或CentOS8.X,当然其他的Linux如deepin、Ubuntu也可以,只是软件环境的安装包和安装方式...

【技术】Maven 上传第三方jar包到私服

通过nexus后台上传私服以NexusRepositoryManagerOSS2.14.5-02为例。登录nexus后台。定义Maven坐标Maven坐标有两种方式:1.自定义参数;2....

JVM参数、main方法的args参数使用

一、前言我们知道JVM参数分为自定义参数、JVM系统参数,Javamain方法的参数。今天就谈谈怎么使用吧。二、查看jvm参数定义自定义参数我们打开cmd窗口,输入java,就能看到自定义参数的格式...

Maven项目如何发布jar包到Nexus私服

Maven项目发布jar包到Nexus私服在编码过程中,有些通用的代码模块,有时候我们不想通过复制粘贴来粗暴地复用。因为这样不仅体现不了变化,也不利于统一管理。这里我们使用mavendeploy的方...

干货丨Hadoop安装步骤!详解各目录内容及作用

Hadoop是Apache基金会面向全球开源的产品之一,任何用户都可以从ApacheHadoop官网下载使用。今天,播妞将以编写时较为稳定的Hadoop2.7.4版本为例,详细讲解Hadoop的安...