posted @ 2010-05-16 22:05 feedback 阅读(1011) 评论(5) 编辑

  前一篇,我们定义并实现了配置文件的读写功能,这次我们来实现配置文件的界面展示。之前我们设计的时候,就要求界面能够动态展现,比如在界面定义文件中新增一个CheckBox定义,那么要求界面能够反映出来。

本次界面还原技术,我们采用SharpDev的方式,利用xml文件对界面进行描述,然后利用反射将界面展示出来。(PS:如果你用过Delphi,你同样会发现Delphi的frm文件也是采用这样的思路),这里有个问题需要暂时搁置一下,对于界面中用到的图像资源的处理,目前暂时不用管。

好了,我们先来看一下设计思路

总界面管理类定义

代码
    /// <summary>
    
/// 界面管理类
    
/// </summary>
    public interface IConfigUiManager
    {
        
/// <summary>
        
/// 默认界面文件路径
        
/// </summary>
        string DefaultFloder
        {
            
get;
            
set;
        }
        
/// <summary>
        
/// 界面描述文件的后缀
        
/// </summary>
        string DefaultExt
        {
            
get;
            
set;
        }
        
/// <summary>
        
/// 扫描默认目录下的界面文件并加载
        
/// </summary>
        void Load();
        
/// <summary>
        
/// 定位某个界面
        
/// </summary>
        
/// <param name="pName"></param>
        
/// <returns></returns>
        IConfigSectionUi FindUi(string pName);
        
/// <summary>
        
/// 展示总配置界面
        
/// </summary>
        void ShowUi();
    }

 

 当个配置程序节的界面定义

 

代码
    /// <summary>
    
/// 单个配置程序节的界面
    
/// </summary>
    public interface IConfigSectionUi
    {
        
/// <summary>
        
/// 是否集成到总界面中
        
/// </summary>
        bool LazyLoad
        {
            
get;
            
set;
        }
        
/// <summary>
        
/// 界面名称
        
/// </summary>
        string Name
        {
            
get;
            
set;
        }
        
/// <summary>
        
///从配置文件中加载选项
        
/// </summary>
        void LoadFromConfig();
        
/// <summary>
        
///  将设置保存到配置文件中
        
/// </summary>
        void SaveToConfig();
        
/// <summary>
        
/// 从xml文件中提取的界面
        
/// </summary>
        System.Windows.Forms.Control Ui
        {
            
get;
            
set;
        }
        
/// <summary>
        
/// 展示当前的配置界面
        
/// </summary>
        void ShowUi();
        
void LoadFromFile(string pFileName);
        
string Caption
        {
            
get;
            
set;
        }
        Control FindControl(
string pCtlName);

    }

 

在这里,我们需要声明一下,对于界面定义文件,我们支持两种方式,一种是Form形式定义,这样的方式允许程序在运行期弹出独立界面跟用户交互;其二,是UserControl方式,这样的方式运行两种模式运行,第一集成到配置总界面中集中管理,第二,单独的弹出界面跟用户交互;基于这样的考虑,所以,我在接口IConfigSectionUi中定义了标识LazyLoad。

基本类的定义就是上面两个,但是辅助类还没有定义,这里,我不妨直接借用SharpDev的代码来实现

这里用到了其中核心的一个类XmlLoader(具体实现可以参考其源代码)

  好了,这样一来,界面的还原功能就实现了。但还是没有达到我们之前制定的目标。好吧,我们来实现IConfigSectionUi.LoadFromFile方法

 

代码
        XmlLoader xmlLoader = null;

        
void IConfigSectionUi.LoadFromFile(string pFileName)
        {
            
using (FileStream pStream = new FileStream(pFileName, FileMode.Open))
            {
                AppConfig.Ui.FakeForm FakeForm 
= new AppConfig.Ui.FakeForm();
                
object FakeObj = null;

                
if (pStream == null)
                {
                    
throw new System.ArgumentNullException("stream");
                }
                FakeForm.SuspendLayout();
                xmlLoader 
= new XmlLoader();
                SetupXmlLoader();
                
if (pStream != null)
                {
                    FakeObj 
= xmlLoader.LoadObjectFromStream(FakeForm, pStream);
                }
                
if (FakeForm.Controls.Count > 0)
                {
                    
this._Ui = FakeForm;
                    
this._Name = FakeForm.Name;
                    
this._LazyLoad = true;
                    
this._Caption = FakeForm.Caption;
                    FakeForm.ResumeLayout(
false);
                }
                
else
                {
                    
this._Ui = (Control)FakeObj;
                    
this._Name = _Ui.Name;
                    
this._Caption = ((Ui.FakeUserControl)_Ui).Caption;
                }
                pStream.Close();
            }
        }

 

  嗯,我们按照两种方式,将界面Form和UserControl区分开了,那么在展现的做一下手脚就可以了。

看一下总界面的展现方法实现

 

代码
        void IConfigUiManager.ShowUi()
        {
            Ui.FormConfigMain FormConfigMain 
= new AppConfig.Ui.FormConfigMain();
            TabControl pTab 
= FormConfigMain.pcCtl;
            
foreach (KeyValuePair<string, IConfigSectionUi> pUi in _List)
            {
                
if (pUi.Value.LazyLoad)
                {
                    
// pUi.Value.ShowUi();
                }
                
else//加入总界面
                {
                    TabPage pPage 
= new TabPage();
                    pPage.Text 
= pUi.Value.Caption;
                    pPage.Controls.Add(pUi.Value.Ui);
                    pUi.Value.Ui.Dock 
= DockStyle.Fill;
                    pTab.TabPages.Add(pPage);
                }
            }
            FormConfigMain.ShowDialog();
        }

 

如果发现此界面为单独界面即Form类型,则不加载到总界面中;

嗯,那么单个界面展示如何展示呢?看一下吧

 

