还在为WinForm项目中界面逻辑与业务逻辑耦合严重而头疼?传统的WinForm开发中,UI操作、数据验证、业务处理往往都堆积在Form的事件处理器中,导致代码难以维护和测试。今天我将分享一个革命性的解决方案——使用Fody在WinForm中实现MVVM模式,让你的代码结构更清晰,可维护性显著提升!
本文将通过完整的实战案例,带你从零开始搭建一个基于Fody的WinForm MVVM架构,包含数据绑定、属性变更通知、输入验证等核心功能。
在传统WinForm开发中,我们经常看到这样的代码:
C#private void btnSave_Click(object sender, EventArgs e)
{
// 界面验证
if (string.IsNullOrEmpty(txtName.Text))
{
MessageBox.Show("姓名不能为空");
return;
}
// 业务逻辑
var person = new Person
{
Name = txtName.Text,
Age = (int)numAge.Value
};
// 数据保存
SaveToDatabase(person);
// UI更新
UpdateSummaryLabel();
}
问题显而易见:界面逻辑、业务验证、数据操作全部混合在一起,难以进行单元测试,代码复用性极差。
XMLFody PropertyChanged.Fody
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PropertyChanged;
namespace AppFodyBasic
{
[AddINotifyPropertyChangedInterface]
public class PersonViewModel
{
// 基础属性
public string Name { get; set; } = string.Empty;
public int Age { get; set; } = 18;
public string Email { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
// 计算属性 - 依赖于其他属性
[DependsOn(nameof(Name), nameof(Age), nameof(Email))]
public string Summary => $"姓名: {Name}, 年龄: {Age}, 邮箱: {Email}";
// 验证属性
[DependsOn(nameof(Name), nameof(Email))]
public bool IsValid => !string.IsNullOrEmpty(Name) &&
!string.IsNullOrEmpty(Email) &&
IsValidEmail(Email);
// 条件属性
[DependsOn(nameof(Email))]
public bool HasEmail => !string.IsNullOrEmpty(Email);
// 业务逻辑方法
public bool SavePerson()
{
if (!IsValid)
{
MessageBox.Show("请填写完整且正确的信息!", "验证失败",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return false;
}
try
{
// 模拟保存到数据库
var person = new Person
{
Name = this.Name,
Age = this.Age,
Email = this.Email,
Phone = this.Phone,
Address = this.Address
};
// 实际业务
return true;
}
catch (Exception ex)
{
MessageBox.Show($"保存失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
public void ResetPerson()
{
Name = string.Empty;
Age = 18;
Email = string.Empty;
Phone = string.Empty;
Address = string.Empty;
}
private bool IsValidEmail(string email)
{
try
{
var addr = new System.Net.Mail.MailAddress(email);
return addr.Address == email;
}
catch
{
return false;
}
}
}
}
C#namespace AppFodyBasic
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PropertyChanged;
namespace AppFodyBasic
{
[AddINotifyPropertyChangedInterface]
public class PersonViewModel
{
// 基础属性
public string Name { get; set; } = string.Empty;
public int Age { get; set; } = 18;
public string Email { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
// 计算属性 - 依赖于其他属性
[DependsOn(nameof(Name), nameof(Age), nameof(Email))]
public string Summary => $"姓名: {Name}, 年龄: {Age}, 邮箱: {Email}";
// 验证属性
[DependsOn(nameof(Name), nameof(Email))]
public bool IsValid => !string.IsNullOrEmpty(Name) &&
!string.IsNullOrEmpty(Email) &&
IsValidEmail(Email);
// 条件属性
[DependsOn(nameof(Email))]
public bool HasEmail => !string.IsNullOrEmpty(Email);
// 业务逻辑方法
public bool SavePerson()
{
if (!IsValid)
{
MessageBox.Show("请填写完整且正确的信息!", "验证失败",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return false;
}
try
{
// 模拟保存到数据库
var person = new Person
{
Name = this.Name,
Age = this.Age,
Email = this.Email,
Phone = this.Phone,
Address = this.Address
};
// 实际业务
return true;
}
catch (Exception ex)
{
MessageBox.Show($"保存失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
public void ResetPerson()
{
Name = string.Empty;
Age = 18;
Email = string.Empty;
Phone = string.Empty;
Address = string.Empty;
}
private bool IsValidEmail(string email)
{
try
{
var addr = new System.Net.Mail.MailAddress(email);
return addr.Address == email;
}
catch
{
return false;
}
}
}
}
使用[DependsOn]
特性可以精确控制属性依赖关系:
C#[DependsOn(nameof(FirstName), nameof(LastName))]
public string FullName => $"{FirstName} {LastName}";
[DependsOn(nameof(Age))]
public string AgeGroup => Age < 18 ? "未成年" : Age < 60 ? "成年人" : "老年人";
C#// ❌ 错误示例 - 可能导致循环依赖
[DependsOn(nameof(PropertyB))]
public string PropertyA => PropertyB + "A";
[DependsOn(nameof(PropertyA))]
public string PropertyB => PropertyA + "B";
// ✅ 正确示例 - 清晰的依赖关系
[DependsOn(nameof(BaseValue))]
public string DisplayValue => FormatValue(BaseValue);
C#// 订单录入ViewModel示例
[AddINotifyPropertyChangedInterface]
public class OrderViewModel
{
public string ProductName { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
[DependsOn(nameof(Price), nameof(Quantity))]
public decimal TotalAmount => Price * Quantity;
[DependsOn(nameof(TotalAmount))]
public string FormattedTotal => TotalAmount.ToString("C");
}
C#[AddINotifyPropertyChangedInterface]
public class SearchViewModel
{
public string Keyword { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
[DependsOn(nameof(Keyword))]
public bool CanSearch => !string.IsNullOrEmpty(Keyword);
public ObservableCollection<SearchResult> Results { get; set; }
}
C#public void LoadPersonData(Person person)
{
// 使用SuppressPropertyChangedWarnings减少通知频率
using (PropertyChangedEventManager.SuppressNotifications())
{
Name = person.Name;
Age = person.Age;
Email = person.Email;
// ... 其他属性
}
// 退出using块时会触发一次性通知
}
通过本文的实战演示,我们看到了Fody在WinForm MVVM开发中的强大威力:
这种模式特别适合企业级应用开发,能够显著提高代码质量和团队协作效率。在实际项目中,结合依赖注入、数据访问层等技术,可以构建出非常健壮的WinForm应用程序。
🤔 技术讨论:
💬 经验分享:如果你已经在项目中应用了类似的MVVM模式,欢迎在评论区分享你的实践心得和踩过的坑!
觉得这篇文章对你有帮助吗?请转发给更多需要提升WinForm开发技能的同行,让我们一起构建更优雅的C#应用程序!
#C#开发 #WinForm #MVVM #编程技巧 #Fody
相关信息
通过网盘分享的文件:AppFodyBasic.zip 链接: https://pan.baidu.com/s/1Cnffmk0A5qC_LuxCF-QZHQ?pwd=dxeh 提取码: dxeh --来自百度网盘超级会员v9的分享
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!