简单MVVM教程(改进版) - 第二章
第一章见这里。上一次,我只是开了个头而已,然而在这一章中,我们将看到一点实际的代码了。我构想了很久,怎样让新手能快速掌握我想要传达的知识,然后我得出一个结论:一定一定要简单化,并且要有看的见摸的着的代码实例。好吧,我们开始。
打开你的VS2010,新建一个WPF项目,命名为MvvmTutorial即可。紧接着,在当前Solution添加4个文件夹,分别为:Infrastructure, Views, ViewModels, Models。然后,把App.xaml改成如下:
<Application x:Class="MvvmTutorial.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Application>
把MainWindow.xaml,MainWindow.xaml.cs删掉。在Views下添加一个新的WPF Window,命名为ShellView。在App.xaml.cs中加入:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var shell = new ShellView();
shell.Show();
}
都完成了吗?现在按F5,你应该可以看到你的程序正常运行,并且已经可以看到主窗体了。至此,我们只是做了一些准备工作。Shell其实就是壳的意思,每一个Windows程序都会有一个主窗体,也就是一个壳,我们在这个壳上面拼凑各种View来构成一个丰富的应用程序。
现在我们来看一下具体我们要做些什么。我说过,尽量简单化,所以我们这章的任务很简单:就是把一些联系人显示在主窗体里。我们的联系人很简单,只有两个属性:名字和电话号码。我个人喜欢从ViewModel这一层出发,但是许多朋友还是习惯从Model层写起,那么我们就先来研究一下Model,即实体。在第一章中有人问是否应该在Model里实现INotifyPropertyChanged接口,我个人认为这个没有特别的死的做法。有点人愿意把Model尽量简单化,也就是说只是一个数据的载体而已,而把所有与View打交道的事情全部推给ViewModel。然而对于我们这个简单的例子,我选择让Model也实现INotifyPropertyChanged接口,如此一来,当我们对Model做出修改后,View上就可以显示出变化了(不过在今天这一章里,我们暂时不讨论ViewModel/Model的修改)。现在,在Models下添加一个Contact类。
我们的Model,很简单,具体是这个样子的:
using MvvmTutorial.Infrastructure;
namespace MvvmTutorial.Models
{
/// <summary>
/// Our Contact model, which stores data retrieved from data persistence layer
/// </summary>
public class Contact : ObservableObject
{
#region Fields
string _name;
string _phoneNumber;
#endregion // Fields
#region Properties
public string Name
{
get
{
return _name;
}
set
{
if (_name != value)
{
_name = value;
RaisePropertyChanged(() => Name);
}
}
}
public string PhoneNumber
{
get
{
return _phoneNumber;
}
set
{
if (_phoneNumber != value)
{
_phoneNumber = value;
RaisePropertyChanged(() => PhoneNumber);
}
}
}
#endregion // Properties
}
}
你们可能注意到了这个Contact实际上继承了ObservableObject。这是一个抽象的基类,由于我们将来会有很多类都要实现INotifyPropertyChanged接口,所以我在这里写了一个基类。在Infrastructure下添加一个ObservableObject:
using System;
using System.ComponentModel;
using System.Linq.Expressions;
namespace MvvmTutorial.Infrastructure
{
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
var propertyName = PropertySupport.ExtractPropertyName(propertyExpression);
this.RaisePropertyChanged(propertyName);
}
}
}
好的,这里我要说一下,其实这个类不是我个人写的,而是“剽窃”了一些现有的开源代码,拼凑起来的。请注意PropertySupport,这是一个静态类,它其实来自于微软的Prism框架里一小段代码,我之所以这样做只是让大家看的更清楚这些MVVM的框架内部大体是怎么回事,其实都是大同小异的。请在Infrastructure下添加PropertySupport:
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace MvvmTutorial.Infrastructure
{
public static class PropertySupport
{
public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
{
throw new ArgumentNullException("propertyExpression");
}
var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression == null)
{
throw new ArgumentException("The expression is not a member access expression.", "propertyExpression");
}
var property = memberExpression.Member as PropertyInfo;
if (property == null)
{
throw new ArgumentException("The member access expression does not access a property.", "propertyExpression");
}
var getMethod = property.GetGetMethod(true);
if (getMethod.IsStatic)
{
throw new ArgumentException("The referenced property is a static property.", "propertyExpression");
}
return memberExpression.Member.Name;
}
}
}
有的人可能会问“PropertySupport”到底是干嘛的?其实我们经常写这样的代码:RaisePropertyChanged("SomeProperty"),这个代码本身没有任何问题,但是我们传入的是一个string,这也就暗示了两个小问题:1.当你的Property改名字以后,你需要修改这个string;2.输入string是个稍微容易出错的过程(打字错误)。那么PropertySupport.ExtractPropertyName便在牺牲了一点点效率的前提下,通过指定一个Expression来获得其属性的名字。所以我们就可以写成:RaisePropertyChanged(() => PhoneNumber);如此一来,你只需要指定哪个属性即可,至于它的名字,不需要你操心,而且当下次你修改PhoneNumber为PrivatePhoneNumber后,你也不需要修改任何string。
Okay,既然我们说了要显示出一系列联系人,我们便需要一个View和ViewModel。在ViewModels下添加ContactMasterViewModel:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using MvvmTutorial.Infrastructure;
using MvvmTutorial.Models;
namespace MvvmTutorial.ViewModels
{
public class ContactMasterViewModel : ObservableObject
{
#region Fields
private bool _isLoaded;
private ObservableCollection<Contact> _items = new ObservableCollection<Contact>();
#endregion // Fields
#region Properties
public IEnumerable<Contact> Items
{
get
{
// If we load this view model in design mode (for example, in VS or Expression),
// we add some random data so that we can preview the layout of our view
if (DesignHelper.IsInDesignMode)
{
for (int i = 0; i < 25; ++i)
{
_items.Add(new Contact().GenerateRandomData());
}
}
else if (!_isLoaded)
{
Load();
}
return _items;
}
}
#endregion // Properties
#region Private Methods
private void Load()
{
// TODO: Once we finish the implementation of data persistence layer,
// we need to re-write this code to make this method work for real-world app.
// We haven't implemented data persistence
// Therefore, we temporarily load some random data in memory
for (int i = 0; i < 25; ++i)
{
_items.Add(new Contact().GenerateRandomData());
}
_isLoaded = true;
}
#endregion // Private Methods
}
}
注意这里面的DesignHelper:在Infrastructure下添加DesignHelper类:
这一贴的字基本用光了,下一贴继续。
--------------------编程问答-------------------- DesignHelper内容如下:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Windows;
namespace MvvmTutorial.Infrastructure
{
public static class DesignHelper
{
#region Fields
private static bool? _isInDesignMode;
private static readonly Random Rand = new Random(Guid.NewGuid().GetHashCode());
#endregion // Fields
#region Properties
/// <summary>
/// Gets a value indicating whether the control is in design mode
/// (running in Blend or Visual Studio).
/// </summary>
[SuppressMessage(
"Microsoft.Security",
"CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands",
Justification = "The security risk here is neglectible.")]
public static bool IsInDesignMode
{
get
{
if (!_isInDesignMode.HasValue)
{
#if SILVERLIGHT
_isInDesignMode = DesignerProperties.IsInDesignTool;
#else
#if WIN8
_isInDesignMode = Windows.ApplicationModel.DesignMode.DesignModeEnabled;
#else
var prop = DesignerProperties.IsInDesignModeProperty;
_isInDesignMode
= (bool)DependencyPropertyDescriptor
.FromProperty(prop, typeof(FrameworkElement))
.Metadata.DefaultValue;
// Just to be sure
if (!_isInDesignMode.Value
&& Process.GetCurrentProcess().ProcessName.StartsWith("devenv", StringComparison.Ordinal))
{
_isInDesignMode = true;
}
#endif
#endif
}
return _isInDesignMode.Value;
}
}
#endregion // Properties
#region Public Methods
/// <summary>
/// Gets a random string, given its minimum length and maximum length
/// </summary>
public static string GetRandomString(int minLen = 15, int maxLen = 50)
{
StringBuilder builder = new StringBuilder();
int length = Rand.Next(minLen, maxLen);
char ch;
for (int i = 0; i < length; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * Rand.NextDouble() + 65)));
builder.Append(ch);
}
return builder.ToString().ToLower();
}
public static string GetRandomNumericString(int minLen = 15, int maxLen = 25)
{
StringBuilder builder = new StringBuilder();
int length = Rand.Next(minLen, maxLen);
for (int i = 0; i < length; i++)
{
builder.Append(Rand.Next(0, 10).ToString());
}
return builder.ToString().ToLower();
}
#endregion // Public Methods
}
}
注意IsInDesignMode属性:这是我剽窃MvvmLight的代码。它的作用在于调用它,你可以知道当前你是处于开发视图下还是runtime环境下,什么意思呢,等会儿再解释。还有一个new Contact().GenerateRandomData(),这个GenerateRandomData其实来自于一个Helper类:在Models下添加ModelHelper:
using MvvmTutorial.Infrastructure;
namespace MvvmTutorial.Models
{
public static class ModelHelper
{
public static Contact GenerateRandomData(this Contact target)
{
target.Name = DesignHelper.GetRandomString(5, 15);
target.PhoneNumber = DesignHelper.GetRandomNumericString(8, 12);
return target;
}
}
}
这个应该很容易理解,就是给一个Contact的属性添加一些随机的数据而已,这样便于我们设计和测试。有了ContactMasterViewModel,我们必然需要ContactMasterView,于是在Views下添加ContactMasterView,其XAML代码如下:
<UserControl x:Class="MvvmTutorial.Views.ContactMasterView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:MvvmTutorial.ViewModels"
mc:Ignorable="d" d:DataContext="{Binding Source={StaticResource DesignContext}}"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<vm:ContactMasterViewModel x:Key="DesignContext"/>
</UserControl.Resources>
<Grid>
<ListView ItemsSource="{Binding Items, Mode=OneWay}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name, Mode=OneWay}" VerticalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Phone" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding PhoneNumber, Mode=OneWay}" VerticalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
请注意d:DataContext="{Binding Source={StaticResource DesignContext}}"这里,我们给View绑上来一个DataContext,然而这只是开发视图环境下的DataContext而已。很多时候,当你做完View以后,你希望直接可以在开发视图中看到结果,这样一来你便不需要不断编译,运行,你可以很快获得修改View以后的视觉反馈(我承认我这里的中文讲话水平真的不高)。然而,还记得之前的DesignHelper.IsInDesignMode吗?它可以决定你当前是在运行程序,还是在开发视图下,如果在开发视图下,我们就给ContactMasterViewModel.Items中添加一些随机数据,如果不是开发视图,我们才真正的要从数据层返回一些真实数据(不在本章介绍数据层)。
现在还缺什么呢?ShellViewModel:在ViewModels下添加ShellViewModel:
using MvvmTutorial.Infrastructure;
namespace MvvmTutorial.ViewModels
{
public class ShellViewModel : ObservableObject
{
#region Fields
ContactMasterViewModel _contactMaster;
#endregion // Fields
#region Properties
public ContactMasterViewModel ContactMaster
{
get
{
if (_contactMaster == null)
{
_contactMaster = new ContactMasterViewModel();
}
return _contactMaster;
}
}
#endregion // Properties
}
}
将ShellView.xaml修改如下:
<Window x:Class="MvvmTutorial.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:MvvmTutorial.Views" WindowStartupLocation="CenterScreen"
Title="Contact Book" Height="600" Width="800">
<Grid>
<view:ContactMasterView DataContext="{Binding ContactMaster}"/>
</Grid>
</Window>
这里应该很好理解,我们将ContactMasterView放到ShellView中,并为其指定了DataContext。那么ShellView的DataContext从哪里来呢?再次,为了简化教程,我们用一种比较天真直接的办法:修改该App.xaml.cs如下:
using System.Windows;
using MvvmTutorial.ViewModels;
using MvvmTutorial.Views;
namespace MvvmTutorial
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var shell = new ShellView();
var shellViewModel = new ShellViewModel();
shell.DataContext = shellViewModel;
shell.Show();
}
}
}
现在按F5,运行程序,顺利的话,你应该可以看到一些随机数据显示在界面上。好了大体就先讲到这里。其实大家可以看到,我并没有什么奇思妙想,基本上就是一路“剽窃”各路高手的代码,然后自己拼凑了个小例子而已。编程总是有一些很固定的东西,而且这么多年来,全世界的编程高手,专家,都已经写出来许多拿来即用的东西,我们需要做的是掌握好基础,多读书,多关注新知识,然后“拿来主义”,让这些好用的工具为我们服务。当然,我这个例子目前来看,实在太简单了,不过别急,后面还有新东西要讲的。下回见。谢谢大家支持。 --------------------编程问答-------------------- 订正:ObservableObject应该是public abstract class ObservableObject。 --------------------编程问答-------------------- 好,更加完整了 --------------------编程问答--------------------
我发现CSDN缺一种功能:就是你拖一个Solution上来,CSDN可以让用户直接在线浏览整个Solution,包括其结构,代码,就跟在VS下一样。 --------------------编程问答-------------------- lz可以把这个demo上传,提供下载 ,支持lz --------------------编程问答-------------------- 上传资源的页面 --------------------编程问答--------------------
好的,我还没上传过。感谢提醒,我看一下。 --------------------编程问答-------------------- 第二章的Solution我暂时先不上传,等讲完第三章以后,我整理一下再上传。目前,因为这个程序还几乎没有什么内容,即使上传也没多大意义。 --------------------编程问答-------------------- 不错哦! --------------------编程问答--------------------
感谢分享。。。支持 --------------------编程问答--------------------
你说的是 git 。。。 --------------------编程问答-------------------- --------------------编程问答-------------------- 谢谢楼主了,很好的教程,有转载到这里
MVVM教程
望见谅 --------------------编程问答-------------------- 感谢分享 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答--------------------
It's my hornor. I don't mind. :D --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 看不明白呀!!!郁闷!! --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 看看 研究下 谢谢 --------------------编程问答-------------------- --------------------编程问答-------------------- 感谢分享,学习 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 很好很强大 --------------------编程问答-------------------- 感谢分享,学习 --------------------编程问答-------------------- 请教下,怎么样把这个实例转到B/S下可以浏览呢? --------------------编程问答-------------------- 感谢楼主分享了! --------------------编程问答-------------------- 谢谢感谢楼主分享了 --------------------编程问答-------------------- 谢谢 很好 谢谢楼主分享
--------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 坐等后续 --------------------编程问答-------------------- 不错啊!非常好! --------------------编程问答--------------------
转成B/S?不太确定你的B/S具体指什么。这个例子经过简单修改该,转成Silverlight是可以的 --------------------编程问答--------------------
现在才知道,原来我经常会用到git,只是不知道它叫git。。。。。。 --------------------编程问答--------------------
转成WpfBrowserApplication,谢谢你的回答。 --------------------编程问答-------------------- 我是这周一才接触WPF的。
我想再请教下,WpfBrowserApplication和WpfApplication直接的语法差异或者说是语法格式大吗? --------------------编程问答--------------------
WpfBrowserApp和WpfApp没有什么太大区别,它们的语法没有什么区别。WpfBrowserApp可以运行于浏览器中。你可以看一下这个帖子:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/8bdff32d-6666-457c-8788-41b2c314bba1/ --------------------编程问答-------------------- 谢谢楼主,学习了。 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 整理出一个文档附上Demo就更完美了啊 --------------------编程问答-------------------- wpf还没弄过 --------------------编程问答-------------------- --------------------编程问答--------------------
Thank you for the suggestion. I'll do that later. --------------------编程问答-------------------- --------------------编程问答-------------------- 啊,两天没上网就出新的了,,,
学习。。。。 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 这么快。。。。。 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 支持,
不过我用的是 Winform,
大哥能不能写一个基于 WinForm 的MVVM 出来呢?
WPF 也用过,资料太少,用起来很不顺手,很多功能都无法实现(可能不熟练,也找不到参考)
但对 MVVM 还是很认同的,
就是如果 MVVM 能少用点绑定就好了,绑定不是很灵活,感觉很死。
如果大哥能写个 WinForm 版的 MVVM ,肯定支持你的非常多,
包括用友、金蝶,都是用 WinForm 的吧。 --------------------编程问答-------------------- 不知道 用友、金蝶 有没有 出过 WPF的版本?
不知道,反正周围认识的人都是用 WinForm的。 --------------------编程问答-------------------- 哈哈,找到了,在你的前一贴里找到了 WinForm 的 MVVM 例子, 太感谢你的帖子了。
http://www.cnblogs.com/zenghongliang/archive/2010/07/26/1784944.html
中国还是 WinForm 的天下,用 WPF的毕竟很少,所以入乡随俗,呵呵。
现在还在用VB6、delphi7的,还有很多呢,更不用说 WinForm了,
微软想干掉这些软件,可结果把自己的 Vista给干掉了, 顾客至上,
微软应该多为用户考虑考虑了,
--------------------编程问答-------------------- 中午饭挺好吃的 --------------------编程问答--------------------
首先感谢你的支持。其实你这话说的有点反了:正是因为XAML提供了灵活强大的数据绑定,才使得MVVM这种模式发挥了它的巨大优势;相反,如果数据绑定减少,或者甚至没有了,那不又成了事件驱动了吗?WinForm的开发有它自己的一些模式,你可以到google上查一下,比如Winform MVP --------------------编程问答-------------------- --------------------编程问答--------------------
以前做过ASP.NET,绑定DataGrid,
但绑定很不灵活,对于很复杂的表格,比如多表头,任意合并单元格、多种颜色字体变化的处理,
用绑定就很难实现了。 --------------------编程问答-------------------- XAML 其实也类似于 HTML,
WPF的理念也应该是模仿 HTML的。 --------------------编程问答-------------------- MVP,也不错,要学习一下了,楼主有 没有好的 MVP 例子,介绍一下。 --------------------编程问答--------------------
这个我不太在行,我winform经验相对很少。你可以去Google上搜一下,有很多非常好的介绍MVP的文章,我记得MSDN上也有篇不错的文章。直接搜winform MVP --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 多谢!! --------------------编程问答-------------------- 好强大啊 什么都没有看懂 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答--------------------
谢谢KTEI --------------------编程问答-------------------- --------------------编程问答-------------------- 分享是一种美德,谢谢博主的文章。 --------------------编程问答-------------------- 收藏学习 --------------------编程问答-------------------- 收藏学习 --------------------编程问答--------------------
code:
http://download.csdn.net/detail/wsimei/4174941 --------------------编程问答-------------------- 大哥,我发现数据绑定有个问题,
比如绑定学生列表吧,无法支持动态绑定,
就是数据源DataTable有多少列,就显示多少列,
不知道这个问题怎么解决?
比如查询学生列表,
写SQL语句,查出:学号、姓名、班级、地址。
过几天,用户要求加一列,加一个 “所修课程”列,
如果按你的绑定模式,就得修改类,增加“所修课程”属性,然后再修改界面,显示它。
但如果采用动态绑定的话,有多少列显示多少列,
那我就只需要修改数据源,查出“所修课程”,而界面不用修改,类属性也不用修改。
这种情况很常见,不知道怎么解决? --------------------编程问答-------------------- 就是能否绑定 DataTable 这样的数据源,而不是对象集。 --------------------编程问答--------------------
非常感谢你的源码,方便了很多人啊!
我没想到会有这么多人来学习,如果你们觉得对你们有点帮助的话,就是我往下写的最大动力。再次感谢! --------------------编程问答-------------------- 非常感谢大家的支持和鼓励。
我会尽快更新的。 --------------------编程问答--------------------
你的要求是DataTable返回多少列,就显示出多少列是吧?这其实是显示层的工作。我猜你是想直接绑上DataTable,然后它有多少列,你的界面就自动显示出多少列。GridView据我所知没有AutoGenerateColumns这种功能,但是WPF Toolkit里的DataGrid控件有这个功能。
WPF Toolkit: http://wpf.codeplex.com/releases/view/40535
但是你应该先跟用户谈好他们的需求到底是什么样的,然后再开始开发。如果后来他们的需求有变,你可以通过打补丁的方式升级他们的程序。 --------------------编程问答--------------------
呵呵,设计模式有一条规则:对修改封闭,对扩展开放。
增加一列,不应该属于修改,应该属于扩展吧。 --------------------编程问答-------------------- 不过能实现就行了。多谢你的回复。你给的连接也很有用。
--------------------编程问答-------------------- --------------------编程问答-------------------- ktei,等你跟新好多天了…… --------------------编程问答--------------------
Sorry... I think I can update this weekend. --------------------编程问答-------------------- 呵呵、lz太强了、这么多代码都贴出。 --------------------编程问答-------------------- 那这个周末就等你跟新了!
谁能写个MVVM模式的WpfBrowserApplication的简单Dome,功能越简单越好。这样看的明白。
网上找的都是WpfApplication的Dome啊-,-!新手真难,谢谢了!有些不知道怎么用怎么用语言总结的疑惑。
--------------------编程问答-------------------- 大哥,我问个很有意义的问题,我一直为这个问题烦恼了几年了,
举个例子,学生信息的编辑,
编辑的字段有:学号,姓名,所属班级,地址。
字段说明:
学号:整数,大于0
姓名:字符,长度=10
所属班级:整数,关联班级表
地址:字符,长度=100
对于这样一些属性的字段,
如果我设计一个学生信息编辑界面,要输入这些信息,
那如何自动绑定这些属性呢?
比如学号是用一个文本框来编辑,那文本框只能输入>0的整数,
这些逻辑控制,如何通过控制层去控制?
补充:.NET技术 , C#