前面的话
在上一篇自己动手写工具----XSmartNote中,我简单介绍了这个小玩意儿的大致界面和要实现的功能,看了一下园子里的评论,评价褒贬不一,有人说“现在那么多云笔记的工具”,“极简版evernote”,我想说的是,别人的工具再好用,终究不是自己写的,其实写这个的目的,一方面是锻炼自己的技术能力,在coding的时候,或多或少会遇到一些问题,在解决这些问题的过程中,技术能力就会有所提升;另一方面,写这个东西还有自己个人原因,可以随时记录一些繁杂的知识点,通过给这些知识点打上标签,可以实现归类,那有的人会说,EverNote呢?嗯,如果你用着自己写的软件和用EverNote,哪个会更有成就感呢?好了,不多说,上图上代码!!
这个小东西基本上实现了上一篇中列出的功能,添加note、note分类、为note加标签、根据标签对note进行筛选等。下面介绍各个功能点
功能
添加note
首先在界面的右上角会提示您目前选择的树结构节点,如果新添加note就必须选择该note的所属目录(左侧的树节点),否则会因为找不到所属目录而导致添加note失败,如下图:
这样,新增的note就会自动归类为DOT NET文件夹下咯~
1 private void btn_Save_Click(object sender, EventArgs e) 2 { 3 TreeNode node = tv_Folder.SelectedNode; 4 TipsForm tf = new TipsForm(); 5 if (node == null) 6 { 7 return; 8 } 9 if (node.Tag.ToString() == Enums.LEAVES.ToString()) 10 { 11 //同时更新标题和内容 12 int i = SQLHelper.UpdateContent(node.Name.ToInt(), txt_Title.Text, txt_Content.Text); 13 //同时重新加载Treeview 14 BuildTree(this.tv_Folder, GetFolderSet()); 15 if (i > 0) 16 { 17 tf.Show("保存成功!"); 18 } 19 } 20 }
由于建立新note时,note的ID就确定了,所以只要根据ID来更新几个字段就可以了。所以上面是更新操作而不是插入操作。
1 //更新标题及内容 2 public static int UpdateContent(int id,string title,string content) 3 { 4 int result = -1; 5 StringBuilder cmd = new StringBuilder(); 6 cmd.Append(string.Format("update Table_Content set Content = '{0}',Title='{1}' where Id={2}",content,title,id)); 7 return NonQuery(cmd, result); 8 }
为note分类
这个比较简单了,只要在添加的时候指定好note的所属目录就可以了,单击目录时,右侧下方的预览区会显示出该目录下的所有note,并且最上方的标签区域显示该目录下所有的note包含的标签~
为note指定标签
为note指定标签的过程实际上是向关联note和标签的表中加入数据的过程,这里note和标签是多对多的关系,所以需要单独建立一个关系表。
为note加标签,是通过自定义控件LabelWithCheck的选中事件触发的,而且LabelWithCheck是在初始化时动态生成并且动态绑定事件的。
1 public void AddLabelToLocation(FlowLayoutPanel flp, int column, string tag, int Id, bool ischecked,bool registerEvent) 2 { 3 //int flag = 0; 4 int labelCount = flp.Controls.Count; 5 int lines = labelCount / column; 6 int left = labelCount % column; 7 int X = (left * WIDTH) + (left + 1) * MARGIN; 8 int Y = lines * HEIGHT + (lines + 1) * MARGIN; 9 LabelWithCheck label = new LabelWithCheck(); 10 //注册事件 11 if (registerEvent) 12 { 13 label.LabelCheckedEvent += Label_LabelCheckedEvent; 14 //new TipsForm().Show("注册插入数据库事件"); 15 } 16 else 17 { 18 label.LabelCheckedEvent += Label_LabelSelectEvent; 19 //new TipsForm().Show("注册过滤事件"); 20 } 21 22 label.BackColor = ColorTranslator.FromHtml(ColorManager.ColorConvertor(flagForPanelEdit)); 23 label.Location = new Point(X, Y); 24 label.LabelText = tag;//存储标签名称 25 label.Id = Id;//存储标签ID 26 label.LabelChecked = ischecked;//选中状态 27 flp.Controls.Add(label); 28 flagForPanelEdit++; 29 if (flagForPanelEdit > 19) 30 { 31 flagForPanelEdit = 0; 32 } 33 }
下面是自定义控件LabelWithCheck的代码,重绘LabelWithCheck
1 #region OVERRIDE 2 protected override void OnPaint(PaintEventArgs e) 3 { 4 Graphics g = e.Graphics; 5 int x = this.Width; 6 int y = this.Height; 7 Point leftTop = new Point(0, 0); 8 Point rightTop = new Point(x - 1, 0); 9 Point leftBottom = new Point(0, y - 1); 10 Point rightBottom = new Point(x - 1, y - 1); 11 12 g.DrawLine(new Pen(Color.White), leftTop, rightTop); 13 g.DrawLine(new Pen(Color.White), leftBottom, rightBottom); 14 g.DrawLine(new Pen(Color.White), leftTop, leftBottom); 15 g.DrawLine(new Pen(Color.White), rightTop, rightBottom); 16 //画上边缘 17 for (int i = 0; i < x - 1; i += 3) 18 { 19 g.FillRectangle(new SolidBrush(Color.Black), new Rectangle(i, 0, 2, 1)); 20 } 21 22 //画下边缘 23 for (int m = 0; m < x - 1; m += 3) 24 { 25 g.FillRectangle(new SolidBrush(Color.Black), new Rectangle(m, y - 1, 2, 1)); 26 } 27 28 //画左边缘 29 for (int i = 0; i < y - 1; i += 3) 30 { 31 g.FillRectangle(new SolidBrush(Color.Black), new Rectangle(0, i, 1, 2)); 32 } 33 34 //画右边缘 35 for (int i = 0; i < y - 1; i += 3) 36 { 37 g.FillRectangle(new SolidBrush(Color.Black), new Rectangle(x - 1, i, 1, 2)); 38 } 39 base.OnPaint(e); 40 } 41 #endregion
定义LabelWithCheck控件的事件,为note添加标签的时候就触发这个事件,参数中包括了标签的一些信息
1 #region EVENT 2 public delegate void LabelWithCheckSelectedHandler(object sender, LabelWithCheckEventArgs e); 3 public event LabelWithCheckSelectedHandler LabelCheckedEvent; 4 private void ck_CheckedChanged(object sender, EventArgs e)//checkBox原型 5 { 6 if (LabelCheckedEvent != null) 7 { 8 LabelCheckedEvent(sender, new LabelWithCheckEventArgs(this._Id,this.LabelText)); 9 } 10 } 11 #endregion
每选择一个LabelWithCheck都会动态添加该控件
1 private void Label_LabelSelectEvent(object sender, LabelWithCheckEventArgs e) 2 { 3 AddLabelToLocation(flowLayoutPanel2,6,e.LabelText,e.Id,false,false); //Stack Overflow 重复绑定重复执行 形成无限循环导致 4 }
根据目录和标签筛选
这一部分还没有仔细地去做,目前只是大概地处理了一下,最近实在太忙了。大概的筛选原则就是右侧上方的两个标签区域的交集,只要符合条件就会在下面的预览区域显示出来,也就是我们想要看到的结果啦~
上面一排是所选的目录下所有note包含的所有的标签,下面是手工指定的标签,通过筛选条件的就会出现在下面的note预览区域中
结语
本来这个小东西早就该完成,但是中间公司又分配了些项目,没有太多的空闲时间,今天抽空把他总结出来,对自己也有个交代。在写这个玩意儿的时候,的确遇到了一些小问题,如左侧树状结构绑定同一张表中带有层级结构的数据,这是第一次接触,但是掌握了方法就OK了;还有自定义控件的动态添加和绑定事件等等。如果您有什么建议,欢迎评论,大神勿拍... ...如果觉得好玩儿,就给个赞吧~~
2014马上过去了,不得不说时间飞快,祝各位园友在新的一年里,能够实现升职加薪,出任CTO,迎娶白富美,走向人生巅峰
作者:悠扬的牧笛
博客地址:http://www.cnblogs.com/xhb-bky-blog/p/4167108.html
声明:本博客原创文字只代表本人工作中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未授权贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文连接。