前言 :本方法用于 从数据库中搜索出的数据集合绑定到 表格控件中。一个页面搜一下查一下感觉挺简单的,但是写到5个以上的这种类似的页面就有些烦了,于是就动了点小脑筋,简化搜索的操作。
封装个通用的集合 PageDataOperate.cs
这个地方 作为页面数据的基础类包括页码 Size等信息
/// <summary>
/// 页面数据 翻页 当前页 总页数等信息
/// </summary>
public class PageDataBase : NotifyPropertyClass
{
/// <summary>
/// 当前页页码
/// </summary>
private int _pagenow = 1;
public int PageNow
{
get { return _pagenow; }
set
{
_pagenow = value;
OnPropertyChanged("PageNow");
}
}
/// <summary>
/// 页面显示条数
/// </summary>
private int _pagesize = 10;
public int PageSize
{
get { return _pagesize; }
set
{
_pagesize = value;
OnPropertyChanged("PageSize");
OnPropertyChanged("PageNow");
OnPropertyChanged("TotalPage");
}
}
/// <summary>
/// 条数数
/// </summary>
internal int _totalnum = 0;
public int TotalNum
{
get { return _totalnum; }
set
{
_totalnum = value;
OnPropertyChanged("TotalNum");
OnPropertyChanged("PageSize");
OnPropertyChanged("PageNow");
OnPropertyChanged("TotalPage");
}
}
/// <summary>
/// 总页数
/// </summary>
public int TotalPage
{
get
{
if (TotalNum == 0)
return 1;
return (int)Math.Ceiling((double)TotalNum / PageSize);
}
}
/// <summary>
/// 消息
/// </summary>
private string _message;
public string Message
{
get { return _message; }
set { _message = value; }
}
/// <summary>
/// 数据部分
/// </summary>
private DataTable _database;
public DataTable DataBase
{
get { return _database; }
set
{
_database = value;
OnPropertyChanged("DataBase");
}
}
}
再上一层的话 不出所料 包含了 1设置数据库的搜索方法 2加载数据 3 翻页的操作 (当然也可以开放一个跳转页面的入口,根据自己的情况设计一下)
/// <summary>
/// 页面数据 翻页 当前页 总页数等信息
/// </summary>
public class PageDataOperate : PageDataBase
{
/// <summary>
/// 是否为带条件搜索
/// </summary>
public bool IsSearchWithKey { get; set; }
//执行 相同参数入参出参的 方法 可以统一调用
public delegate FeedBack<DataTable> DBLoadDataAll(int PageNow, int PageSize, out int TotalNum);
/// <summary>
/// 加载所有房屋方法
/// </summary>
public DBLoadDataAll LoadDataAllEvent { get; set; }
/// <summary>
/// 加载数据
/// </summary>
public void LoadData()
{
if (PageSize <= 0 || PageNow <= 0)
{
return;
}
PageNow = 1;
IsSearchWithKey = false;
DBSelect();//执行搜索
}
/// <summary>
/// 刷新数据
/// </summary>
public void RefreshData()
{
DBSelect();//执行搜索
}
/// <summary>
/// 下一页上一页
/// </summary>
/// <param name="Type">+1 则表示下一页 -1表示上一页 </param>
public void NextPage(int Type)
{
var Act = Type;
if (Act == -1 && this.PageNow == 1)
{//已经是第一页
this.PageNow = 1;
this.Message = "已经是第一页";
return;
}
if (Act == 1 && this.PageNow >= this.TotalPage)
{ //已经是最后一页
this.PageNow = this.TotalPage;
this.Message = "已经是最后一页";
return;
}
this.PageNow += Act;
DBSelect();//执行搜索
}
/// <summary>
/// 执行搜索
/// </summary>
public void DBSelect()
{
if (LoadDataAllEvent == null)
{
return;
}
var feedback = LoadDataAllEvent(this.PageNow, this.PageSize, out this._totalnum);
this.Message = feedback.status ? string.Empty : feedback.message;
TotalNum = this._totalnum;
this.DataBase = feedback.result;
ConvertToT();
}
/// <summary>
/// 转换成List<T>
/// </summary>
public void ConvertToT()
{
}
}
搞到这里感觉够用了,但是发现了一些小问题,有些情况下不够用,就是不能使用条件查询,于是乎便有了这个
/// <summary>
/// 页面数据 翻页 当前页 总页数等信息
/// </summary>
public class PageDataOperate<TInput> : PageDataOperate
{
/// <summary>
/// 索索关键字
/// </summary>
public TInput InputKey { get; set; }
//执行 相同参数入参出参的 方法 可以统一调用
public delegate FeedBack<DataTable> DBLoadDataByKey(TInput InputKey, int PageNow, int PageSize, out int TotalNum);
/// <summary>
/// 加载单个房间信息
/// </summary>
public DBLoadDataByKey LoadDataByKeyEvent { get; set; }
/// <summary>
/// 加载数据
/// </summary>
public void LoadData(TInput InputKey)
{
if (PageSize <= 0 || PageNow <= 0)
{
return;
}
IsSearchWithKey = true;
PageNow = 1;
this.InputKey = InputKey;
DBSelectWithKey();//执行搜索
}
/// <summary>
/// 刷新数据
/// </summary>
public new void RefreshData()
{
if (IsSearchWithKey)
{
DBSelectWithKey();
}
else
{
DBSelect();//执行搜索
}
}
/// <summary>
/// 下一页上一页
/// </summary>
/// <param name="Type">+1 则表示下一页 -1表示上一页 </param>
public void NextPageWithKey(int Type)
{
var Act = Type;
if (Act == -1 && this.PageNow == 1)
{//已经是第一页
this.PageNow = 1;
this.Message = "已经是第一页";
return;
}
if (Act == 1 && this.PageNow >= this.TotalPage)
{ //已经是最后一页
this.PageNow = this.TotalPage;
this.Message = "已经是最后一页";
return;
}
this.PageNow += Act;
DBSelectWithKey();//执行搜索
}
/// <summary>
/// 执行搜索
/// </summary>
public void DBSelectWithKey()
{
if (LoadDataByKeyEvent == null)
{
return;
}
var feedback = LoadDataByKeyEvent(this.InputKey, this.PageNow, this.PageSize, out this._totalnum);
this.Message = feedback.status ? string.Empty : feedback.message;
this.TotalNum = this._totalnum;
this.DataBase = feedback.result;
ConvertToT();
}
}
有时候老板或是产品经理觉得,你列表都搜出来了,是不是应该 统计一点数据什么的顺便传出来。。。比如某一列的总和。内部实现我管不到,但是我觉得可以开放一个出口返回你需要的值,如果返回值超过两个以上我觉得也是能够应付的
/// <summary>
/// 页面数据 翻页 当前页 总页数等信息
/// </summary>
public class PageDataOperate<TInput, TOutput> : PageDataOperate
{
/// <summary>
/// 索索关键字
/// </summary>
public TInput InputKey { get; set; }
private TOutput _output;
public TOutput OutPut
{
get { return _output; }
set
{
_output = value;
OnPropertyChanged("OutPut");
}
}
//执行 相同参数入参出参的 方法 可以统一调用
public delegate FeedBack<DataTable> DBLoadDataByKey(TInput InputKey, int PageNow, int PageSize, out int TotalNum, out TOutput OutPut);
/// <summary>
/// 加载单个房间信息
/// </summary>
public DBLoadDataByKey LoadDataByKeyEvent { get; set; }
/// <summary>
/// 加载数据
/// </summary>
public void LoadData(TInput InputKey)
{
if (PageSize <= 0 || PageNow <= 0)
{
return;
}
IsSearchWithKey = true;
PageNow = 1;
this.InputKey = InputKey;
DBSelectWithKey();//执行搜索
}
/// <summary>
/// 刷新数据
/// </summary>
public new void RefreshData()
{
if (IsSearchWithKey)
{
DBSelectWithKey();
}
else
{
DBSelect();//执行搜索
}
}
/// <summary>
/// 下一页上一页
/// </summary>
/// <param name="Type">+1 则表示下一页 -1表示上一页 </param>
public void NextPageWithKey(int Type)
{
var Act = Type;
if (Act == -1 && this.PageNow == 1)
{//已经是第一页
this.PageNow = 1;
this.Message = "已经是第一页";
return;
}
if (Act == 1 && this.PageNow >= this.TotalPage)
{ //已经是最后一页
this.PageNow = this.TotalPage;
this.Message = "已经是最后一页";
return;
}
this.PageNow += Act;
DBSelectWithKey();//执行搜索
}
/// <summary>
/// 执行搜索
/// </summary>
public void DBSelectWithKey()
{
if (LoadDataByKeyEvent == null)
{
return;
}
var feedback = LoadDataByKeyEvent(this.InputKey, this.PageNow, this.PageSize, out this._totalnum, out this._output);
this.Message = feedback.status ? string.Empty : feedback.message;
this.TotalNum = this._totalnum;
this.OutPut = this._output;
this.DataBase = feedback.result;
ConvertToT();
}
}
若果觉得够用到此也就差不多了,,
但是吼。。。
有时候绑定的不是DataTable 咋办换成其他集和 难道手动转换一下吗
所以 为了外面少写一行 在内部增加了 几百行。。。
基本算是把前面复制了一遍
这么搞是发现了 DataGrid 里 selectchanged 事件 不能直接获取里面的类 datagrid.SelectItem 取出来的是 DataRow
下面转化过的话可以 直接var parament=datagrid.SelectItem as yourCLASS; 直接映射出类
后来想想没啥必要, 直接用 DataRow 自己写个方法ConvertTo<yourCLASS>()转一下也是可以的。。。
/// <summary>
/// 页面数据 翻页 当前页 总页数等信息
/// </summary>
public class PageDataOperateConvert<T> : PageDataOperate where T : new()
{
/// <summary>
/// 数据部分
/// </summary>
private List<T> _dataview;
public List<T> DataView
{
get { return _dataview; }
set
{
_dataview = value;
OnPropertyChanged("DataView");
}
}
public new void LoadData()
{
base.LoadData();
this.ConvertToT();
}
public new void RefreshData()
{
base.RefreshData();
this.ConvertToT();
}
public new void NextPage(int Type)
{
base.NextPage(Type);
this.ConvertToT();
}
public new void ConvertToT()
{
this.DataView = this.DataBase.TableToList<T>();
}
}
/// <summary>
/// 页面数据 翻页 当前页 总页数等信息
/// </summary>
public class PageDataOperateConvert<TInput, T> : PageDataOperate<TInput> where T : new()
{
/// <summary>
/// 数据部分
/// </summary>
private List<T> _dataview;
public List<T> DataView
{
get { return _dataview; }
set
{
_dataview = value;
OnPropertyChanged("DataView");
}
}
public new void LoadData()
{
base.LoadData();
this.ConvertToT();
}
public new void LoadData(TInput InputKey)
{
base.LoadData(InputKey);
this.ConvertToT();
}
public new void RefreshData()
{
base.RefreshData();
this.ConvertToT();
}
public new void NextPage(int Type)
{
base.NextPage(Type);
this.ConvertToT();
}
public new void NextPageWithKey(int Type)
{
base.NextPageWithKey(Type);
this.ConvertToT();
}
public new void ConvertToT()
{
this.DataView = this.DataBase.TableToList<T>();
}
}
/// <summary>
/// 页面数据 翻页 当前页 总页数等信息
/// </summary>
public class PageDataOperateConvert<TInput, TOutput, T> : PageDataOperate<TInput, TOutput> where T : new()
{
/// <summary>
/// 数据部分
/// </summary>
private List<T> _dataview;
public List<T> DataView
{
get { return _dataview; }
set
{
_dataview = value;
OnPropertyChanged("DataView");
}
}
public new void LoadData()
{
base.LoadData();
this.ConvertToT();
}
public new void LoadData(TInput InputKey)
{
base.LoadData(InputKey);
this.ConvertToT();
}
public new void RefreshData()
{
base.RefreshData();
this.ConvertToT();
}
public new void NextPage(int Type)
{
base.NextPage(Type);
this.ConvertToT();
}
public new void NextPageWithKey(int Type)
{
base.NextPageWithKey(Type);
this.ConvertToT();
}
public new void ConvertToT()
{
this.DataView = this.DataBase.TableToList<T>();
}
}
到此也就完了
最后附上刚才代码中没有提及的
NotifyPropertyClass 类以及 Datatable.TableToList<T>();方法
没啥可看的 但是有个优化的地方就是 此处用
Dictionary<string, PropertyChangedEventArgs>
保存了需要通知的属性,避免了通知一次new一次的现象 不知道有没有效果 ,就当是优化了吧 但是这里执行多线程的时候如果恰好都过了非空添加项的时候可能出现重复错误
/// <summary>
/// 用于 非继承类的 快速 建立通知的方法
/// </summary>
public class NotifyPropertyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private Dictionary<string, PropertyChangedEventArgs> PropertyList = new Dictionary<string, PropertyChangedEventArgs>();
virtual internal protected void OnPropertyChanged(string propertyName)
{
if (!PropertyList.ContainsKey(propertyName))
{
PropertyList.Add(propertyName, new PropertyChangedEventArgs(propertyName));
}
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, PropertyList[propertyName]);
}
}
protected void SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return;
storage = value;
this.OnPropertyChanged(propertyName);
}
//protected void SetProperty<T>(ref T storage, T value, Expression<Func<T>> expr)
//{
// //SetProperty(ref ishousepage, value, () => this.IsHousePage);
// var bodyExpr = expr.Body as System.Linq.Expressions.MemberExpression;
// if (bodyExpr == null)
// {
// throw new ArgumentException("Expression must be a MemberExpression!", "expr");
// }
// var propInfo = bodyExpr.Member as PropertyInfo;
// if (propInfo == null)
// {
// throw new ArgumentException("Expression must be a PropertyExpression!", "expr");
// }
// var propName = propInfo.Name;
// storage = value;
// this.OnPropertyChanged(propName);
//}
}
随处可见的 DataTable转 List<T>很常见
public static class staticExtendConvert
{
/// <summary>
/// DataTable转换为List
/// </summary>
/// <typeparam name="T">实体对象</typeparam>
/// <param name="dt">datatable表</param>
/// <returns>返回list集合</returns>
public static List<T> TableToList<T>(this DataTable dt) where T : new()
{
if (dt == null)
{
return new List<T>();
}
//定义集合
List<T> list = new List<T>();
//获得此模型的类型
Type type = typeof(T);
//定义一个临时变量
string tempName = string.Empty;
//遍历Datatable中所有的数据行
foreach (DataRow dr in dt.Rows)
{
T t = new T();
//获得此模型的公共属性
PropertyInfo[] propertys = t.GetType().GetProperties();
//遍历该对象的所有属性
foreach (PropertyInfo pi in propertys)
{
//将属性名称赋值给临时变量
tempName = pi.Name;
//检查DataTable是否包含此列(列名==对象的属性名)
if (dt.Columns.Contains(tempName))
{
//判断此属性是否有Setter
if (!pi.CanWrite) continue;//该属性不可写,直接跳出
//取值
object value = dr[tempName];
//如果非空,则赋给对象的属性
if (value != DBNull.Value)
{
//加一重if判断,如果属性值是int32类型的,就进行一次强制转换
if (pi.GetMethod.ReturnParameter.ParameterType.Name == "Int32")
{
value = Convert.ToInt32(value);
}
//加一重if判断,如果属性值是int32类型的,就进行一次强制转换
if (pi.GetMethod.ReturnParameter.ParameterType.Name == "Int64")
{
value = Convert.ToInt64(value);
}
try
{
pi.SetValue(t, value, null);
}
catch (Exception ex)
{
}
}
}
}
//对象添加到泛型集合中
list.Add(t);
}
return list;
}
}
/// <summary>
/// 返回信息的结构体
/// </summary>
public struct FeedBack<T>
{
/// <summary>
/// 状态,返回true/false
/// </summary>
public bool status { get; set; }
/// <summary>
/// 错误代码
/// </summary>
public int code { get; set; }
/// <summary>
/// Json结构的对象
/// </summary>
public T result { get; set; }
/// <summary>
/// 信息
/// </summary>
public string message { get; set; }
}
后面会更新一个 简单版的 这个看起来确实复杂,没必要
对了好像忘了 说怎么用这个东西
1.声明
/// <summary>
/// 数据集中类(包含 当前现实的页面 当前页码 总页数总条数,仅需一次绑定无需换绑即可刷新)
/// </summary>
public Moldels.Local.PageDataOperateConvert<string, decimal, PayBillSummByHouse> PageDataOperate { get; set; } = new PageDataOperateConvert<string, decimal, PayBillSummByHouse>();
2.赋值
//列表数据
PageDataOperate.LoadDataByKeyEvent = yourDB.GetPayBillSummaryByWhereKey;
这里的
yourDB.GetPayBillSummaryByWhereKey
是你搜索数据库的方法 返回 DataTable格式的数据
Feedback<DataTable> (string WhereKey, int PageNow, int PageSize, out int TotalNum, out decimal Totaloverdue){
select table。。。。where 。。。。
搜索完的数据 搞成 DataTable
return Feedback<DataTable>();
}
3.运行
PageDataOperate.LoadData(KeyStr3);
4.界面中绑定
DataTable.ItemSource {binding PageDataOperate.DataView 或 PageDataOperate.DataBase}
刷新是由
NotifyPropertyClass
实现的
随便搞搞 有帮助当然好,没帮助能激发点创造思路也不错。