将一些有用的实例整理出来,供参考。FAQ形式,整理多少记多少。
【目录】
- 如何制作安装包能在Menu菜单中添加卸载菜单
- 如何让应用程序只能启动1次
- 如何让DataTable.WriteXml保存的Xml加上Encoding申明
- 如何读取两个以上的游标?(DataReader.NextResult)
- 将Form加到另一个Form里
- 如何在项目中引用exe路径以外的dll
- 如何在windows service里运行"cmd.exe"
- 如何添加Clickonce的Publish页面
- 动态创建 Lambda 表达式
- 在WebBrowser控件中注入脚本
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的方式组合到主画面中。
效果如下:
修改 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);
}
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);
}
}
10. 在WebBrowser控件中注入脚本
(1) 添加 Microsoft.mshtml.dll 引用
(2) 添加代码如下:
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.οnlοad=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.οnlοad=function() { alert('test') }";
head.appendChild((IHTMLDOMNode)script);
}
private void button1_Click(object sender, EventArgs e)
{
webBrowser1.Navigate("http://www.hao123.com");
}