代码
        void IConfigSectionUi.ShowUi()
        {
            
if (this._Ui == nullreturn;
            
if (_LazyLoad)
                
this._Ui.Show();
            
else
            {
                Ui.FormConfigDynamic frm 
= new AppConfig.Ui.FormConfigDynamic();
                frm.pnlCtl.Controls.Add(
this._Ui);
                frm.Show();
            }
        }

 

如果此界面为单独界面,直接Show出来,如果是个UserControl,则用内置的ormConfigDynamic界面包装一下然后Show出来。

好了,到此为止,基本实现了我们之前定义的需求。

展示一下几个测试界面

好了,到此,界面的动态展示基本完成。下次,我们将解决界面内选项的动态展示,也就是涉及到脚本技术跟C#的互动。

(未完待续...)

posted @ 2010-05-16 21:33 feedback 阅读(262) 评论(0) 编辑

  上次,我们分析了“动态”配置文件的基本需求,也基本定下了设计思路。我们今天就来实现第一要素:读写配置文件

  按照我们上次的分析要求,我设计了以下几个类

ConfigManager,【配置文件管理类】

Config,【单个配置文件】

ConfigSection,【配置文件中的单个程序节】

三个类依次包含,为了方便程序调用,为此,设计了三个接口,分别由三个类来实现。这样一来,外部调用的程序,只需要知道接口,而不需要引用这个类;

部分定义代码

IConfigManager定义

IConfigManager
 1     /// <summary>
 2     /// 配置文件管理接口
 3     /// </summary>
 4     public interface IConfigManager
 5     {
 6         /// <summary>
 7         /// 增加配置文件
 8         /// </summary>
 9         /// <param name="pCfg">配置文件</param>
10         void AddConfig(IConfig pCfg);
11         /// <summary>
12         /// 删除配置文件
13         /// </summary>
14         /// <param name="pCfg">配置文件</param>
15         void DeleteConfig(IConfig pCfg);
16         /// <summary>
17         /// 定位配置文件
18         /// </summary>
19         /// <param name="pName"></param>
20         /// <returns></returns>
21         IConfig FindConfig(string pName);
22         /// <summary>
23         /// 配置文件是否存在
24         /// </summary>
25         /// <param name="pName"></param>
26         /// <returns></returns>
27         bool HasExist(string pName);
28         /// <summary>
29         /// 默认配置文件后缀
30         /// </summary>
31         string DefaultEx
32         {
33             get;
34             set;
35         }
36         /// <summary>
37         /// 默认配置文件存放位置
38         /// </summary>
39         string DefaultFolder
40         {
41             get;
42             set;
43         }
44         /// <summary>
45         /// 加载目录下的所有配置文件
46         /// </summary>
47         void Load();
48         /// <summary>
49         /// 当前的配置文件
50         /// </summary>
51         IConfig CurrentConfig
52         {
53             get;
54             set;
55         }
56     }

 

IConfig定义

 

代码
 1     /// <summary>
 2     /// 单个配置文件
 3     /// </summary>
 4     public interface IConfig
 5     {
 6         /// <summary>
 7         /// 配置文件名称
 8         /// </summary>
 9         string Name
10         {
11             get;
12             set;
13         }
14         /// <summary>
15         /// 增加程序节
16         /// </summary>
17         /// <param name="pCfgSec"></param>
18         void AddSection(IConfigSection pCfgSec);
19         /// <summary>
20         /// 删除程序节
21         /// </summary>
22         /// <param name="pCfgSec"></param>
23         void DeleteSection(IConfigSection pCfgSec);
24         /// <summary>
25         /// 定位程序节
26         /// </summary>
27         /// <param name="pName"></param>
28         /// <returns></returns>
29         IConfigSection FindSection(string pName);
30         /// <summary>
31         /// 查询程序节是否存在
32         /// </summary>
33         /// <param name="pName"></param>
34         /// <returns></returns>
35         bool HasExist(string pName);
36         /// <summary>
37         /// 直接读取某个程序节下的设置
38         /// </summary>
39         /// <param name="pSectionName"></param>
40         /// <param name="pKeyName"></param>
41         /// <param name="pDefaultValue"></param>
42         /// <returns></returns>
43         object ReadKeyValue(string pSectionName, string pKeyName, object pDefaultValue);
44         /// <summary>
45         /// 写入某个程序节下,如果此程序节不存在,将创建
46         /// </summary>
47         /// <param name="pSectionName"></param>
48         /// <param name="pKeyName"></param>
49         /// <param name="pValue"></param>
50         void WriteKeyValue(string pSectionName, string pKeyName, object pValue);
51         /// <summary>
52         /// 加载文件,读取全部配置
53         /// </summary>
54         /// <param name="pFileName"></param>
55         void LoadfromFile(string pFileName);
56         /// <summary>
57         /// 设置保存到文件
58         /// </summary>
59         void SaveToFile();
60         /// <summary>
61         /// 自动保存
62         /// </summary>
63         bool AutoSave
64         {
65             get;
66             set;
67         }
68         /// <summary>
69         /// 是否开启文件监测
70         /// </summary>
71         bool Watched
72         {
73             get;
74             set;
75         }
76         /// <summary>
77         /// 此配置文件的文件路径
78         /// </summary>
79         string FileName
80         {
81             get;
82             set;
83         }
84     }

 

IConfigSection定义

 

代码
    /// <summary>
    
/// 配置分类
    
/// </summary>
    public interface IConfigSection
    {
        
string SectionName
        {
            
get;
            
set;
        }
        
void Add(string pKeyName, object pKeyValue);
        
void Delete(string pKeyName);
        
object ReadKeyValue(string pKeyName, object pDefaultValue);
        
void WriteKeyValue(string pKeyName, object pValue);
        
void SaveToFile();
    }

 

 

由于本次采用ini文件作为配置文件的载体,所以,在读写上就省略了很多方法。甚至在IConfig接口上提供了读写方法,但为了XML文件之类的读写,还是提供了方法定义。

(未完待续...)

posted @ 2010-05-16 20:55 feedback 阅读(822) 评论(1) 编辑