有这样一个场景,有AB两个客户总对界面摆放有着不同的喜好,一个喜欢查询条件输入区(被放在一个groupbox中)在界面的上半部分,输入区在下半部分(被放在另一个groupbox中),另一个用户则正好相反,所以我们在界面设计确认时今天A在时,我们听他的要求,改一次,明天A去开会了,B来确认,又让我们改回来,几次下来,觉得很痛苦,如果界面有区多的区域,比如说一个查询条件输入区、一个业务数据录入区、一个输出区,这种情况下,客户的喜好更是会让你左改右改,所以我们最后决定提供以GroupBox为单位的,运行时可拖拽上下位置的功能,让不同的客户根据自己的喜好去拖拽,我们后台自动保存设定就是了。
场景描述很复杂,但代码实现却很简练:
一个全权负责拖放管理的类实现:
using System;
using System.Windows.Forms;
namespace Subindex
{
/// <summary>
///
/// </summary>
public class DragDropAgent//4 groupBox control in runtime dragDrop support, Written By Linnet 2006-4-6
{
private DragDropAgent()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
/// <summary>
/// 得到一个包含首层父控件的控件的对象名,如form1下groupbox1中的textbox1,将返回form1.textbox1
/// </summary>
/// <param name="sender">要获得对象名的控件实例</param>
/// <returns></returns>
public static string getFullName(Control sender)
{
string name=sender.Name;
while (sender.Parent!=null)
sender=sender.Parent;
return sender.Name+"."+name;
}
/// <summary>
/// 设置指定GroupBox控件的拖放操作,根据CanDrag和CanDrop决定拖出/放入的支持
/// </summary>
/// <param name="sender">要设置拖放特性的GroupBox对象</param>
/// <param name="CanDrag">是否可以拖出</param>
/// <param name="CanDrop">是否可以放入</param>
public static void DragDropHook(GroupBox sender,bool CanDrag,bool CanDrop)
{
if (CanDrag) DragHook(sender);
if (CanDrop) DropHook(sender);
gutPosition(sender);
}
/// <summary>
/// 设置指定GroupBox控件的拖放操作,同时支持拖出和放入
/// </summary>
/// <param name="sender">要设置拖放特性的GroupBox对象</param>
public static void DragDropHook(GroupBox sender)
{
DragDropHook(sender,true,true);
}
private static void DragHook(GroupBox sender)
{
sender.MouseDown+=new MouseEventHandler(Do_Drag);
}
private static void DropHook(GroupBox sender)
{
sender.AllowDrop=true;
sender.DragDrop+=new DragEventHandler(Drag_Drop);
sender.DragEnter+=new DragEventHandler(Drag_Enter);
}
private static void Drag_Enter(object sender, System.Windows.Forms.DragEventArgs e)
{
if (e.Data.GetDataPresent(new GroupBox().GetType()))
e.Effect = DragDropEffects.Move ;
}
private static void Do_Drag(object sender, MouseEventArgs e)
{
(sender as Control) .DoDragDrop(sender, DragDropEffects.Move);
}
private static void Drag_Drop(object sender, System.Windows.Forms.DragEventArgs e)
{
try
{
GroupBox self=sender as GroupBox;
GroupBox ct= e.Data.GetData(self.GetType()) as GroupBox;
if (self==ct) return;
Control parent=self.Parent;
int ord=parent.Controls.GetChildIndex(self);
int ordself=self.Top>ct.Top?ord+1:ord-1;
DockStyle dss=self.Dock;
self.Dock=ct.Dock;;
ct.Dock=dss;
//System.Drawing.Point dps=self.Location;
//self.Location=ct.Location;
//ct.Location=dps;
if (ordself>ord)
{
setPosition(self,ordself);
setPosition(ct,ord);
}
else
{
setPosition(ct,ord);
setPosition(self,ordself);
}
}
catch (Exception ee)
{
System.Windows.Forms.MessageBox.Show(ee.Message,"Error");
}
}
private static void gutPosition(GroupBox sender)
{
string order=AppSettings.ReadSetting(getFullName(sender)+":Order");
string dock=AppSettings.ReadSetting(getFullName(sender)+":Dock");
try
{
int Position=int.Parse(order);
sender.Parent.Controls.SetChildIndex(sender,Position);
Position=int.Parse(dock);
sender.Dock=(DockStyle)Position;
}
catch
{
}
}
private static void setPosition(GroupBox sender,int Position)
{
sender.Parent.Controls.SetChildIndex(sender,Position);
AppSettings.WriteSetting(getFullName(sender)+":Order",Position.ToString());
AppSettings.WriteSetting(getFullName(sender)+":Dock",((int)sender.Dock).ToString());
}
}
}
只要将所有groupBox的Dock属性设为同一方向后,只需要Form_Load时调用只需一句就可实现运行时拖放:
DragDropAgent.DragDropHook(this.grpIndex);
DragDropAgent.DragDropHook(this.grpWrap);//可拖动可放入,如果要设计成只可拖动或只可放入的请修改DragDropAgent类的那个实现方法的为public
另外,上述类中使用了负责配置文件写入的AppSettings类,代码也一并给出:
using System;
using System.Xml;
using System.Configuration;
using System.Reflection;
using System.IO;
namespace Subindex
{
/// <summary>
///
/// </summary>
public class AppSettings
{
private static readonly string configFile;
private AppSettings()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
static AppSettings()
{
configFile=getConfigFilePath();
}
//public static string ReadSetting(string key)
//{
//string s=null;
//try
//{
//
//s= ConfigurationSettings.AppSettings[key];
//}
//catch (Exception e)
//{
//System.Windows.Forms.MessageBox.Show(e.Message);
//}
//return s;
//}
public static string ReadSetting(string Key)
{
string Path="/configuration/appSettings/add";
XmlDocument doc = loadConfigDocument();
//if (doc.SelectSingleNode(Path) == null) return null;
XmlElement elem = (XmlElement)doc.SelectSingleNode(string.Format(Path+"[@key='{0}']", Key));
return elem==null?null:elem.GetAttribute("value");;
}
public static void WriteSetting(string Key, string Value)
{
XmlDocument doc = loadConfigDocument();
if (doc.SelectSingleNode("//configuration") == null)
doc.AppendChild(doc.CreateNode(XmlNodeType.Element,"configuration",""));
XmlNode node = doc.SelectSingleNode("//appSettings");
if (node == null)
{
node=doc.CreateNode(XmlNodeType.Element,"appSettings","");
doc.SelectSingleNode("//configuration").AppendChild(node);
}
try
{
XmlElement elem = (XmlElement)node.SelectSingleNode(string.Format("//add[@key='{0}']", Key));
if (elem != null)
{
elem.SetAttribute("value", Value);
}
else
{
elem = doc.CreateElement("add");
elem.SetAttribute("key", Key);
elem.SetAttribute("value", Value);
node.AppendChild(elem);
}
doc.Save(configFile);
}
catch
{
throw;
}
}
public static void RemoveSetting(string key)
{
XmlDocument doc = loadConfigDocument();
XmlNode node = doc.SelectSingleNode("//appSettings");
try
{
if (node == null)
throw new InvalidOperationException("appSettings section not found in config file.");
else
{
node.RemoveChild(node.SelectSingleNode(string.Format("//add[@key='{0}']", key)));
doc.Save(configFile);
}
}
catch (NullReferenceException e)
{
throw new Exception(string.Format("The key {0} does not exist.", key), e);
}
}
private static XmlDocument loadConfigDocument()
{
XmlDocument doc = null;
try
{
doc = new XmlDocument();
doc.Load(configFile);
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
}
return doc;
}
public static string getConfigFilePath()
{
string configFile=Assembly.GetExecutingAssembly().Location + ".config";
if (!File.Exists(configFile)) CreateFile(configFile);
return configFile;
}
public static bool ConfigFileExist()
{
string configFile=Assembly.GetExecutingAssembly().Location + ".config";
return File.Exists(configFile);
}
private static void CreateFile(string FileName)
{
XmlTextWriter writer = new XmlTextWriter(FileName,System.Text.Encoding.Default);
writer.WriteStartElement("configuration");
writer.WriteStartElement("appSettings");
writer.WriteEndElement() ;
writer.Flush();
writer.Close();
}
}
}