主要关注
设计模式:观察者模式
架构模型:MVC模型
ps: 本文略过有关观察者模式和MVC模型的概念介绍。
1.资源管理器Explorer的组成
Explorer的组成:Tree(左边树,简称树),ListView(右边列表视图,简称列表),LocationBar(上方的地址栏,简称地址栏),如下所示:
2.三者的联动
资源管理器中,可通过选中树上的目录节点,或双击列表中的目录,或向地址栏填入目录路径并回车等事件,以浏览或选中指定目录;
值得注意的是,树、列表和地址栏的变化或响应是同步的,也就是说,三者中任一的改变可能会引起其他二者的同步变化,例如:当选中树上的某一目录节点A时,列表会同步显示A目录下的目录和文件,地址栏也会同步显示A目录的路径;或者向地址栏填入目录B的路径并回车时,树会改变当前选中节点到B节点,列表会同步显示B目录包含的目录和文件;当双击列表的目录也会引起树和地址栏的同步变化;姑且把这种同步的变化称为联动。
联动的实现
显然,三者的联动是通过事件响应的方式实现,具体实现方式也有多种;
简单的设计:
三者均包含其余两者对象的引用,当事件发生时,主体(事件源)响应当前事件,同时通过引用调用其余二者的相应的响应方法,以实现同步变化(联动);例如:树对象包含列表对象和地址栏对象的引用,当树的选中节点发生变化时,树自身会响应这种变化(如选中的节点的颜色变化,展开节点等),同时通过引用调用列表对象和地址栏对象的相应的方法,以保持联动; 这也是典型的观察者模式,被观察者(主题角色)是树对象,观察者是列表对象和地址栏对象,观察者订阅树对象的发布的事件;同时,三者既充当被观察者,又充当观察者角色;
缺点:组件间耦合,不好扩展,当新增组件、移除组件时,所有组件都受影响,需要重新重新设置对其他组件对象的引用;
更好的设计
为消除组件间的耦合,使得组件间互不可见,是透明的,我们引入一个被称为控制器(Controller)的角色,它等同于MVC模型的控制器(Controller)的角色,而树、列表和地址栏被当成视图(View),这样控制器就能响应视图(三者)的变化,而视图之间是透明的;而关于模型(Model)由什么来充当呢,模型的变化会通过控制器传递给视图,引起视图的变化,并且视图的变化也有可能通过控制器引起模型的改变(或许会有疑问,会不会导致死循环?不控制的话当然会,但可以通过判断视图的状态信息来防止);因此模型应该是能被树、列表和地址栏所改变,且是通过上述的这些事件来改变的,它就是当前目录的路径(或目录地址)path信息!也是资源管理器的关键设计。
M:path
V:tree、listView、LocationBar
C:Controller
更进一步,从观察者设计模式的角度看来,核心事件为当前目录路径(path)的变化,树、列表和地址栏既是观察者,又是被观察者,因此我们有以下设计:
核心事件:path 的变化。
IPathViewer:接口,显示器,视图,具备根据 Path 更新方法(更新当前视图)。
IPathEditer:接口,编辑器,被观察者角色(主题角色),编辑或设置path值,发布 path 变化事件,并触发path变化事件。
Controller:类,控制器,观察者角色,订阅编辑器的 Path 变化事件,并响应该事件;所有的显示器和编辑器都需要向控制器注册,因此控制器拥有显示器集合和编辑器集合;通过编辑器集合,控制器可以向所有的编辑器订阅 Path 变化事件,当path变化事件发生时,控制器遍历显示器集合,并调用每个显示器的path更新方法以更新视图。
另外,可以看出,就控制器和所有的显示器之间的关系而言,控制器也是充当的被观察者角色,所有的显示器充当观察者角色; 而对于编辑器和显示器和而言,也可理解为,编辑器是被观察者,显示器观察者,只是订阅-发布的事件响应过程是通过控制器间接实现的,这正是为了解耦的结果;
对于树、列表和地址栏,他们既是显示器,是针对path的不同视图,具有根据path更新方法,又是编辑器,能触发path变化事件;同时实现这两个接口;
三者联动过程:
编辑器发布和触发path变化事件,控制器订阅和响应该事件,并调用显示器的相应方法更新视图。
3.代码实现(C#):
IPathViewer:显示器接口,定义path属性以及path更新方法;
/// <summary>
/// 定义 Path 视图。
/// </summary>
public interface IPathViewer
{
/// <summary>
/// 定义 Path 属性。
/// </summary>
string Path { get; set; }
}
IPathEditer:编辑器接口,发布 Path 变化事件;
/// <summary>
/// 定义 Path 的编辑器。
/// </summary>
public interface IPathEditer
{
/// <summary>
/// 发布 Path 事件。
/// </summary>
event PathEventHandler PathChanging;
}
Treeview 控件:
/// <summary>
/// 定义 Treeview 控件。
/// </summary>
public class FSTreeview : TreeView,IPathViewer, IPathEditer
{
/// <summary>
/// 定义 Path 属性。
/// </summary>
private string _path;
public string Path
{
get { return _path; }
// 更新视图的方法。
set
{
_path = value;
try
{
_Locate(_path);
}
catch (Exception e)
{
throw e;
}
}
}
/// <summary>
/// 发布 Path 事件。
/// </summary>
public event PathEventHandler PathChanging;
/// <summary>
/// 初始化 FSTreeview 。
/// </summary>
public void Initialize()
{
_LoadRootNode();
BeforeExpand += _BeforeExpandHandler;
AfterSelect += _AfterSelectHandler;
}
/// <summary>
/// 定位到某个节点。
/// </summary>
/// <param name="p_path">指定节点的路径 <see cref="string"/> 。</param>
private void _Locate(string p_path)
{
if (p_path != null)
{
this.SelectedNode = parentNode;
}
}
/// <summary>
/// 处理 BeforeExpand 事件。
/// </summary>
/// <param name="p_sender">表示事件的来源 <see cref="object"/> 。</param>
/// <param name="e">表示事件的数据 <see cref="TreeViewCancelEventArgs"/> 。</param>
private void _BeforeExpandHandler(object p_sender, TreeViewCancelEventArgs e)
{ }
/// <summary>
/// 处理 AfterSelect 事件。
/// </summary>
/// <param name="p_sender">表示事件的来源 <see cref="object"/> 。</param>
/// <param name="e">表示事件的数据 <see cref="TreeViewEventArgs"/> 。</param>
private void _AfterSelectHandler(object p_sender, TreeViewEventArgs e)
{
......
//触发 path 事件。
var pathAgrs = new PathEventAgrs(fullpath);
PathChanging(this, pathAgrs);
}
}
定义 ListView 控件:
/// <summary>
/// 定义 ListView 控件。
/// </summary>
public class FSListView : ListView, IPathViewer, IPathEditer
{
/// <summary>
/// 定义 Path 属性。
/// </summary>
private string _path = null;
public string Path
{
get
{
return _path;
}
// 更新视图的方法。
set
{
_path = value;
if (_path != null)
{
this.Items.Clear();
_LoadItems(value);
}
}
}
/// <summary>
/// 发布 PathEvent 事件。
/// </summary>
public event PathEventHandler PathChanging;
/// <summary>
/// 初始化 FSListView 。
/// </summary>
public void Initialize()
{
this.DoubleClick += OnDoubleClick;
}
/// <summary>
/// 处理 ListView 的双击事件。
/// </summary>
/// <param name="p_sender">指定事件的来源 <see cref="object"/>。</param>
/// <param name="e">指定事件的数据 <see cref="EventArgs"/>。</param>
private void OnDoubleClick(object p_sender, EventArgs e)
{
.....
// 触发 path 事件。
PathEventAgrs pathArgs = new PathEventAgrs(path);
PathChanging(this, pathArgs);
}
/// <summary>
/// 加载 items 并显示。
/// </summary>
/// <param name="p_path">指定 path <see cref="string"/>。</param>
private void _LoadItems(string p_path)
{ }
}
定义 AdressBar 控件。
/// <summary>
/// 定义 AdressBar 控件。
/// </summary>
public class AdressBar : TextBox, IPathViewer, IPathEditer
{
/// <summary>
/// 定义 Path 属性。
/// </summary>
private string _path;
public string Path
{
get
{
return _path;
}
// 更新视图的方法。
set
{
_path = value;
if (value != null)
{
this.Text = value;
}
}
}
/// <summary>
/// 发布 PathEvent 事件。
/// </summary>
public event PathEventHandler PathChanging;
/// <summary>
/// 初始化 AdressBar 。
/// </summary>
public void Initialize()
{
this.Validating += _OnValidatingHandler;
this.KeyPress += _OnKeyPressHandler;
}
/// <summary>
/// 处理 Validating 事件。
/// </summary>
/// <param name="p_sender">表示事件的来源 <see cref="object"/>。</param>
/// <param name="e">表示事件的数据 <see cref="EventArgs"/>。</param>
private void _OnValidatingHandler(object p_sender, EventArgs e)
{
// 触发 path 事件。
PathEventAgrs adressBarAgrs = new PathEventAgrs(this.Text);
PathChanging(this, adressBarAgrs);
}
/// <summary>
/// 处理 KeyPress 事件。
/// </summary>
/// <param name="p_sender">表示事件的来源 <see cref="object"/>。</param>
/// <param name="e">表示事件的数据 <see cref="KeyPressEventArgs"/>。</param>
private void _OnKeyPressHandler(object p_sender, KeyPressEventArgs e)
{
if (e.KeyChar == 13)
{
_OnValidatingHandler(this, e);
}
}
}
控制器的实现:PathEventController
/// <summary>
/// 表示 Path 事件的控制器。
/// </summary>
public class PathEventController
{
// 显示器和编辑器的集合。
private readonly List<IPathViewer> _pathViewerList = null;
private readonly List<IPathEditer> _pathEditerList = null;
/// <summary>
/// 定义 Path 属性。
/// </summary>
private string _path = null;
public string Path
{
get
{
return _path;
}
// 当path 改变时,更新所有视图。
set
{
if ((value != null) && (!value.Equals(_path)))
{
_path = _ValidatePath(value);
foreach (IPathViewer pathViewer in _pathViewerList)
{
pathViewer.Path = _path;
}
}
}
}
/// <summary>
/// 初始化 PathEventController 实例。
/// </summary>
public PathEventController()
{
_pathViewerList = new List<IPathViewer>();
_pathEditerList = new List<IPathEditer>();
}
public void Initialize()
{
Path = "/";
}
/// <summary>
/// 添加 Control 。
/// </summary>
/// <param name="p_control">指定 Control 实例 <see cref="Control"/>。</param>
public void AddControls(Control p_control)
{
if (typeof(IPathViewer).IsInstanceOfType(p_control))
{
IPathViewer pathViewer = (IPathViewer)p_control;
// 添加 IPathViewer 实例到容器。
_pathViewerList.Add(pathViewer);
}
if (typeof(IPathEditer).IsInstanceOfType(p_control))
{
IPathEditer pathEditer = (IPathEditer)p_control;
// 订阅 IPathEditer 的 Path 事件。
pathEditer.PathChanging += _OnPathChanging;
// 添加 IPathEditer 实例到容器。
_pathEditerList.Add(pathEditer);
}
}
/// <summary>
/// 处理 IPathViewer 的 PathChanging 事件。
/// </summary>
/// <param name="p_sender">指定事件的来源 <see cref="object"/>。</param>
/// <param name="e">指定事件包含的数据 <see cref="PathEventAgrs"/>。</param>
private void _OnPathChanging(object p_sender, PathEventAgrs e)
{
// 调用 Path 属性的 set 方法更新视图。
Path = e.Path;
}
/// <summary>
/// 验证 Path 的有效性和正确性。
/// </summary>
/// <returns>表示 Path 有效性 <see cref="bool"/>。</returns>
private string _ValidatePath(string p_path)
{ }
}
定义 Path 事件 和相关事件参数类:
/// <summary>
/// 发布 PathEvent 事件。
/// </summary>
/// <param name="p_sender"></param>
/// <param name="e"></param>
public delegate void PathEventHandler(object p_sender, PathEventAgrs e);
/// <summary>
/// 表示 PathEvent 事件提供数据。
/// </summary>
public class PathEventAgrs : EventArgs
{
/// <summary>
/// 表示文件系统的路径。
/// </summary>
public string Path { get; private set; }
/// <summary>
/// 初始化 PathEventAgrs 的实例。
/// </summary>
/// <param name="p_path">指定文件路径 <see cref="string"/>。</param>
public PathEventAgrs(string p_path)
{
Path = p_path;
}
}
- 大小: 78.1 KB
分享到:
相关推荐
3.实现了主窗体左边驱动器树形视图(显示各驱动器及内部各文件夹列表)、右边文件列表视图(显示当前文件夹下所包含的文件和下一级文件夹)的显示,以及两者的联动显示。左右窗体间设有分隔条,拖动可改变左右窗体大小...
layui实现的资源管理配置系统为企业提供了便捷的资源管理工具,其源码设计遵循MVC模式,易于理解和扩展。通过深入学习和实践,开发者不仅能掌握layui框架的应用,还能提升在资源管理领域的专业技能,为后续的项目...
“C# ListView和TreeView实现资源管理介面例子”这个主题中,我们可能会看到如何结合这两种控件来创建一个类似于操作系统资源管理器的界面。在这样的界面中,TreeView可能用于显示文件夹结构,用户可以浏览和选择...
基于Excel的切片器实现多透视表联动分析 在商业智能和数据分析领域,Excel是一个非常流行的工具,能够帮助用户快速生成报表和数据分析结果。然而,随着数据规模的增加和复杂度的提高,使用Excel进行数据分析变得...
Excel 切片器实现多透视表联动分析 在 Excel 中,切片器(Slicer)是一种强大的工具,能够帮助用户快速、灵活地对数据进行筛选和分析。然而,在实际应用中,用户可能会遇到一个问题,即如何将多个数据透视表(Pivot...
总的来说,"C#实现联动效果"涉及到C#编程、ASP.NET的控件使用、三层架构的设计模式以及与SQL数据库的交互。通过合理地组织代码和充分利用数据绑定机制,我们可以构建出响应迅速、功能丰富的Web应用。而文件"联动效果...
在IT领域,尤其是在数据分析和报表展示中,帆软FineReport是一款广泛应用的报表工具。它提供了丰富的图表类型和灵活的数据交互方式,使得用户可以方便地创建复杂的动态报表。本资源主要涉及的是利用FineReport的...
在Android开发中,有时我们需要实现一个功能,让用户能够选择国家、省份和城市,这被称为“地区三级联动”。同时,日期选择器也是应用中常见的组件,用于让用户方便地选取日期。本教程将详细介绍如何使用WheelView来...
为了实现列表联动,我们需要创建一个自定义的Adapter,这个Adapter不仅管理单个列表的数据,还需要处理不同列表之间的交互。 1. **创建RecyclerView实例**:在XML布局文件中添加RecyclerView元素,并设置相应的...
大型仪器共享管理系统的设计思路主要包括:设备资源的梳理、共享流程的设计、系统平台的功能设计和技术实现等方面。 在设备资源的梳理方面,需要对设备资源和共享流程进行梳理,根据仪器设备资源的类型设置仪器设备...
本示例主要讲解如何使用Android原生组件和一些设计模式来实现这样的功能。 首先,我们要理解"联动菜单"的概念。联动菜单是指在一个菜单的选择项被选中时,会影响并展示与其相关的下一级菜单。在Android中,我们可以...
在Android开发中,...总之,Android ListView的三级联动实现地址选择器涉及到了数据结构设计、事件监听、数据加载和UI布局等多个方面。通过巧妙地组合和定制,我们可以创建出高效、用户体验良好的地址选择组件。
在IT领域,联动是一种常见的交互设计模式,常用于构建用户界面和系统间的协同工作。"死联动"和"活联动"是联动的两种不同状态,它们在数据获取和更新方面存在差异,对于用户体验和系统性能有着重要影响。 首先,我们...
使用Excel VBA 编程,轻松实现省份、城市、区县三级联动
在网页开发中,"AJAX实现省市区三级联动"是一个常见的功能需求,它允许用户在选择省份时,相应的城市和区域会自动更新,无需刷新整个页面。这一功能大大提升了用户体验,尤其是在注册、地址填写等场景中。以下是关于...
在本案例中,我们将讨论如何通过JavaScript来实现这种三级联动效果,同时也会提及到源码分析和相关工具的使用。 首先,我们来看"qqJsAddress"这个文件名,这可能是一个JavaScript库或者脚本,专门用于处理省市区三...
通过阅读和分析这些代码,开发者可以更直观地学习如何在Android中实现二级列表的联动效果。 总的来说,实现Android中的二级列表联动功能需要对ListView或RecyclerView有深入的理解,掌握事件监听、数据交互以及布局...
在本项目中,它可能被用来从网页抓取最新的省市区镇数据,因为描述中提到网上的资源往往不实时更新。JavaJsoup能够解析HTML文档,提取所需的数据,例如省份、城市、区县和城镇的名称和ID,然后将这些数据存储在...