将一些有用的实例整理出来,供参考。FAQ形式,整理多少记多少。
【目录】
1. 如何制作安装包能在Menu菜单中添加卸载菜单
首先需要一个Uninstall的bat文件。其实是调用系统的 msiexec.exe 来删除程序。
@echo off
%windir%/system32/msiexec.exe /x {7EFECBCB-357A-47DE-9AC0-C220A62FA217}
红色字体是程序的 ProductCode, 从安装工程的属性里可以看到。
然后把这个bat作为程序的内容添加到安装包里来。最后在用户的Program Menu的程序菜单里添加上这个bat的快捷方式就可以了。(bat会和exe一起输出到安装路径下)
2. 如何让应用程序只能启动1次
方法1: 通过ProcessName判断当前进程中,是否启动了当前程序名的进程。
[STAThread] static void Main() { if (System.Diagnostics.Process.GetProcessesByName( System.Diagnostics.Process.GetCurrentProcess().ProcessName).Length > 1) { MessageBox.Show("应用程序已经启动过了。"); return; } Application.Run(new Form1()); }
方法2: 利用System.Threading.Mutex对象,即应用程序启动时都去检查一个共享区,如果已经上锁则退出。
[STAThread]static void Main() { bool createNew = false; System.Threading.Mutex mutex = new System.Threading.Mutex(true, "MyApplication", out createNew); if (createNew == false) { MessageBox.Show("应用程序已经启动过了。"); return; } Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); // 释放锁 mutex.ReleaseMutex(); }
需要注意的是: Mutex.ReleaseMutex是在最后调用的。从.NET 2.0开始,Thread如果在Mutex没有释放时退出,那么这个mutex就会被标识为废弃。(如果Application途中Crash的情况发生)那么,下一个尝试取得Mutex的线程,就会抛出:AbandonedMutexException异常。另外,如果Mutex被废弃的情况下,也有可能发生Application被强制终止。因此,上面的代码稍微改进一下。
private static System.Threading.Mutex _mutex; [STAThread] static void Main() { _mutex = new System.Threading.Mutex(false, "MyApplication"); //Mutex所有权取得 if (_mutex.WaitOne(0, false) == false) { MessageBox.Show("应用程序已经启动过了。"); return; } Application.Run(new Form1()); }
注意:这里的Mutex被定义为Static类成员。这是因为如果定义为局部变量,Mutex所有权取得有时候不能正常进行。另外,也存在程序运行中GC把局部变量销毁的可能性。当然,定义为局部变量的Mutex也可以通过GC.KeepAlive方法来保持。
另外,对于多用户互斥只要在Mutex名称上加上:"Global\\" 的前缀就可以了。
3. 如何让DataTable.WriteXml保存的Xml加上Encoding声明
先看看通常的写法:
static void DataTableWriteXmlDefault() { DataTable data = new DataTable("TestData"); data.Columns.Add("Column1"); data.Columns.Add("Column2"); data.Rows.Add("value11", "value12"); data.Rows.Add("value21", "value22"); data.Rows.Add("value31", "value32"); string xmlFilePath = "test1.xml"; data.WriteXml(xmlFilePath); }
生成的XML如下,注意到没,在Xml里并没有指定Encoding(第一行的Xml头)。如果DataTable保存有一些中文信息的话,再次读入的时候就需要指定编码了。(如果系统是非中文系统的话,比如日文系统,保存的Xml就有可能变为乱码)
<?xml version="1.0" standalone="yes"?> <DocumentElement> <TestData> <Column1>value11</Column1> <Column2>value12</Column2> </TestData> <TestData> <Column1>value21</Column1> <Column2>value22</Column2> </TestData> <TestData> <Column1>value31</Column1> <Column2>value32</Column2> </TestData> </DocumentElement>
那么如何加入Encoding声明呢?——通过XmlWriter的WriteProcessingInstruction来控制。
using (System.Xml.XmlTextWriter xtw = new System.Xml.XmlTextWriter(xmlFilePath, Encoding.UTF8)) { xtw.WriteProcessingInstruction("xml", "version=/"1.0/" encoding=/"UTF-8/""); xtw.Formatting = System.Xml.Formatting.Indented; data.WriteXml(xtw); }
这样生成的Xml就加上Encoding声明了:
<?xml version="1.0" encoding="UTF-8"?>
<DocumentElement>
<TestData>
<Column1>value11</Column1>
<Column2>value12</Column2>
</TestData>
<TestData>
<Column1>value21</Column1>
<Column2>value22</Column2>
</TestData>
<TestData>
<Column1>value31</Column1>
<Column2>value32</Column2>
</TestData>
</DocumentElement>
5. 如何将一个Form加到另一个Form里
我们在开发时,有时会需要非常复杂的画面,里面充满了各种控件,还有多个TabPage。上百个控件充斥着Form,不要说并行开发了,design时修改一个控件都害怕牵一发而动全身。通常我们会抽出共同的用户控件来简化开发。这里介绍另一个方法来应对这种场景的问题:那就是将主画面进行分解,分解到各个子画面中。再通过Controls.Add的方式组合到主画面中。
var subForm = new Form2();subForm.TopLevel = false;this.Controls.Add(subForm);subForm.Show();
效果如下:
修改 subForm 的 FormBorderStyle 为 None 之后,看上去 subform 就像是用户控件一样了。
6. 如何在项目中引用exe路径以外的dll
1. 主工程添加控件工程,copy local设置为false
(这个意思是控件工程生成的dll不会copy到主工程下,即不会build一份和exe放在一块。)
2. 在主工程里添加一个app.config。配置如下:
<?xml version="1.0"?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <!--<probing privatePath="bin;bin2/subbin;bin3"/>--> <dependentAssembly> <assemblyIdentity name="MyCheckBoxCtrl"/> <codeBase href="ExtDlls/MyCheckBoxCtrl.dll" mce_href="ExtDlls/MyCheckBoxCtrl.dll"/> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
注意:如果是强名称的dll,可以是放在任意位置。没有强名称的dll只能放在exe目录下面的某个子目录。
比如:exe是在bin/debug,那么可以放在 bin/debug/bin2 或者其他的别的名字的目录里。
7. 如何在window service里运行"cmd.exe"
一般默认安装完的service运行"cmd.exe"不会有什么效果。这里是说:可能调用不会出错但实际上并没有成功的执行。
原因在于:安全上限制。你可以看到下面抓图中,"Allow Service to interact with desktop"没有勾选上。
下面的代码可以让你在安装时将此选项勾选上:
【在 ProjectInstaller 里重写了 Commit 方法】
public override void Commit(IDictionary savedState) { // set the service "allow service interact with desktop" as "true" // e.g. service can run "cmd.exe" var coOptions = new ConnectionOptions {Impersonation = ImpersonationLevel.Impersonate}; var mgmtScope = new ManagementScope(@"root\CIMV2", coOptions); mgmtScope.Connect(); var wmiService = new ManagementObject("Win32_Service.Name='" + serviceInstaller1.ServiceName + "'"); var inputParams = wmiService.GetMethodParameters("Change"); inputParams["DesktopInteract"] = true; var outParams = wmiService.InvokeMethod("Change", inputParams, null); base.Commit(savedState); }
9. 动态创建 Lambda 表达式
class Program { static void Main(string[] args) { var user = new User { ID = "123" }; var parameter = Expression.Parameter(typeof(User), "s"); var memberAccessor = Expression.MakeMemberAccess(parameter, typeof(User).GetField("ID")); var constant = Expression.Constant("123", typeof(string)); // static method call expression var method = typeof(string).GetMethod("Equals", new[] {typeof(string), typeof(string)}); var callExpr = Expression.Call(method, memberAccessor, constant); var lambda = Expression.Lambda<Func<User, bool>>(callExpr, parameter); var exec = lambda.Compile(); var result = exec(user); Console.WriteLine(lambda.ToString() + "\t" + result); // binary expression var binaryExpr = Expression.Equal(memberAccessor, constant); var lambda1 = Expression.Lambda<Func<User, bool>>(binaryExpr, parameter); var exec1 = lambda1.Compile(); var result1 = exec1(user); Console.WriteLine(lambda1.ToString() + "\t" + result1); // instance method call expression var method1 = typeof(User).GetMethod("Validate"); var callExpr1 = Expression.Call(parameter, method1, constant); var lambda2 = Expression.Lambda<Func<User, bool>>(callExpr1, parameter); var exec2 = lambda2.Compile(); var result2 = exec2(user); Console.WriteLine(lambda2.ToString() + "\t" + result2); Console.Read(); } } class User { public string ID; public bool Validate(string arg) { return string.Equals(ID, arg); } }
private void Form1_Load(object sender, EventArgs e) { webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted); } void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { var htmlDoc = (IHTMLDocument3)webBrowser1.Document.DomDocument; HTMLHeadElement head = htmlDoc.getElementsByTagName("head").Cast<HTMLHeadElement>().First(); var script = (IHTMLScriptElement)((IHTMLDocument2)htmlDoc).createElement("script"); script.text = "window.onload=function() { alert('test') }"; head.appendChild((IHTMLDOMNode)script); } private void button1_Click(object sender, EventArgs e) { webBrowser1.Navigate("http://www.hao123.com"); }private void Form1_Load(object sender, EventArgs e) { webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted); } void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { var htmlDoc = (IHTMLDocument3)webBrowser1.Document.DomDocument; HTMLHeadElement head = htmlDoc.getElementsByTagName("head").Cast<HTMLHeadElement>().First(); var script = (IHTMLScriptElement)((IHTMLDocument2)htmlDoc).createElement("script"); script.text = "window.onload=function() { alert('test') }"; head.appendChild((IHTMLDOMNode)script); } private void button1_Click(object sender, EventArgs e) { webBrowser1.Navigate("http://www.hao123.com"); }