最近,我给一家公司做了个电梯多媒体软件,该软件使用C#编写,现在我将其中遇到的问题及其解决方法总结一下,以便下次再遇到同样的问题可以快速解决;同时,也给博友分享一下,共同学习,共同提高。
1、Question:关闭窗体时出现“执行CreateHandle()时无法调用值Dispose()”的错误,如下图所示:
Answer:原因是当前窗体的句柄还未创建完成,还存在CreateHandle()事件,还不能回收垃圾,还不能直接关闭窗体。
在执行窗体的Close方法时,加入判断语句,如下:
if ( !IsHandleCreated)
{
this.Close();
}
2、Question:C#窗体间相互调用及数据传递方法
Answer:当我们在一个主窗体MainForm中生成一个窗体Form1,而又需要将窗体Form1中的数据传给MainForm,此时就涉及到窗体间的相互调用。
1)当我们在主窗体MainForm中生成窗体Form1时,采用模式窗体,将MainForm设为Form1的父窗体,在Form1中调用MainForm时直接获取其父窗体即可:
//MainForm中
Form1 form1 = new Form1();
form1.ShowDialog(this); //Form1中
MainForm mainform = (MainForm)this.Owner;
mainform.BackColor = Color.Black;
mainform.button1.BackColor = Color.Blue;
2)使用回调对象的方法:
//MainForm中
Form1 form1 = new Form1();
form1.mainform = this;
form1.Show(); //Form1中
public MainForm mainform = new MainForm();
mainform.BackColor = Color.Black;
mainform.button1.BackColor = Color.Blue;
3、Question:局域网内文件的传输
Answer:下面列举几种我尝试的局域网内文件传输的方法:
1)文件复制至共享文件夹:引用Microsoft.VisualBasic.dll,调用FileSystem类的FileCopy方法
2)FTP协议
4、Question:C/S模式中的网络通信(进程间通信)
Answer:Socket
5、Question:播放视频
Answer:COM组件Windows Media Player
在C# .NET Windows应用程序中做视频播放,首先要用到COM组件中的WMP控件(Windows Media Player)。下面主要讲述在VS2010中WinForm窗体WMP控件的使用。
(1)在建好WinForm窗体后首先应添加COM组件Windows Media Player的引用。
(2)添加引用后,会建立其对象
private AxWMPLib.AxWindowsMediaPlayer axWindowsMediaPlayer;
其初始化代码如下所示:
//
// axWindowsMediaPlayer
//
this.axWindowsMediaPlayer.Enabled = true;
this.axWindowsMediaPlayer.Location = new System.Drawing.Point(0, 0);
this.axWindowsMediaPlayer.Name = "axWindowsMediaPlayer";
this.axWindowsMediaPlayer.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("axWindowsMediaPlayer.OcxState")));
this.axWindowsMediaPlayer.Size = new System.Drawing.Size(400, 300);
this.axWindowsMediaPlayer.TabIndex = 0;
(3)设置其循环播放模式
this.axWindowsMediaPlayer.settings.setMode("loop", true);//循环播放
(4)播放列表操作
axWindowsMediaPlayer.currentPlaylist.clear();//清空
axWindowsMediaPlayer.currentPlaylist.appendItem(axWindowsMediaPlayer.newMedia("test.mp4"));//添加
(5)播放器控制
axWindowsMediaPlayer.Ctlcontrols.play();//播放
(6)Windows Media Player控件的详细说明:
[基本属性]
- URL:string 可以指定媒体位置
- enableContextMenu:Boolean 显示/不显示播放位置的右键菜单
- fullScreen:boolean 全屏显示
- stretchToFit:boolean 非全屏状态时是否伸展到最佳大小
- uMode:string 播放器的模式,full:有下面的控制条; none:只有播放部份没有控制条
- playState:integer 当前控件状态,状态变化时会触发OnStatusChange事件,其值如下所示:
Value State Description
Undefined Windows Media Player is in an undefined state.(未定义)
Stopped Playback of the current media item is stopped.(停止)
Paused Playback of the current media item is paused. When a media item is paused, resuming playback begins from the same location.(停留)
Playing The current media item is playing.(播放)
ScanForward The current media item is fast forwarding.
ScanReverse The current media item is fast rewinding.
Buffering The current media item is getting additional data from the server.(转换)
Waiting Connection is established, but the server is not sending data. Waiting for session to begin.(暂停)
MediaEnded Media item has completed playback. (播放结束)
Transitioning Preparing new media item.
Ready Ready to begin playing.(准备就绪)
Reconnecting Reconnecting to stream.(重新连接)
[controls]
可通过WindowsMediaPlayer.controls对播放器进行控制并取得相关的一些信息:
- controls.play; 播放
- controls.stop; 停止
- controls.pause; 暂停
- controls.currentPosition:Double 当前播放进度
- controls.currentPositionString:string 时间格式的字符串 “0:32″
[currentMedia]
可以通过WindowsMediaPlayer.currentMedia取得当前媒体的信息
- currentMedia.duration Double 总长度
- currentMedia.durationString 时间格式的字符串 “4:34″
[settings]
可以通过WindowsMediaPlayer.settings对播放器进行设置,包括音量和声道等。
- settings.volume:integer 音量 (0-100)
- settings.balance:integer 声道,通过它应该可以进行立体声、左声道、右声道的控制。
6、Question:获取并显示天气信息
Answer:添加Web服务引用(http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx)
(1)建好WinForm项目后,添加服务引用
(2)获取天气的核心代码:
private string[] MyGetWeather()
{
weatherInfos = new string[]{""};//length: 32 string
try
{
MyWeatherWS.WeatherWS weather = new MyWeatherWS.WeatherWS();
weatherInfos = weather.getWeather(strWeatherCity, "");
return weatherInfos;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n远程网络连接失败!", "网络错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return weatherInfos;
}
}
(3)关于WeatherWS的使用,参考http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx
7、Question:INI配置文件操作
Answer:
1)调用系统函数GetPrivateProfileString()和WritePrivateProfileString()等
(1)导入库
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
(2)调用函数读写ini配置文件
//读
StringBuilder strCom = new StringBuilder();
GetPrivateProfileString("串口参数", "端口", "", strCom, , "Setting.ini"); //写
WritePrivateProfileString("串口参数", "端口", "COM3", "Setting.ini");
2)配置文件操作组件:SharpConfig
SharpConfig 是 .NET 的 CFG/INI 配置文件操作组件。
配置文件示例(sample.cfg):
[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment
SomeFloat = 20.05
ABoolean = true
C#代码示例:
Configuration config = Configuration.LoadFromFile( "sample.cfg" );
Section section = config["General"];
string someString = section["SomeString"].Value;
int someInteger = section["SomeInteger"].GetValue<int>();
float someFloat = section["SomeFloat"].GetValue<float>();
上述SharpConfig参考http://www.oschina.net/p/sharpconfig。
8、Question:获取并显示时间日期
Answer:调用DateTime.Now对象的方法
//获取时间
DateTime.Now.ToLongTimeString().ToString(); // 16:16:16
//获取日期
DateTime.Now.ToLongDateString().ToString(); // 2015年9月5日
DateTime.Now.ToShortDateString().ToString(); // 2015-9-5
DateTime.Now.ToString("yyyy-MM-dd"); // 2015-09-05
9、Question:ToString()格式
Answer:Int.ToString("Format"),Format如下所示:
10、Question:String方法
Answer:如下所示
string s = "";
//(1)字符访问(下标访问s[i])
s = "ABCD";
Console.WriteLine(s[]); // 输出"A";
Console.WriteLine(s.Length); // 输出4
Console.WriteLine(); //(2)打散为字符数组(ToCharArray)
s = "ABCD";
char[] arr = s.ToCharArray(); // 把字符串打散成字符数组{'A','B','C','D'}
Console.WriteLine(arr[]); // 输出数组的第一个元素,输出"A"
Console.WriteLine();
//(3)截取子串(Substring)
s = "ABCD";
Console.WriteLine(s.Substring()); // 从第2位开始(索引从0开始)截取一直到字符串结束,输出"BCD"
Console.WriteLine(s.Substring(, )); // 从第2位开始截取2位,输出"BC"
Console.WriteLine(); //(4)匹配索引(IndexOf())
s = "ABCABCD";
Console.WriteLine(s.IndexOf('A')); // 从字符串头部开始搜索第一个匹配字符A的位置索引,输出"0"
Console.WriteLine(s.IndexOf("BCD")); // 从字符串头部开始搜索第一个匹配字符串BCD的位置,输出"4"
Console.WriteLine(s.LastIndexOf('C')); // 从字符串尾部开始搜索第一个匹配字符C的位置,输出"5"
Console.WriteLine(s.LastIndexOf("AB")); // 从字符串尾部开始搜索第一个匹配字符串BCD的位置,输出"3"
Console.WriteLine(s.IndexOf('E')); // 从字符串头部开始搜索第一个匹配字符串E的位置,没有匹配输出"-1";
Console.WriteLine(s.Contains("ABCD")); // 判断字符串中是否存在另一个字符串"ABCD",输出true
Console.WriteLine(); //(5)大小写转换(ToUpper和ToLower)
s = "aBcD";
Console.WriteLine(s.ToLower()); // 转化为小写,输出"abcd"
Console.WriteLine(s.ToUpper()); // 转化为大写,输出"ABCD"
Console.WriteLine(); //(6)填充对齐(PadLeft和PadRight)
s = "ABCD";
Console.WriteLine(s.PadLeft(, '_')); // 使用'_'填充字符串左部,使它扩充到6位总长度,输出"__ABCD"
Console.WriteLine(s.PadRight(, '_')); // 使用'_'填充字符串右部,使它扩充到6位总长度,输出"ABCD__"
Console.WriteLine(); //(7)截头去尾(Trim)
s = "__AB__CD__";
Console.WriteLine(s.Trim('_')); // 移除字符串中头部和尾部的'_'字符,输出"AB__CD"
Console.WriteLine(s.TrimStart('_')); // 移除字符串中头部的'_'字符,输出"AB__CD__"
Console.WriteLine(s.TrimEnd('_')); // 移除字符串中尾部的'_'字符,输出"__AB__CD"
Console.WriteLine(); //(8)插入和删除(Insert和Remove)
s = "ADEF";
Console.WriteLine(s.Insert(, "BC")); // 在字符串的第2位处插入字符串"BC",输出"ABCDEF"
Console.WriteLine(s);
Console.WriteLine(s.Remove()); // 从字符串的第2位开始到最后的字符都删除,输出"A"
Console.WriteLine(s);
Console.WriteLine(s.Remove(, )); // 从字符串的第1位开始删除2个字符,输出"EF"
Console.WriteLine(); //(9)替换字符(串)(Replace)
s = "A_B_C_D";
Console.WriteLine(s.Replace('_', '-')); // 把字符串中的'_'字符替换为'-',输出"A-B-C-D"
Console.WriteLine(s.Replace("_", "")); // 把字符串中的"_"替换为空字符串,输出"A B C D"
Console.WriteLine(); //(10)分割为字符串数组(Split)——互逆操作:联合一个字符串静态方法Join(seperator,arr[])
s = "AA,BB,CC,DD";
string[] arr1 = s.Split(','); // 以','字符对字符串进行分割,返回字符串数组
Console.WriteLine(arr1[]); // 输出"AA"
Console.WriteLine(arr1[]); // 输出"BB"
Console.WriteLine(arr1[]); // 输出"CC"
Console.WriteLine(arr1[]); // 输出"DD"
Console.WriteLine(); s = "AA--BB--CC--DD";
string[] arr2 = s.Replace("--", "-").Split('-'); // 以字符串进行分割的技巧:先把字符串"--"替换为单个字符"-",然后以'-'字符对字符串进行分割,返回字符串数组
Console.WriteLine(arr2[]); // 输出"AA"
Console.WriteLine(arr2[]); // 输出"BB"
Console.WriteLine(arr2[]); // 输出"CC"
Console.WriteLine(arr2[]); // 输出"DD"
Console.WriteLine(); //(11)格式化(静态方法Format)
Console.WriteLine(string.Format("{0} + {1} = {2}", , , + ));
Console.WriteLine(string.Format("{0} / {1} = {2:0.000}", , , 1.00 / 3.00));
Console.WriteLine(string.Format("{0:yyyy年MM月dd日}", DateTime.Now)); //(12)连接成一个字符串(静态方法Concat、静态方法Join和实例方法StringBuilder.Append)
s = "A,B,C,D";
string[] arr3 = s.Split(','); // arr = {"A","B","C","D"} Console.WriteLine(string.Concat(arr3)); // 将一个字符串数组连接成一个字符串,输出"ABCD" Console.WriteLine(string.Join(",", arr3)); // 以","作为分割符号将一个字符串数组连接成一个字符串,输出"A,B,C,D" StringBuilder sb = new StringBuilder(); // 声明一个字符串构造器实例
sb.Append("A"); // 使用字符串构造器连接字符串能获得更高的性能
sb.Append('B');
Console.WriteLine(sb.ToString());// 输出"AB"
String方法详解
11、Question:窗体控件较多时,重绘控件易引起窗体闪烁,重绘效率降低
Answer:通过使用控件的SuspendLayout()方法,可以将控件的布局暂时挂起,其后的代码中将会把子控件的Layout事件暂时挂起,只是把相应属性的值设置为新值,并不激发Layout事件,待调用ResumeLayout()方法后,再一起使子控件的Layout事件生效。当需要立即执行布局事件时,可以直接调用PerformLayout()方法。
在设置子控件的一些与外观、布局有关的属性时,比如Size、Location、Anchor或Dock等,会激发子控件的Control.Layout事件,并可能会引起窗口重绘。当子控件较多时,如果频繁设置上述属性(例如在窗体的初始化代码中),多个子控件的Layout事件会引起窗口重绘效率问题,比如闪烁。特别地,通过动态加载插件生成的UI对象特别多时,闪烁的情况就特别严重。此时,我们就要考虑上述解决办法。
12、Question:加密狗(SoftDog)的使用
Answer:程序启动时先判断加密狗的序列号,决定是否启动程序;启动后再通过定时器定期检查加密狗的序列号,若发现错误及时退出程序。
13、Question:串口编程
Answer:SerialPort组件
14、Question:多线程中,跨线程访问控件出错
Answer:将访问控件的代码封装成一个方法,再通过Invoke()调用其委托delegate。
15、Question:窗体全屏
Answer:代码如下所示:
private void fullScreen()
{
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
//this.WindowState = FormWindowState.Maximized; //屏幕分辨率
int nScreenWidth = Screen.PrimaryScreen.Bounds.Width;
int nScreenHeight = Screen.PrimaryScreen.Bounds.Height; int nWidthBorder = (this.Width - this.ClientRectangle.Width) / ;
int nHeightTitle = this.Height - this.ClientRectangle.Height - nWidthBorder; this.Left = -nWidthBorder;
this.Top = -nHeightTitle;
this.Width = nScreenWidth + nWidthBorder * ;
this.Height = nScreenHeight + nHeightTitle + nWidthBorder;
}
16、Question:焦点在其他控件上时,窗体接收不到按键消息
Answer:设置this.KeyPreview = true;(该值指示在将键事件传递到具有焦点的控件前,窗体是否将接收此键事件)
电梯多媒体相关链接:
ELCD_XXXM电梯多媒体显示器:http://www.embedtools.com/ADPlayer/