作者:李福红
工作单位:河南省鹤壁市鹤壁工贸学校计算机教研室
联系地址:河南省鹤壁市淇滨区兴鹤大街南段鹤壁工贸学校
邮编:458030
Email:hebiziyu@https://www.wendangku.net/doc/9b3362005.html, ;hebilifuhong@https://www.wendangku.net/doc/9b3362005.html,
联系电话:138********
XtraLayout让软件用户拥有自己个性化的界面
----DevExpress For https://www.wendangku.net/doc/9b3362005.html, 高级技巧系列(三)
李福红
摘要:DevExress控件是https://www.wendangku.net/doc/9b3362005.html,开发中应用最广、效果最出众的控件包之一,这里我们尝试用具体实例来介绍它的一些高级用法。
关键词:DevExpress控件;运行时动态设置;XtaLayout技巧;个性化软件界面;
正文:
DevExpres产品是全球享有极高声誉的一流控件套包产品!其中的XtraLayoutControl 可以帮助我们快速的创建漂亮的界面,从控件的自动排版到分辨率独立,XtraLayoutControl提供一套全面的表单设计特征集。XtraLayoutControl通过动态设计布局,可以帮助软件的最终用户轻松布局自己的个性化软件界面,极大地满足用户需求,一直以来,这个问题就是困扰软件开发工作者的一个难题。如今、DevExpress的XtarLayoutControl通过有效地运行期设计,完美解决了这一难题。我们结合自己的教学和开发实例,在这里就这个问题做一介绍,希望对读者朋友能够有所助益。
开发环境:VS2010 C#,Access,DevExpress 控件包V10.1.5。
示例软件运行环境:.netframework2.0,windows xp/windows2003/windows7/Access2003。
要实现用户界面的个性化定义,我们不妨来看看通常需要考虑哪些因素是必要的。首先、既然是用户个性化设置,自然少不了用户姓名(或用户账号);其次,目前绝大多数软件都有一套权限机制,自定义用户界面作为涉及到系统级的设计、自然也少不了权限的机制;第三,对于软件开发而言,一个窗体经过处理从而作为多种应用界面的情况屡见不鲜(这也是软件设计中的一个基本方针了),所以,自定义用户界面数据的存储、应该考虑的是最终呈现给用户时显示的窗体标题而不是设计期间的窗体名称;第四,既然是要保存XtraLayout 的界面设置信息,我们需要知道保存的是哪一个XtraLayout,也就是控件的名称。有了这些因素,我们就可以来设计我们需要的用于保存界面设置信息的数据库表结构了。来看下面的表格:
有了以上的信息,我们就可以以此建立需要的数据表了,详细的建表脚本,我们这里就不说了,示例程序中有access数据库,表名称为:Sys_UIStream,朋友们可自行查看。
准备好了数据库,我们来看看XtraLayout控件是否能满足我们的需要。
XtraLayout控件有一个保存的方法,在代码智能提示中我们可以看到该方法的三个重载:layoutControl1.SaveLayoutToXml(string sXMLFileName);——保存Layout布局到XML 文件;
layoutControl1.SaveLayoutToRegistry(string sRegPath); ——保存Layout布局到系统注册表;
layoutControl1.SaveLayoutToStream(myStream); ——保存Layout布局到内存流;
考虑到我们的要求、xml和注册表的方法我们放弃,内存流是无法直接写入到数据库的,不过我们可以把内存流数据转换成长字符串(ToBase64String),这样就可以顺利写入数据库了。好了、有了这样的分析结论、我们首先用代码来实现内存流写入数据库的部分功能:
using System;
using System.Data;
using System.IO;
namespace DevControlpractice.LFH.Function
{
public class UIStream_Database
{
///
/// 从数据库读取Layout 界面配置数据流。
///
///
///
///
public static MemoryStream GetUIStream_ForceDB(string MenuName, string ControlName, string RightValue, string sUserName)
{
var dt = new DataTable();
MemoryStream myStream = null; //定义一个内存流变量、用于存放从数据库中读取到的界面配置流。
string sSq =
string.Format(
"select * from Sys_UIStream where FormName='{0}' and FormPower='{1}' and FormComent='{2}' and UserName='{3}'", MenuName,
RightValue, ControlName, sUserName);
dt = AccessHelper.ExecuteSqlQuery(AccessHelper.connStr, sSq, null); //从数据库中读取指定的配置;
if (dt.Rows.Count > 0)
{
//将数据库中存储的流字符串转化为内存流。
myStream =
LFHConvert.ConvertBase64StringToObject(dt.Rows[0]["FormStream"].ToString()) as MemoryStream;
return myStream;
}
else
return null;
}
///
/// 保存流到数据库;
///
/// 窗体名称
/// 控件名称
/// 权限标识
/// 内存流字符串
public static string _saveStream(string sFName, string sComponentName, string sFPower, string myStreamStr, string sUserName)
{
string sSq =
string.Format(
"select * from Sys_UIStream where FormName='{0}' and FormPower='{1}' and FormComent='{2}' and UserName='{3}'", sFName,
sFPower, sComponentName, sUserName);
//首先检查数据库中是否已经存在当前窗体、当前控件在当前权限下的界面数据流信息
DataTable dt = AccessHelper.ExecuteSqlQuery(AccessHelper.connStr, sSq, null);
bool isExist = false;
if ((dt != null) && (dt.Rows.Count > 0))
{
isExist = true;
}
string sqltxt = "";
if (isExist)
{
//如果数据库中已经存在当前界面配置信息,则使用更新方法更新数据库中的信息;
sqltxt =
string.Format(
"update sys_uistream set FormStream='{0}', ModifyDate=convert(datetime,'{1}')
where [FormName]='{2}' and [FormPower]='{3}'and [FormComent]='{4}' and UserName='{5}'",
myStreamStr, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), sFName, sFPower, sComponentName, sUserName);
}
else
{
//否则插入新纪录,将当前界面流数据保存到数据库中去;
sqltxt =
string.Format(
"insert into
sys_uistream([ID],[DelMark],[CreateDate],[CreateBy],[FormName],[FormPower],[FormComent],[FormStream],[ UserName]) values('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}')",
FuncCommon.getGuidString(), "False", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
"Your Name here", sFName, sFPower, sComponentName, myStreamStr, sUserName);
}
return AccessHelper.ExecuteNonQuery(AccessHelper.connStr, sqltxt, null).ToString();
}
//**************************************************************** }
}
Ok,接下来我们要做的、就是在界面层中根据不同的需要来调用这些方法:
代码实现:
以下代码、位于项目中的:namespace DevControlpractice.LFH.Function. LFHConvert ///
/// 将object对象序列化转存为字符串
///
/// 对象名
///
public static string ConvertObjectToBase64String(object o)
{
if (o == null)
{
return null;
}
var stream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(stream, o);
byte[] b = stream.ToArray();
stream.Close();
stream.Dispose();
return Convert.ToBase64String(b);
}
///
/// 将序列化的字符串还原为对象
///
/// 序列化后的字符串对象
///
public static object ConvertBase64StringToObject(string Base64String)
{
if ((Base64String == null) | (Base64String == ""))
{
return null;
}
else
{
var ms = new MemoryStream();
var formatter = new BinaryFormatter();
byte[] b = Convert.FromBase64String(Base64String);
ms.Write(b, 0, b.Length);
ms.Position = 0;
object o = formatter.Deserialize(ms);
ms.Close();
ms.Dispose();
return o;
}
}
界面层按钮事件:
开始自定义布局按钮:
///
/// 开始自定义界面布局;
///
///
///
private void SimpleButton2Click(object sender, EventArgs e)
{
layoutControl1.ShowCustomizationForm();
}
保存界面和加载界面按钮:
private void simpleButton4_Click(object sender, EventArgs e)
{
var myStream = new MemoryStream();//新建一个内存数据流对象;
layoutControl1.SaveLayoutToStream(myStream);//将Layout界面布局保存到内存流,这是Xtralayout控件自身的方法;
string myStreamStr = LFHConvert.ConvertObjectToBase64String(myStream);//把
内存流对象转换为Base64string 类型。
sUser = "李四";
UIStream_Database._saveStream(Text, https://www.wendangku.net/doc/9b3362005.html,, "None", myStreamStr, sUser);//保存到数据库中去;
}
///
/// 加载用户自定义界面;
///
///
///
private void simpleButton5_Click(object sender, EventArgs e)
{
if (!DesignMode)
{
sUser = "张三";//设置用户名称
MemoryStream myStream = UIStream_Database.GetUIStream_ForceDB(Text, https://www.wendangku.net/doc/9b3362005.html,, "None", sUser);//根据当前窗体标题、Layout控件名称、权限标识、用户名称这几个条件来读取用户自定义的界面数据流信息。
if (myStream != null)
{
//设置指针到内存流的起始位置0,——这一点很重要!
myStream.Seek(0, SeekOrigin.Begin);
layoutControl1.RestoreLayoutFromStream(myStream);//从读取到的界
面配置流中恢复Layout控件的用户自定义布局,从而给特定用户呈现特定的界面布局状态;
}
}
}
示例项目运行界面如下:(默认界面)
以修改界面上的文本显示信息。
加载“张三布局”之后的运行界面。看、是不是很方便?
细心的读者可能留意到了一个问题:我们在前面分析问题的时候,提到了权限和用户两个要素,但我们上面的实现方法中并没有给出明确的应用,这是因为本演示代码仅仅是从实际项目中抽取出来的,本着简洁明了的出发点,并没有加入完整的权限模块。朋友们在实际的应用中,可以把用户账号和权限标识加入到读取和写入的方法中去,就完整实现了我们上面分析的应用。当然,朋友们也可以根据自己的实际项目需求、加入更多的因素,从而实现更加复杂的应用需要。
结语:
我们在这里以数据库为例子介绍了存储界面设置的思路和方法。需要说明的是,XtraLayout不仅可以保存到数据库,还可以保存为xml文件或其他形式,方法则是大同小异,
究竟使用哪种方式,则是要根据具体的项目需要来确定的,朋友们不妨尝试一下。