讓你的Winform應用在執行時可自由拖放控制元件位置
有這樣一個場景,有AB兩個客戶總對介面擺放有著不同的喜好,一個喜歡查詢條件輸入區(被放在一個groupbox中)在介面的上半部分,輸入區在下半部分(被放在另一個groupbox中),另一個使用者則正好相反,所以我們在介面設計確認時今天A在時,我們聽他的要求,改一次,明天A去開會了,B來確認,又讓我們改回來,幾次下來,覺得很痛苦,如果介面有區多的區域,比如說一個查詢條件輸入區、一個業務資料錄入區、一個輸出區,這種情況下,客戶的喜好更是會讓你左改右改,所以我們最後決定提供以GroupBox為單位的,執行時可拖拽上下位置的功能,讓不同的客戶根據自己的喜好去拖拽,我們後臺自動儲存設定就是了。
場景描述很複雜,但程式碼實現卻很簡練:
一個全權負責拖放管理的類實現:
using System;
using System.Windows.Forms;
namespace Subindex
{
///
///
///
public class DragDropAgent//4 groupBox control in runtime dragDrop support, Written By Linnet 2006-4-6
{
private DragDropAgent()
{
//
// TODO: 在此處新增建構函式邏輯
//
}
///
/// 得到一個包含首層父控制元件的控制元件的物件名,如form1下groupbox1中的textbox1,將返回form1.textbox1
///
/// 要獲得物件名的控制元件例項
///
public static string getFullName(Control sender)
{
string name=sender.Name;
while (sender.Parent!=null)
sender=sender.Parent;
return sender.Name+"."+name;
}
///
/// 設定指定GroupBox控制元件的拖放操作,根據CanDrag和CanDrop決定拖出/放入的支援
///
/// 要設定拖放特性的GroupBox物件
/// 是否可以拖出
/// 是否可以放入
public static void DragDropHook(GroupBox sender,bool CanDrag,bool CanDrop)
{
if (CanDrag) DragHook(sender);
if (CanDrop) DropHook(sender);
gutPosition(sender);
}
///
/// 設定指定GroupBox控制元件的拖放操作,同時支援拖出和放入
///
/// 要設定拖放特性的GroupBox物件
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
{
///
///
///
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();
}
}
}