【我们一起写框架】MVVM的WPF框架(三)—数据控件
这世上,没人能一次性写出完美无缺的框架;因为,任何一个框架都需要项目的淬炼,然后才能升华,趋近完美。
所以,框架是个反复修改的东西,最终形成的东西。
如果你学了一点技术,觉得自己可以写出框架了,觉得自己有架构师的能力,然而自己总是怀才不遇——那一定是你的错觉。
因为,你框架没有经过项目淬炼;而淬炼过框架的人都了解,设计的再好的框架,最终会被业务需求打的细碎,然后被开发人员搅和再一起。
所以细节决定成败,没有细节的框架就是扯淡。
datacontrol—数据控件
上文我们已经编写出来了wpf的mvvm基础框架,但为了让他更加强壮,为了让他多坚持一阵子再粉碎,我们要让viewmodel更强壮,所以我们要编写[数据控件]。
数据控件其实很好理解,它就是把ui控件中存储的数据提取出来,好让viewmodel可以通过修改数据来控制ui变化;当然,为了更好的控制ui变化,数据控件里还得包含一点管理ui的属性。
因为wpf里的控件大多继承自control,所以我们先创建control的数据控件。
public class control<t> : inotifypropertychanged
{
public event propertychangedeventhandler propertychanged;
public t _datacontent ;
public t datacontent { get { return _datacontent; } set { _datacontent = value; onpropertychanged(); } }
public visibility _visibility;
public visibility visibility { get { return _visibility; } set { _visibility = value; onpropertychanged(); } }
public bool _isreadonly;
public bool isreadonly { get { return _isreadonly; } set { _isreadonly = value; onpropertychanged(); } }
public bool _isenabled;
public bool isenabled { get { return _isenabled; } set { _isenabled = value; onpropertychanged(); } }
protected void onpropertychanged([callermembername]string propertyname = "")
{
if (propertychanged != null)
{
propertychanged(this, new propertychangedeventargs(propertyname));
}
}
}
如上代码所示,我们创建了control的数据控件。
可以看到,处理存贮数据的datacontent属性之外,还创建了一些管理ui的属性isenabled、isreadonly、visibility。
父类数据控件创建完成后,我们开始创建子类的数据控件。[如果子类要管理的ui属性不在父类内,我们就需要额外创建一些]
textblock和textbox
我们先创建最基础的,最常用的textblock和textbox。
textblock代码如下:
public class textblock<t> : control<t>
{
public t _text;
public t text
{
get { return _text; }
set
{
_text = value;
onpropertychanged();
}
}
}
textbox代码如下:
public class textbox<t> : control<t>
{
public action<t> textchangecallback = null;
public t _text;
public t text {
get { return _text; }
set
{
_text = value;
if (textchangecallback != null)
{
textchangecallback(_text);
}
onpropertychanged();
}
}
}
可以看到textblock和textbox都继承了control,而他们的区别只是textbox多了一个textchangecallback。
有人会想到,那完全可以用textbox替代textblock。
理论上,textblock是可以被替换,但为了程序清晰,还是区别开来更好。
控件定义好了,我们现在看一下如何应用。
textbox应用
xaml页面代码
<textbox text="{binding changetextbox.text,mode=twoway}" margin="5" fontsize="12"></textbox>
----------------------------------
viewmodel页面代码
public textbox<string> changetextbox { get; set; }
public vm_pagetextbox()
{
changetextbox = new textbox<string>();
changetextbox.textchangecallback = (text) => { messagebox(text); };//声明textchange
}
如代码所示,我们在viewmodel中定义了changetextbox属性,然后再xaml中绑定了changetextbox属性的text到ui控件textbox的text属性上,这样我们就实现了数据联动。
并且代码中实例化了textchangecallback委托,那么当text数据变化时,该委托就会触发。
注意:textchangecallback委托与textchanged事件不同,并不是每次修改文字都会触发,而是当textbox的text内容真正被修改时,才会触发;我们可以简单的理解为textbox失去焦点时才会触发。
这里只介绍textbox应用,textblock应用就不介绍了,因为使用方式和textbox一样。
如果想了解更多数据控件的应用,请去github下载源码。
combobox
combobox稍微复杂一点,因为他多了一个itemsource属性。
我们先看combobox的数据控件代码:
public class combobox<t> : control<t>
{
public action<t> selectcallback = null;
public combobox()
{
}
public observablecollection<t> _itemssource;
public observablecollection<t> itemssource
{
get
{
return _itemssource;
}
set
{
_itemssource = value;
if (_itemssource != null && _itemssource.count > 0 && selecteditem == null)
{
selecteditem = _itemssource.first();
}
onpropertychanged();
}
}
public t _selecteditem;
public t selecteditem
{
get { return _selecteditem; }
set
{
_selecteditem = value;
if (selectcallback != null)
{
selectcallback(_selecteditem);
}
onpropertychanged();
}
}
private icollectionview _itemssourceview;
public icollectionview itemssourceview
{
get
{
_itemssourceview = collectionviewsource.getdefaultview(_itemssource);
return _itemssourceview;
}
set
{
_itemssourceview = value;
onpropertychanged();
}
}
public void setitemssource(list<t> itemsource)
{
itemssource = new observablecollection<t>(itemsource);
}
}
代码相对简单,selecteditem和itemssource用来绑定ui控件combobox的同名属性。
itemssourceview:itemssourceview属性可能有些难理解,这里我们简单介绍一下。
因为wpf的ui控件被创建以后,要被添加到视觉树中,所以最终会被显示在屏幕上的是包裹着控件的视觉树;其中视觉树与控件是可以分离的;比如控件中绑定的数据是10行,而视觉树可以显示3行。
为了管理视觉树,我们创建了itemssourceview属性。
因为itemssourceview是icollectionview类型,所以itemssourceview可以处理排序、筛选和分组。[有兴趣的同学可以自行了解下icollectionview类型]
感觉这样描述还是很难理解,让我们一起在应用中慢慢理解吧。
observablecollection:我们可以看到itemssource是类型是observablecollection,而不是list。为什么要用observablecollection呢?
很简单,因为observablecollection继承了inotifycollectionchanged,即,数据控件进行[行]的增删,也会让ui进行[行]的增删。
combobox应用
在应用之前,我们先在proxy建立一个获取数据是代理。
创建获取数据的方法如下:
public list<user> getcomboboxdata()
{
list<user> userlist = new list<user>();
user user1 = new user() { id = 1, name = "张三", age = 11 };
userlist.add(user1);
return userlist;
}
xaml页面代码如下:
<combobox margin="5" width="200" fontsize="12" itemssource="{binding testcombobox.itemssource}" displaymemberpath="name" selectedvaluepath="id" selecteditem="{binding testcombobox.selecteditem}" ></combobox>
viewmodel代码如下:
public combobox<user> testcombobox { get; set; }
testdataproxy proxy = new testdataproxy();
public vm_pagecombobox()
{
testcombobox = new combobox<user>();
testcombobox.setitemssource(proxy.getcomboboxdata());
testcombobox.selectcallback = (user) => {
messagebox(user.name);
};
}
如上所示,我们已经实行了在viewmodel中管理combobox。
----------------------------------------------------------------------------------------------------
本篇文章就先讲到这了,下一篇文章我们将一起为框架编写datagrid数据控件。
因为datagrid数据控件是所有数据控件中最复杂的,而且代码量特别多;所以,我决定,单拿出一篇来介绍datagrid。
框架代码已经传到github上了,并且会持续更新。
相关文章:
to be continued——datagrid
github地址:https://github.com/kiba518/kibaframework
----------------------------------------------------------------------------------------------------
注:此文章为原创,欢迎转载,请在文章页面明显位置给出此文链接!
若您觉得这篇文章还不错,请点击下右下角的【推荐】,非常感谢!
上一篇: 前端框架汇总(含国内各大公司)
下一篇: OC内存管理、非ARC机制、MRR机制