动态载入数据的无刷新TreeView控件(4)
前三天我们把TreeView给显示出来了,不过光是显示显然是不够的。TreeView的UI还需要根据用户的各种操作和不同的属性设置产生不同的效果变化,比如:Actived、Selected、Checked等。下面就来设计并实现TreeView的UI动态更新问题。
对于控件开发,不管是Web上的还是WinForm上,使用鼠标和键盘来触发的UI更新和使用程序代码来触发更新是同等地位的。所以我们在设计中最好不要在事件处理函数里面去直接的更新控件UI,为什么呢?因为这样的更新是单向服务的(虽然可以在程序中去调用HTML元素的事件回调,不过语法上太蹩脚了),当我们需要在程序中去更新控件UI,比如设置Selected状态,就需要再写一套代码来从程序的角度去更新UI元素的属性。这时我们会发现前面那种单向服务的代码,其实是完全可以被后者包括(在功能上)的。继续说Selected,当我们用鼠标点击TreeNode时,我们可以从事件响应代码中直接拿到event.srcElement(这就是显示TreeNode的HTML元素),我们如果在此时修改这个元素的属性来显示Selected状态,很容易。可是如果我们还需要在程序中去调用TreeNode.SetSelected(true)来得到Selected效果时,前面所说的单向服务的代码就都被后者(SetSelected)包含了。
哦,那么我们就实现n个方法,比如:SetActived(bool)、SetSelected(bool)、SetChecked(bool),在这些方法中去分别修改控件UI元素属性。由于我们在JS控件中,需要在脚本对象和DHMTL对象中来回引用和查找,并且有些状态的UI的显示还存在优先级的问题(比如Checked和Selected都需要文字颜色变化,但Selected优先级高于Checked)。所以我们也不在每个SetXXX函数中去更新UI元素的属性,而是使用一个统一的函数,来对整个控件的UI更新作出处理。于是我们定义了一个ApplyUIChange()函数,在这里面处理所有和UI呈现有关属性的处理,并具体修改UI元素的属性。
SetXXX方法实现为:
TreeNode.prototype.SetChecked = function(isCheck)
{
var innerCache = this.m_Tree.m_InnerCache;
if ( isCheck )
{
if ( !innerCache.m_Checkeds.Contains(this) )
{
innerCache.m_Checkeds.Add(this);
}
}
else
{
innerCache.m_Checkeds.Remove(this);
}
this.m_Checked = isCheck;
this.ApplyUIChange();
};

TreeNode.prototype.SetSelected = function(isSelected)
{
var innerCache = this.m_Tree.m_InnerCache;
if ( isSelected )
{
if ( !innerCache.m_Selecteds.Contains(this) )
{
innerCache.m_Selecteds.Add(this);
}
}
else
{
innerCache.m_Selecteds.Remove(this);
}
this.m_Selected = isSelected;
this.ApplyUIChange();
};
它们只负责维护控件对象的属性状态,所有的控件的UI相关操作交由this.ApplyUIChange()去处理。这个设计也和WinForm控件中修改属性后的显示调用Invalidate()的设计类似,一切的UI更新都在OnPaint中做。innerCache相关操作在这里不用关心,那是用来记录TreeView实例中被Checked和Selected的Nodes用的,以后再讲。
ApplyUIChange代码实现如下:
TreeNodeBase.prototype.ApplyUIChange = function()
{
if ( this.m_Element.CheckBox )
{
this.m_Element.CheckBox.checked = this.m_Checked;
}
var elmtNode = this.m_Element.Content;
if ( this.m_Selected )
{
elmtNode.style.color = this.Styles('SelectedForeColor');
elmtNode.style.background = this.Styles('SelectedBackColor');
}
else
{
if ( this.m_Checked )
{
elmtNode.style.color = this.Styles('CheckedForeColor');
elmtNode.style.background = this.Styles('CheckedBackColor');
}
else
{
elmtNode.style.color = this.Styles('NormalForeColor');
elmtNode.style.background = this.Styles('NormalBackColor');
}
}
if ( this.m_IsActive )
{
elmtNode.runtimeStyle.textDecoration = 'underline';
}
else
{
elmtNode.runtimeStyle.textDecoration = '';
}
};
在这个方法中,它只用关心属性间的优先级和对UI元素属性的修改,同时这也是程序中唯一修改HTML元素属性的地方。不过本控件中Node的子树的Expand和Collapse的UI元素属性更新没有放在这里,这时因为放在它们独自的方法中也很清晰(不存在和其它UI显示冲突的问题)。也就是说我们虽然有设计原则,不过有时可以使用别的简便方法实现时,也不用太拘泥于原则。设计本身就是妥协,而且我们实际需要的就是简便清晰的实现,而不是要完美的原则。
附各中TreeView的外观样式变化:

to be continued . . .
对于控件开发,不管是Web上的还是WinForm上,使用鼠标和键盘来触发的UI更新和使用程序代码来触发更新是同等地位的。所以我们在设计中最好不要在事件处理函数里面去直接的更新控件UI,为什么呢?因为这样的更新是单向服务的(虽然可以在程序中去调用HTML元素的事件回调,不过语法上太蹩脚了),当我们需要在程序中去更新控件UI,比如设置Selected状态,就需要再写一套代码来从程序的角度去更新UI元素的属性。这时我们会发现前面那种单向服务的代码,其实是完全可以被后者包括(在功能上)的。继续说Selected,当我们用鼠标点击TreeNode时,我们可以从事件响应代码中直接拿到event.srcElement(这就是显示TreeNode的HTML元素),我们如果在此时修改这个元素的属性来显示Selected状态,很容易。可是如果我们还需要在程序中去调用TreeNode.SetSelected(true)来得到Selected效果时,前面所说的单向服务的代码就都被后者(SetSelected)包含了。
哦,那么我们就实现n个方法,比如:SetActived(bool)、SetSelected(bool)、SetChecked(bool),在这些方法中去分别修改控件UI元素属性。由于我们在JS控件中,需要在脚本对象和DHMTL对象中来回引用和查找,并且有些状态的UI的显示还存在优先级的问题(比如Checked和Selected都需要文字颜色变化,但Selected优先级高于Checked)。所以我们也不在每个SetXXX函数中去更新UI元素的属性,而是使用一个统一的函数,来对整个控件的UI更新作出处理。于是我们定义了一个ApplyUIChange()函数,在这里面处理所有和UI呈现有关属性的处理,并具体修改UI元素的属性。
SetXXX方法实现为:



































它们只负责维护控件对象的属性状态,所有的控件的UI相关操作交由this.ApplyUIChange()去处理。这个设计也和WinForm控件中修改属性后的显示调用Invalidate()的设计类似,一切的UI更新都在OnPaint中做。innerCache相关操作在这里不用关心,那是用来记录TreeView实例中被Checked和Selected的Nodes用的,以后再讲。
ApplyUIChange代码实现如下:


































在这个方法中,它只用关心属性间的优先级和对UI元素属性的修改,同时这也是程序中唯一修改HTML元素属性的地方。不过本控件中Node的子树的Expand和Collapse的UI元素属性更新没有放在这里,这时因为放在它们独自的方法中也很清晰(不存在和其它UI显示冲突的问题)。也就是说我们虽然有设计原则,不过有时可以使用别的简便方法实现时,也不用太拘泥于原则。设计本身就是妥协,而且我们实际需要的就是简便清晰的实现,而不是要完美的原则。
附各中TreeView的外观样式变化:

to be continued . . .
分类:
Jscript&Dhtml开发
posted on 2005-03-17 00:19 birdshome 阅读(8633) 评论(5) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器