1.默认EF生成的连接字符串比较的长和怪异,若想使用普通的连接字符串来连接EF,则可以通过创建分部类,并重写一个构造函数,在构造函数中通过动态拼接EntityConnectionString得到EF所需的连接字符串,具代实现代码如下:
class="brush:csharp;gutter:true;"> public partial class DataEntities { private static ConcurrentDictionary<string, string> entityConnStrings = new ConcurrentDictionary<string, string>(); public DataEntities(string connName) : base(BuildEntityConnectionString(connName)) { } private static string BuildEntityConnectionString(string connName) { if (!entityConnStrings.ContainsKey(connName)) { var connStrSetting = System.Configuration.ConfigurationManager.ConnectionStrings[connName]; EntityConnectionStringBuilder entityConnStrBuilder = new EntityConnectionStringBuilder(); entityConnStrBuilder.Provider = connStrSetting.ProviderName; entityConnStrBuilder.ProviderConnectionString = EncryptUtility.DesDecrypt("XXXXX", connStrSetting.ConnectionString); entityConnStrBuilder.Metadata = "res://*/Data.csdl|res://*/Data.ssdl|res://*/Data.msl"; string entityConnString = entityConnStrBuilder.ToString(); entityConnStrings.AddOrUpdate(connName, entityConnString, (key, value) => entityConnString); } return entityConnStrings[connName]; } }
注意上面的类是一个分部类:partial,同时BuildEntityConnectionString方法是一个静态方法,在BuildEntityConnectionString方法中ProviderConnectionString = EncryptUtility.DesDecrypt("XXXXX", connStrSetting.ConnectionString);是关键,我这里是对config中的连接字符串 也都进行了加密,故此处我需要解密,若无这个需求可以直接:ProviderConnectionString =connStrSetting.ConnectionString即可。后续实例化EF上下文对象时,请使用:DataEntities(string connName)这个构造涵数即可,DataEntities是具体的EF上下文对象,大家的EF上下文类名均可能不相同。
2.支持一个通用对象的XML序列化(即:一个类中有可变类型属性成员,需要不同的序列结果及生成不同的序列元素名称),具体实现代码如下:
一个需要被序列化成XML的类:其中要求生成的XML元素detail必需有子元素,且子元素名称及子元素内部属性根据类型的不同而不同(即:detail元素下的子元素是可变的)
[XmlRootAttribute("master")] public class DemoMaster<T> where T : class { [XmlElement("attr")] public string DemoAttr { get; set; } [XmlElement("detail")] public DemoDetail<T> DemoDetail { get; set; } //关键点在这里,该属性元素为:detail,但其子元素根据T不同而不同 } public class DemoDetail<T> : IXmlSerializable where T : class { public T body { get; set; } public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(System.Xml.XmlReader reader) { string bodyStr = reader.ReadInnerXml(); this.body = XmlHelper.XmlDeserialize<T>(bodyStr, Encoding.UTF8); } public void WriteXml(System.Xml.XmlWriter writer) { writer.WriteRaw(XmlHelper.XmlSerialize(this.body, Encoding.UTF8, true)); } } [XmlTypeAttribute("list-a", AnonymousType = false)] public class DemoDetailA { public string Apro1 { get; set; } public string Apro2 { get; set; } public string Apro3 { get; set; } } [XmlTypeAttribute("list-b", AnonymousType = false)] public class DemoDetailB { public string Bpro1 { get; set; } public string Bpro2 { get; set; } public string Bpro3 { get; set; } } [XmlTypeAttribute("list-c", AnonymousType = false)] public class DemoDetailC { public string Cpro1 { get; set; } public string Cpro2 { get; set; } public string Cpro3 { get; set; } }
注意上面代码中,需要关注:DemoDetail属性及DemoDetail<T>类,DemoDetail属性仅是为了生成detail元素节点,而子节点则由DemoDetail<T>类来进行生成,DemoDetail<T>是实现了IXmlSerializable接口,在XML序列化时,DemoDetail<T>类仅将body属性对应的T类型实例内容进行序列化(WriteRaw),而反序列化时,则先反序列化body属性对应的T类型实例,然后赋值给body属性,这也是巧妙之处,DemoDetail<T>类本身并没有真正参与到序列化中,故序列化的字符串也看不到DemoDetail<T>类相关的元素,DemoDetail<T>类仅仅是一个XML序列化格式生成的中介。序列化的XML结果如下:
序列化代码:
var demo1 = new DemoMaster<DemoDetailA>() { DemoAttr = "demo1", DemoDetail = new DemoDetail<DemoDetailA>() { body = new DemoDetailA() { Apro1 = "demoA1", Apro2 = "demoA2", Apro3 = "demoA3" } } }; var demo2 = new DemoMaster<DemoDetailB>() { DemoAttr = "demo2", DemoDetail = new DemoDetail<DemoDetailB>() { body = new DemoDetailB() { Bpro1 = "demoB1", Bpro2 = "demoB2", Bpro3 = "demoB3" } } }; var demo3 = new DemoMaster<DemoDetailC>() { DemoAttr = "demo3", DemoDetail = new DemoDetail<DemoDetailC>() { body = new DemoDetailC() { Cpro1 = "demoC1", Cpro2 = "demoC2", Cpro3 = "demoC3" } } }; textBox1.Text = XmlHelper.XmlSerialize(demo1, Encoding.UTF8); textBox1.Text += "\r\n" + XmlHelper.XmlSerialize(demo2, Encoding.UTF8); textBox1.Text += "\r\n" + XmlHelper.XmlSerialize(demo3, Encoding.UTF8);
序列化的XML:
<?xml version="1.0" encoding="utf-8"?> <master> <attr>demo1</attr> <detail><list-a> <Apro1>demoA1</Apro1> <Apro2>demoA2</Apro2> <Apro3>demoA3</Apro3> </list-a></detail> </master> <?xml version="1.0" encoding="utf-8"?> <master> <attr>demo2</attr> <detail><list-b> <Bpro1>demoB1</Bpro1> <Bpro2>demoB2</Bpro2> <Bpro3>demoB3</Bpro3> </list-b></detail> </master> <?xml version="1.0" encoding="utf-8"?> <master> <attr>demo3</attr> <detail><list-c> <Cpro1>demoC1</Cpro1> <Cpro2>demoC2</Cpro2> <Cpro3>demoC3</Cpro3> </list-c></detail> </master>
3.winform DataGridView 实现指定列采取密码框模式显示与编辑,以及列绑定到复合属性(即:绑定到多层次属性),具体实现代码如下:
dataGridView1.CellFormatting += new DataGridViewCellFormattingEventHandler(dataGridView1_CellFormatting); dataGridView1.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(dataGridView1_EditingControlShowing); public string EvaluateValue(object obj, string property) { string retValue = string.Empty; string[] names = property.Split('.'); for (int i = 0; i < names.Count(); i++) { try { var prop = obj.GetType().GetProperty(names[i]); var result = prop.GetValue(obj, null); if (result != null) { obj = result; retValue = result.ToString(); } else { break; } } catch (Exception) { throw; } } return retValue; } private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { if (dataGridView1.Columns[e.ColumnIndex].DataPropertyName.Contains(".")) { e.Value = EvaluateValue(dataGridView1.Rows[e.RowIndex].DataBoundItem, dataGridView1.Columns[e.ColumnIndex].DataPropertyName); } if (dataGridView1.Columns[e.ColumnIndex].Name == "KeyCode") { if (e.Value != null && e.Value.ToString().Length > 0) { e.Value = new string('*', e.Value.ToString().Length); } } } private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) { int i = this.dataGridView1.CurrentCell.ColumnIndex; bool usePassword = false; if (dataGridView1.Columns[i].Name == "KeyCode") { usePassword = true; } TextBox txt = e.Control as TextBox; if (txt != null) { txt.UseSystemPasswordChar = usePassword; } } //示例:绑定的源数据类定义 public class DemoBindClass { public string Attr { get; set; } public string KeyCode { get; set; } public DemoDetailA Detail { get; set; } } public class DemoDetailA { public string Apro1 { get; set; } public string Apro2 { get; set; } public string Apro3 { get; set; } public DemoDetailB DetailChild { get; set; } } public class DemoDetailB { public string Bpro1 { get; set; } public string Bpro2 { get; set; } public string Bpro3 { get; set; } }
绑定到数据源:
var demo = new[] { new DemoBindClass() { Attr = "demo", KeyCode="a123456789b", Detail = new DemoDetailA() { Apro1 = "demoA1", Apro2 = "demoA2", Apro3 = "demoA3", DetailChild = new DemoDetailB() { Bpro1 = "demoB1", Bpro2 = "demoB2", Bpro3 = "demoB3" } } } }; dataGridView1.AutoGenerateColumns = false; dataGridView1.DataSource = demo;
实现指定列采取密码框模式显示与编辑,以及列绑定到复合属性均需要订阅DataGridView的CellFormatting及EditingControlShowing事件,并在其中写转换当前Cell的Value,实现列绑定到复合属性,关键点在:EvaluateValue方法,该方法逻辑很简单,就是根据绑定的属性层级(.分隔)层层遍历获取属性的值,直到遍历完或为空时停止,最后得到的结果即是绑定的属性的值。最终实现的效果如下图示: