次中的lbl标签:编号、人数、姓名、性别、请输入而查询的音信,这里他们就由及了证实来意,所有命名一般为默认,只修改Text文本。
程序中之lbl标签:编号后面的0,他从至了同步表中选中人员之id(编号)
人数后的0,他的来意是时刻更新表中终究人数,他们的命名要规范,后面的代码才会编更有益于。
程序中的btn按钮:保存、重置、退出、添加、查询,要想实现他们的功效,就得双击他们接下来以中由及代码,才能够给他们功能,这里要留意按钮的命名规范。
程序运行时,在姓名TextBox文本框中、性别TextBox文本框中,分别输入人员之人名、性别,然后按照保存按钮,人员的音讯就受抱到了数据库被。
if (checkinput())
{
using (SqlConnection con = new SqlConnection(conStr))
{
con.Open();
string sql = "insert B(name,sex) values (@name,@sex)";
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.Add(new SqlParameter("@name", txtname.Text));
cmd.Parameters.Add(new SqlParameter("@sex", txtsex.Text));
int fh = cmd.ExecuteNonQuery();
if (fh > 0) MessageBox.Show("添加成功!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
sj();
rs();
}
}
此处调用了检测输入的完整性方法:checkinput,如果姓名TextBox文本框或性别TextBox文本框中,姓名没有输入,程序会提示请输入人名,性别从不输入,程序会提示请输入性。
private bool checkinput()
{
if (txtname.Text == null || txtname.Text == "")
{
MessageBox.Show("请输入姓名", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
txtname.Focus();
return false;
}
if (txtsex.Text == null || txtsex.Text == "")
{
MessageBox.Show("请输入性别", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
txtsex.Focus();
return false;
}
return true;
}
保留按钮的代码里还调用了,sj();rs();这简单单艺术,sj();这个主意从及了刷新长人员之音信到DGV表格中,rs();这个艺术从及了履新lbl人数标签后的数额功能,更新了总人数之多少信息。
消息输入完添加成,大家看人后的数字是:12,当自身仍确定今后,神奇之作业就是生出了!
人口后的数字12改成了13,这里就是是以保存按钮里调用了,rs();这个办法所以才发出更新数据的效益
private void rs()
{
using (SqlConnection con = new SqlConnection("server=.;uid=sa;pwd=sa;database=YG"))
{
con.Open();
string sql = "select count(*)from B";
SqlCommand cmd = new SqlCommand(sql, con);
object cx = cmd.ExecuteScalar();
//lblRS.Text = cx.ToString(); 将查询到的结果同步标签
lblrs.Text = cx.ToString(); //将查询到的结果同步到lbl标签
}
}
即时是因保存按钮代码里调用了,sj();这个法子,将新保存的人口信息更新至了DGV表格中。
private void sj()
{
SqlConnection con = new SqlConnection(conStr);//创建连接对象指定连接字符串
string sql = "select*from B";//sql查询语句
SqlDataAdapter cx = new SqlDataAdapter(sql, con);//连接数据库并执行sql语句
DataTable ta = new DataTable();//创建表对象
cx.Fill(ta);//将查询的内容填充到表对象
dataGridView1.DataSource = ta;//设置DGV表的数据来源
}
if (checkinput())//调用检测输入的完整性方法
{
using (SqlConnection con = new SqlConnection(conStr))//创建连接对象,指定连接字符串
{
con.Open();//打开连接
string sql = "insert B(name,sex) values (@name,@sex)";//SQL语句,在数据库里要执行的操作
SqlCommand cmd = new SqlCommand(sql, con);//Cmand命名对象执行操作
cmd.Parameters.Add(new SqlParameter("@name", txtname.Text));//指定参数跟对应的数据匹配
cmd.Parameters.Add(new SqlParameter("@sex", txtsex.Text));//指定参数跟对应的数据匹配
int fh = cmd.ExecuteNonQuery();//ExecuteNonQuery(),这个方法在执行增、删、改的时候就调用它
if (fh > 0) MessageBox.Show("添加成功!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
sj();//调用这个方法更新DGV表格中的数据
rs();//调用这个方法更行lbl总人数的数据
}
}
其一措施就回去查询结果集的率先行第一列
实行一个SQL语句,返回给影响之行数,这个办法要用以实践针对数据库执行长、修改、删除操作
询问多实施大多排
lblid.Text = "0";//lbl文本默认为0
txtname.Clear();//将Text文本框的内容清空
txtsex.Clear();//将Text文本框的内容清空
txtname.Focus();//设置焦点
输入好信息后,点击重置按钮就会见清空输入的音讯
Application.Exit();
点击退出后,程序就算见面叫关门。
添加人员 a = new 添加人员();//创建窗体对象
a.ShowDialog();//以对话框模式弹出
sj();//调用sj();这个方法来更新添加的人员数据到DGV表格中
这里丰富按钮的功力及保存按钮的功力是相近的,目的都是为了抬高人员数,只不过我们以此间举行了某些代码知识的扩张。
输入的消息不完整的讲话,会唤起请输入完的信息,这里为得写一个检测输入完整性的法,信息输入完后即使可点击保存了,保存按钮的代码和方面的接近,点击返回按钮后即窗体就见面关闭返回到人口管理主界面。
private void sj()
{
SqlConnection con = new SqlConnection(conStr);//创建连接对象指定连接字符串
string sql = "select*from B";//sql查询语句
SqlDataAdapter cx = new SqlDataAdapter(sql, con);//连接数据库并执行sql语句
DataTable ta = new DataTable();//创建表对象
cx.Fill(ta);//将查询的内容填充到表对象
dataGridView1.DataSource = ta;//设置DGV表的数据来源
}
其实是法在前面就是都冒出了了,当我们新增一个人口的当儿,就得调用sj();这个方式来更新DGV表格中的数额。
SqlConnection con = new SqlConnection(conStr);//创建连接对象指定连接字符串
//string sql = "select * from B where name like '%"+ txtcx.Text + "%'";
string sql = string.Format("select*from B where name like'%{0}%' or sex like'%{1}%' or id like'%{2}%'",txtcx.Text,txtcx.Text,txtcx.Text);//SQL语句根据TextBox输入的查询条件进行模糊查询
DataTable b1 = new DataTable();//创建表对象
SqlDataAdapter cx1 = new SqlDataAdapter(sql, con);//连接数据库并执行sql语句
cx1.Fill(b1);//将查询的内容填充到表对象
dataGridView1.DataSource = b1;//设置DGV表的数据来源
以TextBox文本框中,根据姓查询这里输入了一个:刘
DGV表格中即使会见显得所有姓刘的人员信息
以TextBox文本框中,根据性查询这里输入了一个:男
澳门新葡亰官网DGV表格中显示了具备性别也男性的信。
当此处我们得在DGV表格里加一个上下文菜单,来落实修改及去的意义。
添加人员 a = new 添加人员();//创建窗体对象
a.Text = "修改人员";//将添加人员的窗体Text文本修改为“修改人员”
a.Tag = dataGridView1.SelectedRows[0].Cells["id"].Value.ToString();//将选中的数据传递给修改人员窗体
a.txtname.Text = dataGridView1.SelectedRows[0].Cells["name"].Value.ToString();//DGV表中选中的人员名字传递到修改人员窗体
a.txtsex.Text = dataGridView1.SelectedRows[0].Cells["sex"].Value.ToString();///DGV表中选中的人员性别传递到修改人员窗体
a.ShowDialog();//以对话框模式弹出
修改人口的窗体与点击添加按钮弹来底窗体是暨一个窗体,这里只不过是因此代码修改了窗体的Text文本而已,DGV表中选中的多寡也一起到了修改人口窗体对应之Text文本框中,在此处我们特需要直接修改那些要改的地方即KO了。
if (checkinput())
{
if (this.Text == "添加人员")
{
using (SqlConnection con = new SqlConnection(conStr))
{
con.Open();
string sql = "insert B(name,sex) values (@name,@sex)";
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.Add(new SqlParameter("@name", txtname.Text));
cmd.Parameters.Add(new SqlParameter("@sex", txtsex.Text));
int fh = cmd.ExecuteNonQuery();
if (fh > 0) MessageBox.Show("添加成功!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
this.Close();
}
}
else
{
using (SqlConnection con = new SqlConnection(conStr))
{
con.Open();
//update<修改对象所在表> set < 修改对象 >=< 值 > where < 条件对象 >=< '条件内容' >
string sql = "update B set name=@name,sex=@sex where id=@id";
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.Add(new SqlParameter("@id", this.Tag.ToString()));
cmd.Parameters.Add(new SqlParameter("@name", txtname.Text));
cmd.Parameters.Add(new SqlParameter("@sex", txtsex.Text));
int fh = cmd.ExecuteNonQuery();
if (fh > 0) MessageBox.Show("修改成功!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
this.Close();
}
}
}
改人口中之保留按钮代码,跟点击添加按钮弹有之窗体中保留按钮代码一致,逻辑可能一时不便领悟,多扣几乎全方位就是熟能生巧了!
if (dataGridView1.SelectedRows.Count > 0)
{
string xz = dataGridView1.SelectedRows[0].Cells["id"].Value.ToString();
using (SqlConnection con = new SqlConnection(conStr))
{
con.Open();
string sql = string.Format("delete from B where id='{0}'", xz);
SqlCommand cmd = new SqlCommand(sql, con);
int fh = cmd.ExecuteNonQuery();
if (fh > 0)
{
MessageBox.Show("删除成功!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
sj();
rs();
}
else
{
MessageBox.Show("删除失败!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
sj();
rs();
}
}
追加、删、改、查,的代码流程都大致相同:首先创建连接对象指定连接字符串,打开连接、sql语句以数据库里要做呀操作(增、删、改、查)、然后创建Command命令对象连接数据库并履行sql语句,定义一个变量来接方的返值,增、删、改操作时,调用ExecuteNonQuer这个措施,查询操作时,一般调用的是ExcuteReader这个方式,要召开的操作不同,调用的方法吗会见不同,定义变量时也得定义匹配这个办法的变量。
经过十基本上上之不便奋战,MyKTV点歌系统终于成型,从正开收项目的未知,到成功项目时的高兴,整个经过的艰苦卓绝与付出只有协调知道.虽然是路还有为数不少需要全面的地方,譬如添加歌词信息,实现窗体的美化等,这些在继承时间里本身再次同如出一辙拓展一个到家吧!
率先为,我先拿整个项目所能促成之效益做一个简单的牵线,KTV点歌系统包括了前台和后台两那个组成部分,前台的功用就是是能够基于客户之急需来贯彻点歌操作,后台主要是管理员来补偿加歌手信息和演唱者信息
顿时是前台的主界面,通过主界面上的平多样操作,分别可进入相互呼应的界面
这是当自身播放歌曲后底主界面,添加曲后,主界面虽能显该歌手的图片信息,正在播放以及生一致首为会见显示相应的文书信息,并且,当自身切歌后,歌手图片以及文本框也能够就变动
当时是经过金榜排行上的界面,歌曲的排列顺序都是由此点击的次数降序排列
立马是项目点歌,当客户点击任意一个档次时还见面根据客户所挑选的类,到数据库中展开筛选,然后拿罗后底结果以歌曲列表中显示下
旋即是配数碰歌,其中每个字还是经代码动态变化的,如何转移将于末端写详细代码.当用户点击相应的篇幅时也会在数据库被展开筛,然后在歌曲列表中形出,大家可好明亮的感到到,歌曲列表这个窗体其实是几只力量块共用的一个窗体.
当时是拼音点歌,可以根据用户输入的拼音或者是歌曲名字进行模糊查询.
立马是既接触列表,这之中我加以了一个右键菜单,可以依据用户之要求来进行及时播放以及去
顿时是歌星点歌,这三摆设图其实不是三只窗体,而是一个窗体,只是用了三个listview控件,当自己得展示哪一个控件时就是用其它两独控件被隐蔽了.如何操作也以在背后通过代码进行详尽介绍.
说到底就虽是自我以主界面通过游戏添加的一个猜数小游戏.它能发出一个随机数,跟你输入的累累进行一个比,如果生了或是聊了还见面来照应的提示,直到你中后,又会显得你一共猜了有点坏,用户就好因你猜的次数的略微来进行对应的发落了.而且界面上的希冀是可动的,当程序运行起来后即使恍如一个小姑娘在当年过舞.
这些基本上就是是自总体前台所能落实的具有力量了,后台的口舌在后再和大家逐一展示了.
脚就是于大家展示一些互动呼应的代码了
平等:怎样实现无边框窗体的拖动
1 private Point mouseOffset; //记录鼠标指针的坐标
2 private bool isMouseDown = false; //记录鼠标按键是否按下
3 private void MainMenu_MouseDown(object sender, MouseEventArgs e)
4 {
5 int xOffset;
6 int yOffset;
7 if (e.Button == MouseButtons.Left)
8 {
9 xOffset = -e.X - SystemInformation.FrameBorderSize.Width;
10 yOffset = -e.Y - SystemInformation.CaptionHeight - SystemInformation.FrameBorderSize.Height;
11 mouseOffset = new Point(xOffset, yOffset);
12 isMouseDown = true;
13 }
14
15 }
16
17 private void MainMenu_MouseMove(object sender, MouseEventArgs e)
18 {
19 if (isMouseDown)
20 {
21 Point mousePos = Control.MousePosition;
22 mousePos.Offset(mouseOffset.X + 5, mouseOffset.Y + 30);
23 Location = mousePos;
24 }
25
26 }
27
28 private void MainMenu_MouseUp(object sender, MouseEventArgs e)
29 {
30 // 修改鼠标状态isMouseDown的值
31 // 确保只有鼠标左键按下并移动时,才移动窗体
32 if (e.Button == MouseButtons.Left)
33 {
34 isMouseDown = false;
35 }
36
37 }
每当窗体中找到彼此呼应之风波,然后copy代码便只是实现
其次:实现窗体抖动的代码
//实现窗体抖动的效果
Point first = this.Location;
for (int i = 0; i < 8; i++)
{
Random ran = new Random();
Point p = new Point(this.Location.X + ran.Next(20) - 4, this.Location.Y +
ran.Next(20) - 4);
System.Threading.Thread.Sleep(25);//当前线程挂起15毫秒
this.Location = p;
System.Threading.Thread.Sleep(25);//当前线程再挂起15毫秒
}
this.Location = first; //将窗体还原为原来的位置
全总KTV点歌系统受,我们要定义几独援类.
1:Help类
public class Help
{
public static string str = "data source=.;initial catalog=MyKTV;uid=sa;";
public static string ways = ""; //保存歌手图片路径
public static string songurl = ""; //保存歌曲路径
}
2:PlayBackStatus(播放状态类)
public enum PlayBackStatus
{
PlayBack, //已播
NotBroadcast, //未播
NowBroadcast, //正在播放
Repeat, //重播
baoji, //右键菜单的标记
Cut //切歌
}
3:Song(歌曲类)
public class song
{
public string SongName; //歌曲名称
public string SongURL; //歌曲存放路径
public PlayBackStatus playback; //歌曲播放状态
public string singerphotourl; //歌手图片路径
}
4:PlayList(播放列表类)
public class PlayList
{
public static song[] songlist = new song[100]; //定义一个歌曲数组
public static int SongIndex = 0; //当前播放歌曲在数组中的索引
public static string NextSongName = ""; //下一首歌曲
public static string zhuangtai = ""; //保存是切歌还是重播
//将歌曲增加到歌曲数组中去
public static bool AddSong(song song)
{
bool Result = false; //记录歌曲是否添加成功
for (int i = 0; i < songlist.Length;i++ )
{
if (songlist[i] == null)
{
songlist[i] = song;
Result = true;
break;
}
}
return Result;
}
//切歌
public static void CutSong()
{
//获取到当前播放的歌曲改变播放状态
if (songlist[SongIndex] != null)
{
songlist[SongIndex].playback = PlayBackStatus.Cut;
ChargeInde(); //改变歌曲索引,播放下一首
}
}
//重唱
public static void ListenAgain()
{
if (songlist[SongIndex] != null)
{
songlist[SongIndex].playback = PlayBackStatus.Repeat; //改变歌曲播放状态
}
}
//获取下一首歌曲的名称
public static string GetNextSongName()
{
if (songlist[0]!=null && songlist[SongIndex + 1] == null)
{
NextSongName = "待添加....";
return NextSongName;
}
else
{
if (songlist[0] != null)
{
NextSongName = songlist[SongIndex + 1].SongName;
return NextSongName;
}
else
{
return string.Empty;
}
}
}
//获得当前播放的歌曲
public static song GetPlaySong()
{
if (songlist[SongIndex] != null)
{
return songlist[SongIndex];
}
else
{
return null;
}
}
//播放下一首
public static void ChargeInde()
{
SongIndex++;
}
//点击重播时根据歌曲名称查找该歌曲在歌曲列表中的位置并改变其状态
public static void SelectFromSongName(string name)
{
for (int i = 0; i < songlist.Length;i++ )
{
if (songlist[i] != null)
{
if (songlist[i].SongName.Equals(name))
{
if (zhuangtai.Equals("重播"))
{
songlist[i].playback = PlayBackStatus.Repeat; //将该歌曲状态修改成重播
break;
}
else
{
if (songlist[i + 1] != null && songlist[i].playback == PlayBackStatus.NowBroadcast)
{
songlist[i].playback = PlayBackStatus.Cut; //将该歌曲状态修改成切歌
songlist[i + 1].playback = PlayBackStatus.NowBroadcast; //将下一首歌状态改成正在播放
}
else
{
MessageBox.Show("亲,最后一首歌曲和不是正在播放的歌曲不能切哟~~^_^");
}
break;
}
}
}
else
{
break;
}
}
}
public static bool isRight=false; //记录当isRight等于true时就播放选中歌曲
//点击已点列表中的播放时,根据歌曲名找到索引
public static void SelectIndexBySongName(string name)
{
for (int i = 0; i < songlist.Length; i++)
{
if (songlist[i] != null)
{
if (songlist[i].SongName.Equals(name))
{
songlist[i].playback = PlayBackStatus.baoji; //为选中歌曲做一个标记
songlist[SongIndex].playback=PlayBackStatus.PlayBack; //将当前播放歌曲改为已播状态
SongIndex = i; //将歌曲索引改变为所选中的歌曲
isRight = true;
break;
}
}
else
{
break;
}
}
}
//删除右键菜单选中的歌曲
public static bool delete(string name)
{
for (int i = 0; i < songlist.Length; i++)
{
if (songlist[i] != null)
{
if (songlist[i].SongName.Equals(name))
{
if (songlist[i].playback == PlayBackStatus.NowBroadcast)
{
return false;
}
while(true)
{
if (songlist[i + 1] != null)
{
songlist[i] = songlist[i + 1];
i++;
}
else
{
songlist[i] = null;
break;
}
}
for (int l = 0; l < songlist.Length;l++ )
{
if (songlist[l] != null)
{
if (songlist[l].playback == PlayBackStatus.NowBroadcast)
{
SongIndex = l;
}
}
}
}
}
else
{
break;
}
}
return true;
}
}
当我们将这些辅助类创建好以后,我们不怕足以起实现任何功能块的修了.
首先在相同进主界面的时候咱们就要保存歌手图片路径和歌曲路径
private void Form1_Load(object sender, EventArgs e)
{
//保存歌手图片前半部分路径
string sql = "select ways from Ways where id=1";
Help.ways = retunURL(sql);
//保存歌曲前半部分路径
string sql2 = "select ways from Ways where id=2";
Help.songurl = retunURL(sql2);
}
//返回前半部分路径的方法
public string retunURL(string sql)
{
SqlConnection con = new SqlConnection(Help.str);
con.Open();
SqlCommand com = new SqlCommand(sql, con);
string URL = com.ExecuteScalar().ToString();
con.Close();
return URL;
}
率先步成功后,我们就是可以上如歌星点歌界面,实现歌星图片的动态加载了,我们地方歌星点歌的图片被,第一摆放凡手动添加的,第二布置半动态增长的(也可是及第一摆同手动添加,在这边是为了熟练动态加载的代码),第三摆设是全动态增长的,手动添加的片就是,准备一个listview,imagelist
选择非常图标模式,直接上加图索引和Text文本即可,在此间才展示全动态加载时所形容的代码
第一步,在load事件备受显得第一单listview隐藏第二叔单listview
//Load事件
private void SingerStar_Load(object sender, EventArgs e)
{
//隐藏第二第三个窗体
listView2.Visible = false;
listView3.Visible = false;
}
其次步,当我点击第一个listview时保存所点的笔录之文书或Tag并出示第二独listview
public string singertype = ""; //保存用户选择的歌星类型(男,女,组合)
public int singerdistrictID; //保存用户选择的歌星地区的ID(香港...大陆...台湾.....)
public string singerdistrict; //保存用户选择的歌星地区(香港...大陆...台湾.....)
public int Number; //返回时更具Number的值来判断显示哪个控件,隐藏哪个控件
//从第一个控件跳转到第二个控件,第二个控件的文本和图像都是动态加载的
public void ShowListView2()
{
Number = 2;
if (listView1.SelectedItems[0] != null)
{
listView1.Visible = false; //隐藏第一个控件
listView2.Location = listView1.Location; //让两个控件出现的位置相同
listView2.Visible = true; //显示第二个控件
singertype = listView1.SelectedItems[0].Tag.ToString();
}
SqlConnection con = new SqlConnection(Help.str);
string sql = "select * from singer_type ";
SqlCommand com = new SqlCommand(sql, con);
listView2.Items.Clear(); //清空上次点击加载的数据
try
{
con.Open();
SqlDataReader read = com.ExecuteReader();
if (read != null)
{
if (read.HasRows)
{
int index = 0;
while (read.Read())
{
int TypeId = Convert.ToInt32(read["singertype_id"]);
string TypeName = read["singertype_name"].ToString();
ListViewItem list = new ListViewItem();
list.Text = TypeName;
list.Tag = TypeId;
list.ImageIndex = index;
listView2.Items.Add(list);
index++;
}
}
}
}
catch (Exception)
{
MessageBox.Show("网络错误!");
}
finally
{
con.Close();
}
}
老三步,保存第二只listview中用户所选取的记录,并且亮第三个listview
//从第二个控件跳转到第三个控件,第三个控件的歌星图片是从电脑硬盘上加载的
public void ShowListView3()
{
Number = 3;
if (listView2.SelectedItems[0] != null)
{
listView2.Visible = false; //隐藏第二个控件
listView3.Location = listView2.Location; //两个控件的出现位置相同
listView3.Visible = true; //第三个控件显示
singerdistrictID = Convert.ToInt32(listView2.SelectedItems[0].Tag); //获得用户点击的地区ID
singerdistrict = listView2.SelectedItems[0].Text; //获得用户点击的歌手地区
}
SqlConnection con = new SqlConnection(Help.str);
con.Open();
try
{
//查询符合用户选择的地区和歌手的类型的歌手名字
string sql = @"select singer_name ,siinger_photo_url from singer_info where singer_sex='"
+ singertype + "' and singertype_id=" + singerdistrictID + "";
SqlCommand com = new SqlCommand(sql,con);
SqlDataReader reader= com.ExecuteReader();
listView3.Items.Clear(); //清除上次点击加载的数据
imageList3.Images.Clear(); //清除imagelist中上一次保存的图片数据
if (reader != null)
{
if (reader.HasRows)
{
int index=0;
while (reader.Read())
{
string singerName = reader["singer_name"].ToString();
string singer_phone = reader["siinger_photo_url"].ToString(); //获得图片名字(后半部分路径)
string lujing = Help.ways + singer_phone; //获得图片完整路径
imageList3.Images.Add(Image.FromFile(lujing)); //通过完整路径将图片保存到imagelist3中
ListViewItem list = new ListViewItem();
list.ImageIndex = index;
list.Text = singerName;
listView3.Items.Add(list);
index++;
}
}
else
{
DialogResult result= MessageBox.Show("没有" + singerdistrict+"地区 " + singertype + "歌手信息!!!!","用户提示",MessageBoxButtons.YesNo,MessageBoxIcon.Information);
if (result == DialogResult.Yes)
{
fanhui();
}
}
}
}
catch (Exception)
{
MessageBox.Show("网络异常!!");
}
finally
{
con.Close();
}
}
这样虽可知以我们的老三单listview展示出来,并且会实现动态加载数据了,到这边然后我们不怕得依据用户率先涂鸦,第二涂鸦的条件来寻找数据库中之演唱者信息,当用户点击歌手信息之上就是得于歌列表中因歌手名字显示所有的歌信息了
//获取选中歌星的名字,并将其值传递给歌曲列表然后显示歌曲列表
private void listView3_Click(object sender, EventArgs e)
{
SongList song = new SongList();
song.SingerName = listView3.SelectedItems[0].Text;
song.singer = this;
song.Show();
this.Hide();
}
//这是在歌曲列表中定义的一个歌手名字信息,然后通过窗体传值实现
public string SingerName; //保存从歌星列表中传递过来要查询其歌曲信息的歌手的名字
string sql = @"select siinger_photo_url,song_name,singer_name , song_url from song_info,singer_info
where singer_info.singer_id=song_info.singer_id and singer_name='" + SingerName + "'";
//根据歌手的名字将用户选择的歌手信息展示在LIstView控件中
public void ShowUserByName(string sql)
{
dataGridView1.AutoGenerateColumns = false;
SqlConnection con = new SqlConnection(Help.str);
try
{
SqlDataAdapter da = new SqlDataAdapter(sql,con);
DataSet dt = new DataSet();
da.Fill(dt,"user");
dataGridView1.DataSource = dt.Tables["user"];
}
catch (Exception)
{
MessageBox.Show("网络异常!!");
}
finally
{
con.Close();
}
}
如此,我哪怕可由此歌曲列表中之曲信息来点歌了,当我每点击一首歌,我就算用所接触之歌唱多至自身先行定义好之Song类里面的歌数组当中去
//添加歌曲的方法
public void AddSong()
{
if (dataGridView1.SelectedRows[0].Cells[0].Value.ToString() != "")
{
song Song = new song();
Song.SongName = dataGridView1.SelectedRows[0].Cells["songname"].Value.ToString();
Song.SongURL = dataGridView1.SelectedRows[0].Cells["songurl"].Value.ToString();
Song.playback = PlayBackStatus.NotBroadcast;//播放状态为未播
Song.singerphotourl = dataGridView1.SelectedRows[0].Cells["siinger_photo_url"].Value.ToString(); //添加歌手图片路径
bool result = PlayList.AddSong(Song); //将歌曲增加到播放列表里面
if (result)
{
MessageBox.Show("添加成功!!");
AddSongCount(dataGridView1.SelectedRows[0].Cells["songname"].Value.ToString());
}
else
{
MessageBox.Show("添加失败!");
}
}
else
{
MessageBox.Show("请选择正确的歌曲名称!");
}
}
而且,为了促成金榜排行,用户每添加相同首歌,都于数据库中将歌曲的点击次数加1
//每次点击歌曲后都在数据库中将该歌曲的点击次数增加1
public void AddSongCount(string song_name)
{
SqlConnection con = new SqlConnection(Help.str);
string sql = "update song_info set song_play_count=song_play_count+1 where song_name='"+song_name+"'";
SqlCommand com = new SqlCommand(sql,con);
con.Open();
com.ExecuteNonQuery();
con.Close();
}
设当我们的歌曲数组中产生了曲后,我们尽管好进行歌曲的广播了,在播放器控件所在的界面(我的是主界面)就得透过获得到歌曲的一体化路径来播放歌曲
以动态的为pictureBox添加歌姬图片
public song CurrentSong; //定义当前播放歌曲
//获得当前播放的歌曲
public void PlaySong()
{
CurrentSong = PlayList.GetPlaySong();//事先定义的类里的方法
if (CurrentSong != null)
{
CurrentSong.playback = PlayBackStatus.NowBroadcast; //将歌曲改成正在播放状态
Player1.URL = Help.songurl + CurrentSong.SongURL; //获得歌曲的路径
singerimage.Image = Image.FromFile(Help.ways + CurrentSong.singerphotourl);
textBox1.Text = CurrentSong.SongName;
}
else
{
//给文本框赋值
textBox1.Text = "";
textBox2.Text = "";
}
}
为可以实现连续播放,并且会自动播放下同样首,我们得加一个计时器控件,每隔一秒扫描一浅歌曲信息,判断时吗空,如果也空则展开广播下同样首歌
public song NextSong; //定义下一首播放的歌曲
//获得下一首播放的歌曲名称
public void NextPlay()
{
textBox2.Text= PlayList.GetNextSongName(); //事先定义的类
}
private void timer1_Tick(object sender, EventArgs e)
{
NextPlay(); //获得下一首歌曲的名称
if (CurrentSong == null)
{
PlaySong();
}
if (Player1.playState == WMPLib.WMPPlayState.wmppsStopped) //判断歌曲的播放状态是否为快要停止也就是是否快要播放完
{
if(CurrentSong!=null)
{
CurrentSong.playback = PlayBackStatus.PlayBack; //将该歌曲状态改成已播放
}
CurrentSong = null;
PlayList.ChargeInde(); //Playlist中定义的方法
}
}
然就算基本实现了整套播放歌曲的通通经过了,并且你的歌曲数组中产生稍许歌曲都能够依次顺序播放,以上代码实现了何等通过歌星点歌进行歌曲的播音,但是连从未实现切歌和重唱的功用,
切歌和重唱功能是冲歌的状态,在计时器控件被来进展判定操作的,根据歌状态来施行相对应之点子澳门新葡亰官网(这是主界面的切歌和重唱)
//切歌
private void pictureBox2_Click(object sender, EventArgs e)
{
// PlayList.CutSong();
if (CurrentSong != null)
{
CurrentSong.playback = PlayBackStatus.Cut;
}
else
{
MessageBox.Show("亲~已经没歌了哦~~");
}
}
//重唱
private void lenago_Click(object sender, EventArgs e)
{
if (CurrentSong != null)
{
PlayList.ListenAgain();
}
else
{
MessageBox.Show("亲,还没歌呢~~");
}
}
//Tick事件
private void timer1_Tick(object sender, EventArgs e)
{
NextPlay(); //获得下一首歌曲的名称
if (CurrentSong == null)
{
PlaySong();
}
if (Player1.playState == WMPLib.WMPPlayState.wmppsStopped) //判断歌曲的播放状态是否为快要停止也就是是否快要播放完
{
if(CurrentSong!=null)
{
CurrentSong.playback = PlayBackStatus.PlayBack; //将该歌曲状态改成已播放
}
CurrentSong = null;
PlayList.ChargeInde(); //Playlist中定义的方法
}
if (CurrentSong != null)
{
if (CurrentSong.playback == PlayBackStatus.Repeat)
{
CurrentSong.playback = PlayBackStatus.PlayBack; //将歌曲改成已播放状态
PlaySong();
}
if (CurrentSong.playback == PlayBackStatus.baoji)
{
CurrentSong.playback = PlayBackStatus.NowBroadcast; //将歌曲改成正在播放状态
PlaySong();
}
if (PlayList.isRight) //判断是否播放选中歌曲
{
PlaySong();
PlayList.isRight = false;
}
if (CurrentSong.playback == PlayBackStatus.Cut)
{
PlayList.CutSong();
CurrentSong.playback = PlayBackStatus.PlayBack; //将歌曲改成播放状态
PlaySong();
}
}
}
在既接触列表中之切歌和重唱,还发相对应之右键菜单
//重唱
private void lenago_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count != 0)
{
PlayList.zhuangtai = "重播";
string SongName = listView1.SelectedItems[0].SubItems[0].Text;
PlayList.SelectFromSongName(SongName);
listView1.Items.Clear();
show();
}
else
{
MessageBox.Show("请选择一项歌曲!");
}
}
//切歌
private void pictureBox2_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count!= 0)
{
PlayList.zhuangtai = "切歌";
string SongName = listView1.SelectedItems[0].SubItems[0].Text;
PlayList.SelectFromSongName(SongName);
listView1.Items.Clear();
show();
}
else
{
MessageBox.Show("请选择一项歌曲!");
}
}
//右键菜单点击播放
private void 播放ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count != 0)
{
string SongName = listView1.SelectedItems[0].SubItems[0].Text;
PlayList.SelectIndexBySongName(SongName);
listView1.Items.Clear();
show();
}
}
//右键菜单删除
private void 删除ToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count != 0)
{
string SongName = listView1.SelectedItems[0].SubItems[0].Text;
if( PlayList.delete(SongName)==false)
{
MessageBox.Show("该歌曲正在播放,不能删除!");
}
listView1.Items.Clear();
show();
}
}
哪些动态产生字数沾歌
private void SelectSongFromWords_Load(object sender, EventArgs e)
{
for (int i = 0; i < 12;i++ )
{
ListViewItem li = new ListViewItem();
li.Text = (i + 1) + "个字";
li.Tag=(i+1);
listView1.Items.Add(li);
}
}
猜数小游戏相关代码
public int num = 0; //随机数
public int count = 0; //猜的次数
private void button1_Click(object sender, EventArgs e)
{
number.Clear();
Random r = new Random();
num = r.Next(1, 100); //返回0~100的整数,包含1不包含100
button2.Enabled = true;
}
private void button2_Click(object sender, EventArgs e)
{
if (Convert.ToInt32(number.Text) > num)
{
MessageBox.Show("大了点.再猜!");
count++;
}
else if (Convert.ToInt32(number.Text) < num)
{
MessageBox.Show("小了点,再猜!");
count++;
}
else
{
count++;
MessageBox.Show("恭喜你,猜中了!!!一共猜了" + count + "次");
}
}
到此时,前台就差不多是写了了,还有一些其它力量还死的简要,只是有sql语句的问题了,这里就是不一一展示了.
后台的话由岁月涉及,我虽不一一的显得界面图了,只将有首要代码做个亮
什么通过button按钮浏览本地资源管理器,并以图片展示暨控件被
public string Singer_photo_url; //保存歌手图片的后半部分路径
public string url; //歌手图片的绝对路径
//点击浏览按钮,添加图片
private void button3_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = " bgtr|*.jpg;*.png;*.gif"; //内部筛选符合条件的文件
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)//证明用户双击(选中了)一个文件,我就获取路径
{
//相对路径
Singer_photo_url = openFileDialog1.SafeFileName;
//绝对路径
url = openFileDialog1.FileName;
//给PictureBox的Image属性赋值
pictureBox1.Image = Image.FromFile(url);
MessageBox.Show("请选择正确的文件类型!");
Singer_photo_url = null;
}
}
争挑选文件夹目录
//浏览
private void btnselect_Click(object sender, EventArgs e)
{
DialogResult result = folderBrowserDialog1.ShowDialog();
if (result == DialogResult.OK)
{
txtNewURL.Text = folderBrowserDialog1.SelectedPath;
}
}
安划分文件及相应文件夹下
Directory.Delete(txtNewURL.Text); //删除事先存在的文件夹
Directory.Move(txtNowURL.Text, txtNewURL.Text); //将原文件夹中的内容剪切到新文件夹中
UpdateSongURl(); //将新路劲保存到数据库
什么样复制文件及指定文件夹下
// 移动歌手照片文件到指定的目录
if (!string.IsNullOrEmpty(SongURl))
{
if (url != Help.songurl + SongURl)
{
File.Copy(url, Help.songurl + "\\" + SongURl, true);
}
}
以上就是浑MyKTV的备代码了,因为自身是新专家第一不良写这好不容易比较老的型,所以产生描绘得不好的地方,和不能贯彻之作用,大家便展现谅哈~^_^.
当今,因为种种因素,你必须对一个央或措施开展频率上之访限制。
据,
你对外提供了一个API接口,注册用户每秒钟最多可调用100糟糕,非注册用户每秒钟最多足调用10涂鸦。
按照,
有一个颇吃服务器资源的计,在一如既往时刻不可知跨越10私家调用这个措施,否则服务器满载。
仍, 有局部奇异的页面,访客并无能够屡屡之造访还是发言。
以, 秒杀活动等展开。
论
,防范DDOS,当及一定频率后调用脚本iis服务器ip黑名单,防火墙黑名单。
万一齐种的比喻,也就是说,如何从一个断面的角度对调用的计开展频率上的克。而针对性效率限制,服务器层面都生极致直白的化解措施,现在自己说之虽是代码层面上的频率管控。
正文为闹点儿个示范,一个是基于单机环境之兑现,第二只则是冲分布式的Redis实现。
因为率先单API接口需求吗条例,先说生单机环境下的贯彻。
遵惯性思维,我们当然会想到缓存的逾期策略这种办法,但是严格来讲就是HttpRuntime.Cache而言,通过缓存的过策略来对要进行频率的出现控制是不合适的。
HttpRuntime.Cache
是应用程序级别之Asp.Net的缓存技术,通过这个技能好说明多只缓存对象,可以吗每个对象设置过时,当过时刻到达晚该缓存对象就是会见没有(也即是当您看该对象的当儿也Null)
为什么如此说啊?比如针对某个方法(方法名:GetUserList)我们若开展1秒钟最多10不善的限制,现在咱们尽管新建一个int型的Cache对象,然后设置1秒钟后过消失。那么以访问GetUserList方法前,我们便先判断这Cache对象的价是否超越10,如果超过10即不执行GetUserList方法,如果低于10尽管允许实施。每当访问该对象的时节要未在或者过就新建,这样循环,则该目标永远不可能逾10。
1 if ((int)HttpRuntime.Cache["GetUserListNum"] > 10) //大于10请求失败
2 {
3 Console.WriteLine("禁止请求");
4 }
5 else
6 {
7 HttpRuntime.Cache["GetUserListNum"] = (int)HttpRuntime.Cache["GetUserListNum"] + 1; //否则该缓存对象的值+1
8 Console.WriteLine("允许请求");
9 }
诸如此类的思考以及实现相对来说非常简单,但是依据这样的一个模型设定,那么就会现出这种状况:
设齐图,每个点代表一样不行走访请求,我在0秒的时节
新建了一个名字啊GetUserListNum的缓存对象。
在0~0.5秒中
我访问了3涂鸦,在0.5~1秒内,我们看了7不成。此时,该目标消失,然后我们跟着访问,该对象重置为0.
在第1~1.5秒里,还是看了7软,在第1.5秒~2秒之内做客了3浅。
冲这种简易缓存过期策略的范,在当时2秒钟内,我们虽然平均每秒钟都看了10不好,满足是规定,但是如果我们于中取一个以内段,0.5秒~1.5秒内,也是1秒钟,但是可实实在在的造访了14涂鸦!远远超了我们装的
1秒钟最多看10不成的 限制。
这就是说什么样科学的来解决地方的题材吗?我们可由此模拟对话级别的信号量即时等同招数,这吗便是咱今天之主题了。
什么是信号量?仅就因代码而言, static
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(5);
它的意就是象征于多线程情况下,在其余一样整日,只能以5个线程去访问。
本,在贯彻代码的事先我们事先规划一个型。
假设我们出一个用户A的管道,这个管道里装在用户A的要,比如用户A在一如既往秒钟发出了10破呼吁,那么每一个请求过来,管道里之要素都见面多一个。但是我们设定是管道最多只能容10个因素,而且每个元素的存活期为1秒,1秒后虽说该因素消失。那么这样设计吧,无论是速率还是多少之突进,都见面发出管道长度的限量。这样一来,无论由哪一个时节点还是时间距离出发,这个管道都能满足我们的频率限制需求。
假设这里的管道,就必须跟会话Id来对号入座了。每当发生新会话进来的时段就是很成一个新管道。这个会话id根据自己场景所定,可以是sessionId,可以是ip,也足以是token。
这就是说既是管道是碰头说话级别的,我们定得用一个容器,来装这些管道。现在,我们坐IP来命名会话管道,并把具有的管道还装在一个器皿被,如图
若果据悉刚才底设定,我们尚需对容器内的各国条管道的素进行处理,把过的吃删除掉,为这个,还待单独为该容器开辟有一个线程来吧各个条管道展开元素的清理。而当管道的因素呢0时,我们即便到底掉该管道,以便节省容器空间。
自然,由于用户量基本上,一个容器内或者有上万独管道,这个上偏偏用一个容器来装来清理,在效率达明显是不够的。这个时节,我们就算得对容器进行横向扩张了。
比如,我们得以根据Cpu核心数自动生成对应之数据之容器,然后根据一个算法,对IP来拓展导流。我当下cpu是4只逻辑核心,就不行成了4个容器,每当用户访问的时刻,都见面冠经过一个算法,这个算法会对IP进行处理,如192.168.1.11~192.168.1.13以此Ip段进第一个容器,xxx~xxx进第二只容器,依次类推,相应的,也尽管闹了4个线程去分别处理4个容器被的管道。
那么,最终便形成了咱们的4容器4线程模型了。
现行,着眼于编码实现:
首先我们用一个能够承载这些器皿的载体,这个载体类似于连接池的定义,可以根据部分索要自动生成适应数量的器皿,如果生特殊要求的言辞,还可以以容器上切出一个器皿管理的给,在线程上切出一个线程管理之照以便为实时监察及调度。如果的确使做这样一个网,那么
容器的调度 和 线程的调度功能
是必备的,而本Demo则是得了首要功能,像容器与线程在代码中本身啊绝非退开来,算法为是直接写好的,实际设计中,对算法的规划尚是可怜重大之,还有多线程模型中,怎样上锁才会于效率最大化为是根本的。
万一这里为了案例之直观就直接写很成4只容器。
public static List<Container> ContainerList = new List<Container>(); //容器载体
static Factory()
{
for (int i = 0; i < 4; i++)
{
ContainerList.Add(new Container(i)); //遍历4次 生成4个容器
}
foreach (var item in ContainerList)
{
item.Run(); //开启线程
}
}
而今,我们若 有编号也 0 到 40 这样的 41只用户。那么这个导流算法
我吧就算一直写深,编号0至9底用户
将他们之呼吁被丢转到第一单容器,编号10~19底用户
放到第二独容器,编号20~29推广至第三单容器,编号30~40底用户放第四只容器。
那么这个代码就是这般的:
static Container GetContainer(int userId, out int i) //获取容器的算法
{
if (0 <= userId && userId < 10) //编号0至9的用户 返回第一个容器 依次类推
{
i = 0;
return ContainerList[0];
}
if (10 <= userId && userId < 20)
{
i = 1;
return ContainerList[1];
}
if (20 <= userId && userId < 30)
{
i = 2;
return ContainerList[2];
}
i = 3;
return ContainerList[3];
}
当我们的对话请求经过算法的导流之后,都不能不调用一个方式,用于辨别管道数量。如果管道数量就超过10,则呼吁失败,否则成功
public static void Add(int userId)
{
if (GetContainer(userId, out int i).Add(userId))
Console.WriteLine("容器" + i + " 用户" + userId + " 发起请求");
else
Console.WriteLine("容器" + i + " 用户" + userId + " 被拦截");
}
连着下去便容器Container的代码了。
此处,对容器的选型用线程安全之ConcurrentDictionary类。
线程安全:当多个线程同时读写及一个共享元素的时候,就会现出数错乱,迭代报错等安全问提
ConcurrentDictionary:除了GetOrAdd方法而慎用外,是.Net4.0揽为解决Dictionary线程安全而出之初类型
ReaderWriterLockSlim:较ReaderWriterLock优化的读写锁,多单线程同时做客读锁
或 一个线程访问写锁
private ReaderWriterLockSlim obj = new ReaderWriterLockSlim(); //在每个容器中申明一个读写锁
public ConcurrentDictionary<string, ConcurrentList<DateTime>> dic = new ConcurrentDictionary<string, ConcurrentList<DateTime>>(); //创建该容器 dic
下一场当你向容器上加同条管道被之数额是经此法:
public bool Add(int userId)
{
obj.EnterReadLock();//挂读锁,允许多个线程同时写入该方法
try
{
ConcurrentList<DateTime> dtList = dic.GetOrAdd(userId.ToString(),t=>{ new ConcurrentList<DateTime>()}); //如果不存在就新建 ConcurrentList
return dtList.CounterAdd(10, DateTime.Now); //管道容量10,当临界管道容量后 返回false
}
finally
{
obj.ExitReadLock();
}
}
这里,为了当背后的线程遍历删除ConcurrentList的管道的时光保证ConcurrentList的安全性,所以这里设加读锁。
而ConcurrentList,因为.Net没有出List集合类的线程安全(此间我说明下:之所以不用ConcurrentBag是因只要保证count和add的一致性,这里补充一下),所以自己新建了一个蝉联给List<T>的平安种,在此间
封装了3独需要采用的办法。
public class ConcurrentList<T> : List<T>
{
private object obj = new object();
public bool CounterAdd(int num, T value)
{
lock (obj)
{
if (base.Count >= num)
return false;
else
base.Add(value);
return true;
}
}
public new bool Remove(T value)
{
lock (obj)
{
base.Remove(value);
return true;
}
}
public new T[] ToArray()
{
lock (obj)
{
return base.ToArray();
}
}
}
最后便是线程的运转方式:
public void Run()
{
ThreadPool.QueueUserWorkItem(c =>
{
while (true)
{
if (dic.Count > 0)
{
foreach (var item in dic.ToArray())
{
ConcurrentList<DateTime> list = item.Value;
foreach (DateTime dt in list.ToArray())
{
if (DateTime.Now.AddSeconds(-3) > dt)
{
list.Remove(dt);
Console.WriteLine("容器" + seat + " 已删除用户" + item.Key + "管道中的一条数据");
}
}
if (list.Count == 0)
{
obj.EnterWriteLock();
try
{
if (list.Count == 0)
{
if (dic.TryRemove(item.Key, out ConcurrentList<DateTime> i))
{ Console.WriteLine("容器" + seat + " 已清除用户" + item.Key + "的List管道"); }
}
}
finally
{
obj.ExitWriteLock();
}
}
}
}
else
{
Thread.Sleep(100);
}
}
}
);
}
终极,是法力图,一个是根据控制台的,还一个凡是依据Signalr的。
点介绍了同等种频率限制的范,分布式与单机相比,无非就是是载体不同,我们设把这个容器的载体从程序上移植出来,来弄成一个独门的劳务或者直接借用Redis也是实用之。
这边虽介绍分布式情况下,Redis的落实。
不等于Asp.Net的多线程模型,大概因为Redis的各种类型的素非常粒度的操作造成各种加锁之纷繁,所以当网要处理这块Redis是单线程的,基于Redis的贯彻则坐单线程的故在编码角度不用太多着想到和逻辑无关的题材。
简单介绍下,Redis是一个内存数据库,这个数据库属于非关系型数据库,它的概念不同让一般的我们体会的Mysql澳门新葡亰官网
Oracle
SqlServer关系型数据库,它并未Sql没有字段名没有表名这些概念,它和HttpRunTime.Cache的概念差不多一样,首先由操作上属于键值对模式,就使
Cache[“键名”]
这样就算会得到到价值类似,而且可针对每个Key设置过策略,而Redis中的Key所对应之值并无是怀念存啥就存啥的,它支持五种多少列:string(字符串),hash(哈希),list(列表),set(集合)及sorted
set(有序聚集)。
今日如果说之是Sorted
set有序聚集,有序聚集相比另的集聚类型的特别点在,使用有序聚集的时候还能吃插入的要素指定一个
积分score,我们将这个积分score理解啊破除序列,它里面会对积分进行排序,积分允许再,而有序聚集中之要素虽然是绝无仅有。
还是一样的思绪,每当发生用户访问的时候,都指向拖欠用户之
管道(有序聚集)中补充加一个因素,然后设置该因素的积分也当下光阴。接着在程序中开始个线程,来对管道被积分小于约定时间的因素进行清理。因为规定有序聚集中之元素只能是唯一值,所以当赋值方面只要是满足uuid即可。
那么因此Redis来兑现之代码那就算是类似这种:
透过using语法糖实现IDisposable而包的Redis分布式锁,然后中间正常的逻辑判断。
然的代码虽然为能够形成功能,但切莫敷自己。Redis是只依据内存的数据库,于性能而言,瓶颈在于网络
IO 上,与Get一不成发生同样次于呼吁相比,能无克经过一样段脚本来实现多数逻辑吗?
有的,Redis支持 Lua脚本:
Lua
是如出一辙种轻量小巧的脚本语言,用专业C语言编写并因为自代码形式开放,
其设计目的是为了放置应用程序中,从而为应用程序提供灵活的扩展和定制功能。
大致意思就是是,直接通往Redis发送一截脚本或者受它一直本地读取一段脚本从而直接实现有的逻辑。
/// <summary>
/// 如果 大于10(AccountNum) 就返回1 否则就增加一条集合中的元素 并返回 空
/// </summary>
/// <param name="zcardKey"></param>
/// <param name="score"></param>
/// <param name="zcardValue"></param>
/// <param name="AccountNum"></param>
/// <returns></returns>
public string LuaAddAccoundSorted(string zcardKey, double score, string zcardValue, int AccountNum)
{
string str = "local uu = redis.call('zcard',@zcardKey) if (uu >=tonumber(@AccountNum)) then return 1 else redis.call('zadd',@zcardKey,@score,@zcardValue) end";
var re = _instance.GetDatabase(_num).ScriptEvaluate(LuaScript.Prepare(str), new { zcardKey = zcardKey, score = score, zcardValue = zcardValue, AccountNum=AccountNum });
return re.ToString();
}
local
uu就是表明一个啊名uu的变量的意思,redis.call就是redis命令,这段脚本意思就是是一旦
大于10(AccountNum) 就返回1 否则就是加一长集合中之元素 并回到 空。
管道内元素处理的法门就是:
/// <summary>
/// 遍历当前所有前缀的有序集合,如果数量为0,那么就返回1 否则 就删除 满足最大分值条件区间的元素,如果该集合个数为0则消失
/// </summary>
/// <param name="zcardPrefix"></param>
/// <param name="score"></param>
/// <returns></returns>
public string LuaForeachRemove(string zcardPrefix, double score)
{
StringBuilder str = new StringBuilder();
str.Append("local uu = redis.call('keys',@zcardPrefix) "); //声明一个变量 去获取 模糊查询的结果集合
str.Append("if(#uu==0) then"); //如果集合长度=0
str.Append(" return 1 ");
str.Append("else ");
str.Append(" for i=1,#uu do "); //遍历
str.Append(" redis.call('ZREMRANGEBYSCORE',uu[i],0,@score) "); //删除从0 到 该score 积分区间的元素
str.Append(" if(redis.call('zcard',uu[i])==0) then "); //如果管道长度=0
str.Append(" redis.call('del',uu[i]) "); //删除
str.Append(" end ");
str.Append(" end ");
str.Append("end ");
var re = _instance.GetDatabase(_num).ScriptEvaluate(LuaScript.Prepare(str.ToString()), new { zcardPrefix = zcardPrefix + "*", score = score });
return re.ToString();
立马2段落代码通过发送Lua脚本的款型来形成了全部过程,因为Redis的网络型原因,所以管LuaForeachRemove方法为取出来开只服务来单独处理即可。至于那种多容器多线程的实现,则一心可初步多只Redis的实例来实现。最后放上效果图。
最终,我将这些都受做成了个Demo。但是没找到合适的上传网盘,所以大家可以留邮箱(留了便作),或者直接加QQ群文件自取,讨论交流:166843154
本身爱好跟本身同样的口交朋友,不吃环境影响,自己是投机之师资,欢迎加群
.Net web交流群, QQ群:166843154 欲望与挣扎
作者:小曾
出处:http://www.cnblogs.com/1996V/p/8127576.html 欢迎转载,但任何转载必须保留完整文章及博客园出处,在显要地方显示署名以及原文链接。
.Net交流群, QQ群:166843154 欲望与挣扎
多年来当开项目进度管理时,想透过设置net.sf.mpxj-for-csharp包读取.mpp格式文件,通过Nuget在线安装时,出现以下情形,无法安装,故被离线安装道路。
离线安装步骤如下:
平、下充斥而需要装之离线包nupkg文件,可以当Nuget官网下载:https://www.nuget.org/packages
仲、修改Nuget程序包源:VS>工具》选项》Nuget包管理器》程序包源,如图,将下载的nupkg文件放在C:\Program
Files (x86)\Microsoft SDKs\NuGetPackages\路径下:
老三、如下图,选择离线包源,左侧“浏览”选项卡下就可以看见,你一旦装的保管,点击安装即可。
网站部署的~阿里云系列汇总 http://www.cnblogs.com/dunitian/p/4958462.html
民用网站备案:http://www.cnblogs.com/dunitian/p/4958268.html
优先说企业的域名实名验证:一张图虽ok了
说下步骤,其实跟村办差不多,简单了下吧
1.填写主体信息
2.填写网站信息
3.臻传资料
说生盖章的此事物,个人的无视,PS一下就实施了,这个还是如打印盖章澳门新葡亰官网的
更何况下域名证书,到域名管理内部去,有只域名所有者,最下有下载证书之按钮(不是所有省都需的)
接下来便等候核审,一天后大多初审合格
初的确了了,进入下一阶段,幕布以前免费,下载收费(15初)
卿就算当你寄予快递即可
采购完幕布就相当于阿里邮吧,然后照上传即可
于广大之软件分类中,有几好像的软件不是特别重点,但也不行关键。它们多每隔一段时间需要实行有职责之软件,我们给其定时类软件;还有一样种软件是采网页遭到之数码,我们被它收集类软件。
以产品是任务管理器,包括上述2种植软件
一块服务,可以因安排好之时空距离执行任务。可以各隔一段时间,也得以以有时刻接触执行
集服务,可以搜集指定页面的数量,用于深数目解析。可因网址直接采访,也得可视化采集(如:淘宝被自之订单,就是需要报到才会收集)
.NET Framework 4.0
双击软件图标,打开登录页面,验证成功后弹有要图1-1所出示
图1-1
l 定时模块,任务类包括:间隔时间和时间接触
l 采集模块,支持可视化采集与非可视化采集
l 完善的日志模块帮助问题之定势以及缓解
倘定义好合项,这些共同项可保存至内存中,也堪储存于数据库中。用于定义有哪任务需要定时执行
如果达到图所示
1,
记录并项的开始与了结时,定时执行次数,还有配备起,如:间隔时间,时间点等
2, 最下的日志用于出口同步项之操作结果
凡负程序各间隔定时间,向系统管理员发送邮件。以通知管理员系统运行如常
凡是采集模块范围,下有些详细描述
图3-1
若达到图所示
1.
如约产品已经嵌入几单采访模板,如:博客园、糗事百科、淘宝网和1688(需登录后而视化采集)
2.
中选某个采集模板,点击:创建,相当给创造了之模板的一个实例(可同时创造多个)
如果达到图所示
点击开始后,实现数量收集
倘若可视化采集,点击:开始之时段,会自动弹来可视化采集页面(注:有的要报到)
l 取分页数:是因取得有略分页,如下图所示
l 采集当页:是指仅采集当前页数据,如下图所示
l 下一样页:是凭当前页采集完成后,直接沾:下同样页按钮,实现页面翻转
凡凭借登录的款户及密码,可径直复制。当然,需要超前安排好才行
征集是依用调试中之计,实现对持有页面的采集。步骤如下
a. 先抱有微分页
b. 循环从第1页开始征集
c. 时页采集成功后,再触发下一页按钮,采集第2页,直至所有页面都集完成
无可视化采集,还是未可视化采集。均已经实现组件化开发。如:采集页面就来一个,不同之募集模板,只需要传入不同的参数即可兑现
问:若360康宁警卫开启时,会弹出是否同意此程序运行,如图8-1所显示
图8-1
答:选择:一直允许运行(加入白名单)
问:可视化采集页面中之浏览器控件用之凡哪位?
报:可视化采集控件采用的是微信自带的WebBrowser控件,在Win7或Win10系统被,它需要修改注册,来保证使用的IE内核与系统的IE内核保持一致
本着随产品感兴趣的,可以加以我微信号(xiyang1011要13867408830)私聊
本人的博客即将搬运一头到腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan
1:做了图像展示的都知,我们的图纸大部分且是缩减了之,大部分呢JPEG PNG
BMP其中BMP格式是点阵形式,当图片翻译到内存之后凭杀没减了都见面化为BMP格式放上内存,在是进程遭到,图片数据会几倍的附加,就随JPEG,一摆1M尺寸的JPEG格式的图样,翻译到内存可能就是见面化7倍增左右,也即是7M会放在电脑内存里面,如果显示平摆100M的JPEG图片,放上内存的口舌也许就是见面变成1G,好了而是1G底图样为,你的电脑内存还够用啊,可以,兄弟你得说自己电脑配置很高
达到16G内存条,,如果自身要是给你展示同一摆设4G之图样也,注意压缩了的,翻译到内存将近28G,你说自家可购买一个28G之内存条,可以
,兄弟你大有钱,哈哈哈,,如果你莫要是这样,这篇稿子好无用看了,跪拜土豪。那要是,我不怕想用一个2G的外存条显示就张减少了还有4G底图样咋办,并且我还惦记死成当下张图也,就如,我因此显微镜拍一布置切片,或虽然一个资料的纹理结构,那么尽管可能一个片只来几乎个CM,但是显微镜人家分辨率高呀,看的仔细呀,用显微镜不纵想将图片放大个几千倍显嘛,好了,问题来了,这样显微照相机或要拍上千摆放图纸,最后拼接成一布置大图,然后在电脑上显示,所有医生得以以处理器面前指指点点,是免是殊便利,但是,同志,问题而来了,电脑内存不够,你为转变不了这般可怜之图,生成的进程吧是在电脑内存里面的,
好了,废话不多说了,看下的演示吧。
1:准备等同摆设54889×80315图片,当然不必然多人数会起诸如此类深之图片,因为未知晓这种技术吧,也没法生成这么可怜之图形。
如图:
当即张图片大小是54889×80315
这数据量大概发生多要命啊,我算了瞬间,大概是4.2041G,细心的网友或会见小心到,为什么来得的大小才发399M
呢,,哈哈哈,,这就算是任何一个技能了,想放的意中人等,会在延续之章中,解密。
2:现在若我们大家都生了当时张图片了,下面我们纪念展示这张图纸:首先,都见面想到的,我因此常规的浏览器试一下嘛,我们不怕先用微软从带的图纸浏览器,不要小瞧了之windows图片查看器,亲测,他大智能,也甚高效,千万不要以为他是单稍程序,有时候自己真可以打开我之图片,即使本人的图纸有我计划的特有之数据结构和减少形式,PS都不克开拓自己的图形,这家伙可以打开,所以当此自己要么那个钦佩这个图浏览器。
安,哈哈哈,电脑内存不足够吧,当然是浏览器还挂,也止是傻大粗的野蛮式显示就张图,当然内存不够用了。我于自我爱人8G内存的电脑上吧试试了,一样死机!!!显示都展示不了了,还谈什么产生就张图。
3:但是呢,我于是自己写的软件,就可打开就张图纸,当然之前我也知晓怎么产生就张图,这是一个完的流程;我之软件打开的功能是:
来平等摆放全局的图像效果:如下:
其实把图纸使劲缩小显示,图片的全局意义就是长成这样。其实效果跟而出示同一张小图没什么区别,流畅度,还有你得开标记,什么的,,,,这些还是多多益善别的浏览器都抱有的叠加功能,但是当这些附加功能实现过程也是怪痛苦的,为什么吧,就是因马上是一律布置超大图片,太好了,显示机制不同等,所以整传统艺术还得颠覆一下。
写的好辛苦,这个类型,做了有限年,就是以好这软件,整个经过为于痛苦,因为自己是形而上学出身,现在尚于该校朗诵研究生,写代码的水平赶不达专业出身,这项技艺整个完整流程,我打算慢慢写下去,从您哪产生同样张目前为止最可怜的图纸,让你图像拼接突破计算机限制,让您什么样展示出,如何运动,如何缩放,如何做标记等等,,太多了内容,,完整工程文件,包括编译好之库文件,我都发,压缩包解压就可以直接用,我于是WPF编写的,其实WPF就与C#差不多,其实他少凡是兄弟。代码数量超过好几万。可是花费了自吓特别的脑子。有趣味之对象可百度一晃Aperio,MOTIC这些公司,Aperio这个软件是暨外的表配套出售的,据说一高仪器好几百万,功能就是是发微镜扫描一个片,然后打开浏览切片,主要是便利医生进行切片检查,同时减轻医生的工作量,要明白,没有这个表的话,医生但要是为此眼一个个扣押片,成千上万的片这是要累够呛医生呀!!!眼睛瞅瞎!!!Aperio他们举行的扫视一布置切片就差一点秒,然后就输入到电脑,用软件显示出来,这个软件基本作用,也尽管是自家这软件之功效。。。。。。。
成套软件涉及到之技艺产生,TIFF图像技术,四叉树,虚拟显示技术,虚拟容器技术,内存映射文件技术,图像金字塔技术等等剩下的就是什么,做标记澳门新葡亰官网,XML文档管理,缩略图显示,UI布局等等
真的多。
起趣味之情侣可关注后续的篇章,有得之软件之可沟通自己,我的信箱nanshanyi@sjtu.edu.cn,可以协商。今天虽形容及马上。。。。。。
入坑.Net
也就有数年多了,既然在微软.Net 体系下混,对.Net
体系为需要了解一下,当然这些文化也都是查资料还能够查到的,这里根本是本着协调所法的盘整,况且最近之修有些闭门造车的含意,现在纪念写出来和大家大快朵颐一下,如果掌握有病,欢迎园友指正!
.Net
Framework经历了森本子的转,但是她的框架没有太怪的成形,包括了公共语言运行时(CLR)、基类库和.Net
Framework类库、公共语言专业与支撑的语言;
CLR是.Net Framework的底蕴内容,也是.Net程序的运转环境,可以以那看做一个在推行时管理代码的代办,它提供了内存管理、线程管理、代码执行、垃圾收集(GC)和长距离处理等基本服务,并且还强制实施严格的品种安全和可加强安全性以及可靠性的其它花样之代码准确性。
C#还是其它各种语言编写的源代码通过编译器生成IL代码托管(IL也如托管代码),最后取得一个托管模块,一个要多个托管模块组成程序集(assembly)交给CLR运行,但是CLR还是未能够一直和操作系统(OS)直接互动,还欲JIT引擎来开展“翻译”,变成计算机可以辨认的第二上前制代码交给操作系统执行。
对了这边涉及了CLR就不得不提到托管代码和非托管代码:
托管代码 (managed
code)是由CLR(而不是直由操作系统)执行的代码。托管代码应用程序可以赢得公共语言运行库服务,例如自动垃圾回收、运行库类型检查及安支持等。这些劳动帮扶提供单身为阳台和语言的、统一之托管代码应用程序行为。在托管执行环境遭受利用托管代码及其编译,可以避过多超人的致安全黑洞和无平静程序的编程错误。同样,许多无牢靠的计划也自动的为增长了安全
性,例如
类型安全检查,内存管理及释放无效对象。程序员可以花更多之精力关注程序的应用逻辑设计并可以减掉代码的编写量。这便表示又缺少的支出时间及更健壮的次序。
非托管代码 (unmanaged
code)是依赖于集体语言运行库环境的表,由操作系统直接执行之代码。非托管代码必须提供温馨的废物回收、类型检查、安全支持等服务;它同托管代码不同,后者自集体语言运行库中取得这些劳动。
基类库(NET Standard
Library)包含支持底层操作的平等多元通用功能,覆盖了集操作、线程支持、代码生成、输入输出(IO)、映射和安康等领域的内容。另外,.Net Core也是基类库的兑现,当然为发生温馨特有的贯彻,并且与.Net
Framework不同,它是支持过平台的,详细学习会在继承之博客中分享。
.Net Framework是基类库在windows操作系统下之兑现,包含类库:数据库访问(ADO
.NET等)、XML支持、目录服务(LDAP等)、正则表达式和信支持;并且还实现多咱开发人员平常使用的应用程序开发技术:ASP
.NET技术、WinFroms技术同WPF技术相当高档编程技术。
很遗憾,我本着立即公共语言专业(CLS)也无了解,也只能说说约。
.Net支持广大言语,有C#、VB等,每种语言必定带在温馨的表征,但是大家都能由此编译在CLR上面跑,并且还可以跟其它语言进行互操作,这都是盖所有语言都遵循了CLS;.NET
Framework将CLS定义为同一组规则,所有.NET语言都应该按照这规则才会创造同其它语言可彼此操作的应用程序,但要是专注的是为着使各级语言可以彼此操作,只能采取CLS所列有的成效对象,这些职能统称为跟CLS兼容的效益。再向下之底细实现就无懂得了,把这个邪排在此后之读计划当中吧。
本篇博客就描写及即吧,内容吗多是田园里内容,也期望能够协助及想称坑.Net的对象等。
日前新提升了Visual Studio
2017,创建的Web项目Bin目录中大多了一个受roslyn的公文夹,该文件夹导致网站以少数服务器上揭晓出错
自网上搜索了一下,Roslyn是初发生的动态编译工具
可于服务器上安装.net4.6后还提示编译出错。
解决方式:打开解决方案NuGet包管理器,卸载一个被“Microsoft.CodeDom.Providers.DotNetCom澳门新葡亰官网pilerPlatform”的保管,之后又编译网站,发现Bin目录下并未roslyn文件夹了!
大多重叠分组统计报表即按不同之数据字段,形成铺天盖地分组,并分割层级进行协商。
风土报表的兑现方式多基于
Table
控件,虽然只是实现多独分组功能,但每当表格显示上面来限定,只能呈现上下级的分组,而当代的错综复杂报表的求,通常是左右级嵌套,有时还要求一律内容之只元格合并,使用
Table
控件,有最多的局限,有矣矩表控件,通过简单的拖拽就会轻轻松松实现多叠分组报表,不管发生微个分组和分组小计都能够简单解决。
脚会通过一个实际的案例,使用葡萄城报表惨遭的矩表控件来讲学实现多层分组统计报表。
1.
行使矩表控件
2.
丰富多级嵌套行分组
3.
分组2上加小计,分组1续加总协议
4.
本时间字段进行列分组。
1.
新建RDL 报表模板
2.
增长数据源和数据集
3.
填补加矩表控件
长矩表控件后,会意识有近似 [ 符号,表示分组,即可根据现实数额动态生成行。会意识设计器下面的矩表分组管理器;
4.
表结构
4.1
添加行分组
而上述报表结构分析,行包含四级分组:
1.
Group1:=[生产方式];
2.
Group2:=[出品特性];
3.
Group3:=[所属事业部],小计;
4.
Group4:静态名称(静态列);
于是用丰富三级分组和一列静态列:
4.1.1
选中“行分组单元格”,右键单击,添加行分组——>子分组
4.1.2
添加三层分组
4.1.3
添加静态列
4.1.4
添加静态行:选中四层单元格,插入行——>分组内下方,执行三差
补充加动态列:本节报表结构相对简单,只发生一样实践“=【月】”字段的动态列,该列包含“=【周】”和本周小计。
4.2
添加列,子分组
表结构基本好,接下要举行的是绑定数据。
5.
绑定报表数量
将分组数据拖拽到
单元格,静态列数据只是选。
6.
集合单元格,输入列名称
7.
上加合计
加上【生产方式】合计:添加成功之后,需要活动合并单元格,调整Value值:
补加总协议:
添加“【周】”合计
填补加总协议:
8.
调体制
及这里,报表的整体布局都早就创造好了,需要开的尽管是调整报表样式。
运转效果
9.
总结一下
地方的步子虽然看起有些复杂,但假如真的主宰的矩表控件的法则,类似之复杂性多交汇分组报表只有需要几分钟就会做完了。
有关阅读:
【报表福利大放送】100余仿照报表模板免费下载
矩表 –
现代数据解析着必备的报表工具
矩表实现商品销售对比统计](http://www.cnblogs.com/powertoolsteam/p/pivot_table.html)
1、概念
1.0 线程的及进程的干及优缺点**
windows系统是一个大多线程的操作系统。一个顺序至少有一个经过,一个经过至少发生一个线程。进程是线程的容器,一个C#客户端程序开始吃一个独门的线程,CLR(公共语言运行库)为该过程创造了一个线程,该线程称为主线程。例如当我们创建一个C#控制台程序,程序的入口是Main()函数,Main()函数是初步为一个主线程的。它的功用要
是发新的线程和实行顺序。C#凡相同家支持多线程的编程语言,通过Thread类创建子线程,引入using
System.Threading命名空间。
基本上线程的长处:
1
2
|
1、 多线程可以提高CPU的利用率,因为当一个线程处于等待状态的时候,CPU会去执行另外的线程
2、 提高了CPU的利用率,就可以直接提高程序的整体执行速度
|
差不多线程的短:
1
2
3
|
1、线程开的越多,内存占用越大
2、协调和管理代码的难度加大,需要CPU时间跟踪线程
3、线程之间对资源的共享可能会产生可不遇知的问题
|
1.1 前台线程和后台线程
C#饱受的线程分为前台线程和后台线程,线程创建时莫做设置默认是前台线程。即线程属性IsBackground=false。
Thread.IsBackground = false;//false:设置为前台线程,系统默认为前台线程。
区别及如何利用:
这二者的区分就是:应用程序必须运行了所有的前台线程才可以退出;而对后台线程,应用程序则足以不考虑其是否业已运行了要直白退出,所有的后台线程在应用程序退出时还见面自动终止。一般后台线程用于拍卖时较短的任务,如在一个Web服务器遭到可采用后台线程来拍卖客户端发过来的请求信息。而前台线程一般用来拍卖得丰富日子等的职责,如以Web服务器中之监听客户端请求的次序。
线程是寄托于经过上的,进程都终止了,线程也不怕流失了!
一旦发生一个前台线程未脱离,进程不怕无见面停!即说的就算是程序不会见关闭!(即在资源管理器中得观看进程未终止。)
1.3 多线程的创办
下面的代码创建了一个子线程,作为次的入口mian()函数所当的线程即为主线程,我们通过Thread类来创造子线程,Thread类有 ThreadStart 和
ParameterizedThreadStart类型的嘱托参数,我们啊足以直接写方法的名字。线程执行之点子好传递参数(可选),参数的花色也object,写以Start()里。
class Program
{
//我们的控制台程序入口是main函数。它所在的线程即是主线程
static void Main(string[] args)
{
Thread thread = new Thread(ThreadMethod); //执行的必须是无返回值的方法
thread.Name = "子线程";
//thread.Start("王建"); //在此方法内传递参数,类型为object,发送和接收涉及到拆装箱操作
thread.Start();
Console.ReadKey();
}
public static void ThreadMethod(object parameter) //方法内可以有参数,也可以没有参数
{
Console.WriteLine("{0}开始执行。", Thread.CurrentThread.Name);
}
}
第一使new
Thread()创建有新的线程,然后调用Start方法教线程进入就绪状态,得到系统资源后即使推行,在推行进程中或者有等、休眠、死亡及堵塞四种植状态。正常履行完毕时间片后赶回回到就绪状态。如果调用Suspend方法会进去等状态,调用Sleep或者遇到进程同步使用的锁机制而眠等待。具体经过如下图所示:
2、线程的基本操作
线程和外常见的好像一样,有着许多性和措施,参考下表:
2.1 线程的相干属性
咱们得经上面表中的性能获取线程的一对系消息,下面是代码展示以及出口结果:
static void Main(string[] args)
{
Thread thread = new Thread(ThreadMethod); //执行的必须是无返回值的方法
thread.Name = "子线程";
thread.Start();
StringBuilder threadInfo = new StringBuilder();
threadInfo.Append(" 线程当前的执行状态: " + thread.IsAlive);
threadInfo.Append("\n 线程当前的名字: " + thread.Name);
threadInfo.Append("\n 线程当前的优先级: " + thread.Priority);
threadInfo.Append("\n 线程当前的状态: " + thread.ThreadState);
Console.Write(threadInfo);
Console.ReadKey();
}
public static void ThreadMethod(object parameter)
{
Console.WriteLine("{0}开始执行。", Thread.CurrentThread.Name);
}
输输出结果:
2.2 线程的相干操作
2.2.1 Abort()方法
Abort()方法用来住线程,调用此措施强制停止正在行之线程,它会丢来一个ThreadAbortException异常从而导致目标线程的平息。下面代码演示:
static void Main(string[] args)
{
Thread thread = new Thread(ThreadMethod); //执行的必须是无返回值的方法
thread.Name = "小A";
thread.Start();
Console.ReadKey();
}
public static void ThreadMethod(object parameter)
{
Console.WriteLine("我是:{0},我要终止了", Thread.CurrentThread.Name);
//开始终止线程
Thread.CurrentThread.Abort();
//下面的代码不会执行
for (int i = 0; i < 10; i++)
{
Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name,i);
}
}
行结果:和我们想象的相同,下面的轮回没有于实践
2.2.2 ResetAbort()方法
Abort方法好透过走来ThreadAbortException异常中止线程,而采取ResetAbort方法可撤销中止线程的操作,下面通过代码演示使用 ResetAbort方法。
static void Main(string[] args)
{
Thread thread = new Thread(ThreadMethod); //执行的必须是无返回值的方法
thread.Name = "小A";
thread.Start();
Console.ReadKey();
}
public static void ThreadMethod(object parameter)
{
try
{
Console.WriteLine("我是:{0},我要终止了", Thread.CurrentThread.Name);
//开始终止线程
Thread.CurrentThread.Abort();
}
catch(ThreadAbortException ex)
{
Console.WriteLine("我是:{0},我又恢复了", Thread.CurrentThread.Name);
//恢复被终止的线程
Thread.ResetAbort();
}
for (int i = 0; i < 10; i++)
{
Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name,i);
}
}
实践结果:
2.2.3 Sleep()方法
Sleep()方法调整就死线程,是时线程进入休眠状态,在蛰伏过程被据为己有系统外存但是休占系统时,当休眠期下,继续执行,声明如下:
public static void Sleep(TimeSpan timeout); //时间段
public static void Sleep(int millisecondsTimeout); //毫秒数
实例代码:
static void Main(string[] args)
{
Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadA.Name = "小A";
threadA.Start();
Console.ReadKey();
}
public static void ThreadMethod(object parameter)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name,i);
Thread.Sleep(300); //休眠300毫秒
}
}
将方的代码执行以后,可以清楚的看出每次循环中距离300毫秒的时。
2.2.4 join()方法
Join方法要是用来阻塞调用线程,直到有线程终止或通过了点名时间结束。官方的说明比较单调,通俗的说就是开创一个子线程,给其加了此主意,其它线程就会见搁浅实施,直到这个线程执行完毕为止才去执行(包括主线程)。她的计声明如下:
public void Join();
public bool Join(int millisecondsTimeout); //毫秒数
public bool Join(TimeSpan timeout); //时间段
为了求证点所说的,我们首先看一样段代码:
static void Main(string[] args)
{
Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadA.Name = "小A";
Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadB.Name = "小B";
threadA.Start();
//threadA.Join();
threadB.Start();
//threadB.Join();
for (int i = 0; i < 10; i++)
{
Console.WriteLine("我是:主线程,我循环{1}次", Thread.CurrentThread.Name, i);
Thread.Sleep(300); //休眠300毫秒
}
Console.ReadKey();
}
public static void ThreadMethod(object parameter)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name,i);
Thread.Sleep(300); //休眠300毫秒
}
}
为线程之间的实施是随便的,所有执行结果与我们想象的平等,杂乱无章!但是说明他们是以实行的。
现在咱们将代码中之
ThreadA.join()方法注释取消,首先程序中发出三个线程,ThreadA、ThreadB和主线程,首先主线程先阻塞,然后线程ThreadB阻塞,ThreadA先实施,执行了后ThreadB接着执行,最后才是主线程执行。
在押行结果:
2.2.5 Suspent()和Resume()方法
其实在C# 2.0后,
Suspent()和Resume()方法已不合时宜了。suspend()方法易出死锁。调用suspend()的当儿,目标线程会告一段落下来,但也还是有在即时之前获得的锁定。此时,其他任何线程都无可知顾锁定的资源,除非叫”挂于”的线程恢复运转。对另线程来说,如果它想重操旧业目标线程,同时还要准备利用另外一个锁定的资源,就会见促成死锁。所以无应用suspend()。
static void Main(string[] args)
{
Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadA.Name = "小A";
threadA.Start();
Thread.Sleep(3000); //休眠3000毫秒
threadA.Resume(); //继续执行已经挂起的线程
Console.ReadKey();
}
public static void ThreadMethod(object parameter)
{
Thread.CurrentThread.Suspend(); //挂起当前线程
for (int i = 0; i < 10; i++)
{
Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i);
}
}
执行方的代码。窗口并不曾立刻行
ThreadMethod方法输出循环数字,而是等了三秒钟后才输出,因为线程开始推行的时刻实施了Suspend()方法挂于。然后主线程休眠了3秒钟以后还要通过Resume()方法恢复了线程threadA。
2.2.6 线程的优先级
若果在应用程序中生出多单线程在运行,但局部线程比其它一些线程重要,这种气象下得以一个历程遭到也歧之线程指定不同的预先级。线程的预级可以通过Thread类Priority属性设置,Priority属性是一个ThreadPriority型枚举,列举了5独先行等级:AboveNormal、BelowNormal、Highest、Lowest、Normal。公共语言运行库默认是Normal类型的。见下图:
一直上代码来拘禁效果:
static void Main(string[] args)
{
Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadA.Name = "A";
Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadB.Name = "B";
threadA.Priority = ThreadPriority.Highest;
threadB.Priority = ThreadPriority.BelowNormal;
threadB.Start();
threadA.Start();
Thread.CurrentThread.Name = "C";
ThreadMethod(new object());
Console.ReadKey();
}
public static void ThreadMethod(object parameter)
{
for (int i = 0; i < 500; i++)
{
Console.Write(Thread.CurrentThread.Name);
}
}
推行结果:
面的代码中来三独线程,threadA,threadB和主线程,threadA优先级最高,threadB优先级最低。这等同碰从运行结果遭遇吗堪看到,线程B
偶尔会产出于主线程和线程A前面。当起多独线程同时处在可实行状态,系统优先执行优先级较高的线程,但这仅代表优先级较高的线程占有更多的CPU时间,并无表示早晚要先实行完毕优先级较高的线程,才会实施优先级较逊色的线程。
优先级更强意味着CPU分配为该线程的时间片越多,执行时纵差不多
先期级更没有表示CPU分配为该线程的日子片越少,执行时间虽丢掉
3、线程同步
什么是线程安全:
线程安全是负以当一个线程访问该类的某部数常常,进行保障,其他线程不可知开展走访直到该线程读取完,其他线程才不过下。不会见油然而生数未均等或数传。
线程有或同另外线程共享有资源,比如,内存,文件,数据库等。当多个线程同时读写及同份共享资源的时刻,可能会见引起冲突。这时候,我们要引入线程“同步”机制,即诸君线程之间要起个优先来后到,不可知同卷蜂挤上去抢作一团。线程同步的忠实意思和字面意思恰好相反。线程同步的实际意思,其实是“排队”:几单线程之间如果排队,一个一个对准共享资源进行操作,而非是以展开操作。
何以而落实同步啊,下面的例子我们用著名的单例模式以来吧。看代码
public class Singleton
{
private static Singleton instance;
private Singleton() //私有函数,防止实例
{
}
public static Singleton GetInstance()
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
单例模式就是是确保在普应用程序的生命周期中,在任何时刻,被指定的好像才生一个实例,并也客户程序提供一个落该实例的大局访问点。但地方代码来一个家喻户晓的问题,那便是使两个线程同时失去得到之目标实例,那。。。。。。。。
咱们帮代码进行修改:
public class Singleton
{
private static Singleton instance;
private static object obj=new object();
private Singleton() //私有化构造函数
{
}
public static Singleton GetInstance()
{
if(instance==null)
{
lock(obj) //通过Lock关键字实现同步
{
if(instance==null)
{
instance=new Singleton();
}
}
}
return instance;
}
}
通过改后的代码。加了一个
lock(obj)代码块。这样就会实现协同了,假如不是格外明亮的口舌,咱们看后继续教授~
3.0 使用Lock关键字贯彻线程同步
第一创建两个线程,两个线程执行和一个法,参考下面的代码:
static void Main(string[] args)
{
Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadA.Name = "王文建";
Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadB.Name = "生旭鹏";
threadA.Start();
threadB.Start();
Console.ReadKey();
}
public static void ThreadMethod(object parameter)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i);
Thread.Sleep(300);
}
}
行结果:
经过地方的推行结果,可以好明亮的观看,两只线程是于同时执行ThreadMethod这个艺术,这分明不抱我们线程同步的求。我们本着代码进行修改如下:
static void Main(string[] args)
{
Program pro = new Program();
Thread threadA = new Thread(pro.ThreadMethod); //执行的必须是无返回值的方法
threadA.Name = "王文建";
Thread threadB = new Thread(pro.ThreadMethod); //执行的必须是无返回值的方法
threadB.Name = "生旭鹏";
threadA.Start();
threadB.Start();
Console.ReadKey();
}
public void ThreadMethod(object parameter)
{
lock (this) //添加lock关键字
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i);
Thread.Sleep(300);
}
}
}
实践结果:
我们经过加加了 lock(this)
{…}代码,查看执行结果实现了俺们想只要之线程同步要求。但是我们明白this表示手上仿佛实例的本人,那么闹这样一种情形,我们管要拜访的办法所在的项目进行个别单实例A和B,线程A看实例A的主意ThreadMethod,线程B访问实例B的主意ThreadMethod,这样的话还会达到线程同步的要求也。
static void Main(string[] args)
{
Program pro1 = new Program();
Program pro2 = new Program();
Thread threadA = new Thread(pro1.ThreadMethod); //执行的必须是无返回值的方法
threadA.Name = "王文建";
Thread threadB = new Thread(pro2.ThreadMethod); //执行的必须是无返回值的方法
threadB.Name = "生旭鹏";
threadA.Start();
threadB.Start();
Console.ReadKey();
}
public void ThreadMethod(object parameter)
{
lock (this)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i);
Thread.Sleep(300);
}
}
}
推行结果:
俺们会意识,线程又从未实现同台了!lock(this)对于这种景象是可怜的!所以需要我们本着代码进行改动!修改后底代码如下:
private static object obj = new object();
static void Main(string[] args)
{
Program pro1 = new Program();
Program pro2 = new Program();
Thread threadA = new Thread(pro1.ThreadMethod); //执行的必须是无返回值的方法
threadA.Name = "王文建";
Thread threadB = new Thread(pro2.ThreadMethod); //执行的必须是无返回值的方法
threadB.Name = "生旭鹏";
threadA.Start();
threadB.Start();
Console.ReadKey();
}
public void ThreadMethod(object parameter)
{
lock (obj)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i);
Thread.Sleep(300);
}
}
}
由此翻看执行结果。会发觉代码实现了我们的需求。那么 lock(this)
和lock(Obj)有什么界别吧?
lock(this) 锁定 当前实例对象,如果有多个类实例的话,lock锁定的只是当前类实例,对其它类实例无影响。所有不推荐使用。
lock(typeof(Model))锁定的是model类的所有实例。
lock(obj)锁定的对象是全局的私有化静态变量。外部无法对该变量进行访问。
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
所以,lock的结果好不好,还是关键看锁的谁,如果外边能对这个谁进行修改,lock就失去了作用。所以一般情况下,使用私有的、静态的并且是只读的对象。
总结:
1、lock的凡必是援引类型的目标,string类型除外。
2、lock推荐的做法是以静态的、只念之、私有的靶子。
3、保证lock的目标在外部无法修改才发含义,如果lock的对象在表面改变了,对其它线程就会见通行,失去了lock的意思。
* 不可知锁定字符串,锁得字符串尤其危险,因为字符串被集体语言运行库
(CLR)“暂留”。
这表示任何程序中其他给定字符串都仅仅来一个实例,就是及时和一个目标表示了颇具运行的应用程序域的富有线程中的欠公文。因此,只要以应用程序进程遭到的其余职务处于具有同等内容之字符串上放置了锁,就拿锁定应用程序中该字符串的有着实例。通常,最好避免锁定
public
类型或锁定不被应用程序控制的目标实例。例如,如果该实例可以被公开访问,则
lock(this)
可能会见有问题,因为无吃控制的代码也可能会见锁定该目标。这可能致死锁,即有限独或还多只线程等待释放同一对象。出于同样的原由,锁定公共数据类型(相比于对象)也可能致问题。而且lock(this)只针对当前目标中,如果多单对象期间就达到不至一头的意义。lock(typeof(Class))与锁定字符串一样,范围最常见了。*
3.1 使用Monitor类实现线程同步
Lock关键字是Monitor的同样种植替换用法,lock于IL代码中会为翻成Monitor.
lock(obj)
{
//代码段
}
就同样于
Monitor.Enter(obj);
//代码段
Monitor.Exit(obj);
Monitor的常用属性与办法:
Enter(Object) 在指定对象及获排他锁。
Exit(Object) 释放指定对象及之解他锁。
Pulse 通知等队列中之线程锁定目标状态的改观。
PulseAll 通知所有的等待线程对象状态的改变。
TryEnter(Object) 试图获取指定对象的清除他锁。
TryEnter(Object,
Boolean) 尝试取指定对象及之排除他锁,并活动安装一个价,指示是否得到了该锁。
Wait(Object) 释放对象上之锁并阻止当前线程,直到她再取该锁。
常用之办法发生少数独,Monitor.Enter(object)方法是沾锁,Monitor.Exit(object)方法是释放锁,这即是Monitor最常用的点滴只法子,在运用过程被为避免获取锁之后为生,致锁无法自由,所以待以try{}
catch(){}之后的finally{}结构体中自由锁(Monitor.Exit())。
Enter(Object)的用法很粗略,看代码
static void Main(string[] args)
{
Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadA.Name = "A";
Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadB.Name = "B";
threadA.Start();
threadB.Start();
Thread.CurrentThread.Name = "C";
ThreadMethod();
Console.ReadKey();
}
static object obj = new object();
public static void ThreadMethod()
{
Monitor.Enter(obj); //Monitor.Enter(obj) 锁定对象
try
{
for (int i = 0; i < 500; i++)
{
Console.Write(Thread.CurrentThread.Name);
}
}
catch(Exception ex){ }
finally
{
Monitor.Exit(obj); //释放对象
}
}
TryEnter(Object)和TryEnter() 方法在尝试获得一个对象上之显式锁方面与
Enter()
方法类似。然而,它不像Enter()方法那样会堵塞执行。如果线程成功跻身重点区域那么TryEnter()方法会返回true. 和拟拿走指定对象的消异锁。看下代码演示:
我们可由此Monitor.TryEnter(monster,
1000),该方法吗能够避免死锁的发,我们下面的例证用到的凡欠法的重载,Monitor.TryEnter(Object,Int32),。
static void Main(string[] args)
{
Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadA.Name = "A";
Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法
threadB.Name = "B";
threadA.Start();
threadB.Start();
Thread.CurrentThread.Name = "C";
ThreadMethod();
Console.ReadKey();
}
static object obj = new object();
public static void ThreadMethod()
{
bool flag = Monitor.TryEnter(obj, 1000); //设置1S的超时时间,如果在1S之内没有获得同步锁,则返回false
//上面的代码设置了锁定超时时间为1秒,也就是说,在1秒中后,
//lockObj还未被解锁,TryEntry方法就会返回false,如果在1秒之内,lockObj被解锁,TryEntry返回true。我们可以使用这种方法来避免死锁
try
{
if (flag)
{
for (int i = 0; i < 500; i++)
{
Console.Write(Thread.CurrentThread.Name);
}
}
}
catch(Exception ex)
{
}
finally
{
if (flag)
Monitor.Exit(obj);
}
}
Monitor.Wait和Monitor()Pause()
Wait(object)方法:释放对象及之锁并阻止当前线程,直到她再次得到该锁,该线程进入待队列。
Pulse方法:只有锁之目前主人可以运用 Pulse 向等待对象发出信号,当前有着指定对象及之沿的线程调用此方法以便向行中之生一个线程发出锁的信号。接收及脉冲后,等待线程就给挪动到就是绪队列中。在调用 Pulse 的线程释放锁后,就绪队列中之产一个线程(不必然是收到脉冲的线程)将得到该锁。
另外:
Wait 和 Pulse 方法必须写在 Monitor.Enter
和Moniter.Exit 之间。
点是MSDN的分解。不明白看代码:
首先我们定义一个攻击类,
/// <summary>
/// 怪物类
/// </summary>
internal class Monster
{
public int Blood { get; set; }
public Monster(int blood)
{
this.Blood = blood;
Console.WriteLine("我是怪物,我有{0}滴血",blood);
}
}
下一场于概念一个攻击类
/// <summary>
/// 攻击类
/// </summary>
internal class Play
{
/// <summary>
/// 攻击者名字
/// </summary>
public string Name { get; set; }
/// <summary>
/// 攻击力
/// </summary>
public int Power{ get; set; }
/// <summary>
/// 法术攻击
/// </summary>
public void magicExecute(object monster)
{
Monster m = monster as Monster;
Monitor.Enter(monster);
while (m.Blood>0)
{
Monitor.Wait(monster);
Console.WriteLine("当前英雄:{0},正在使用法术攻击打击怪物", this.Name);
if(m.Blood>= Power)
{
m.Blood -= Power;
}
else
{
m.Blood = 0;
}
Thread.Sleep(300);
Console.WriteLine("怪物的血量还剩下{0}", m.Blood);
Monitor.PulseAll(monster);
}
Monitor.Exit(monster);
}
/// <summary>
/// 物理攻击
/// </summary>
/// <param name="monster"></param>
public void physicsExecute(object monster)
{
Monster m = monster as Monster;
Monitor.Enter(monster);
while (m.Blood > 0)
{
Monitor.PulseAll(monster);
if (Monitor.Wait(monster, 1000)) //非常关键的一句代码
{
Console.WriteLine("当前英雄:{0},正在使用物理攻击打击怪物", this.Name);
if (m.Blood >= Power)
{
m.Blood -= Power;
}
else
{
m.Blood = 0;
}
Thread.Sleep(300);
Console.WriteLine("怪物的血量还剩下{0}", m.Blood);
}
}
Monitor.Exit(monster);
}
}
履代码:
static void Main(string[] args)
{
//怪物类
Monster monster = new Monster(1000);
//物理攻击类
Play play1 = new Play() { Name = "无敌剑圣", Power = 100 };
//魔法攻击类
Play play2 = new Play() { Name = "流浪法师", Power = 120 };
Thread thread_first = new Thread(play1.physicsExecute); //物理攻击线程
Thread thread_second = new Thread(play2.magicExecute); //魔法攻击线程
thread_first.Start(monster);
thread_second.Start(monster);
Console.ReadKey();
}
输出结果:
总结:
首先栽情景:
亚种状况:thread_second首先得同锁对象,首先实施到Monitor.PulseAll(monster),因为程序中尚无用等信号进入就绪状态的线程,所以就无异词代码没有意思,当行及 Monitor.Wait(monster,
1000),自动将协调放逐到等候队列并于这边阻塞,1S
时间后thread_second自动添加至妥善队列,线程thread_first获得monster对象锁,执行及Monitor.Wait(monster);时发出短路释放并对象锁,线程thread_second执行,执行Monitor.PulseAll(monster)时通知thread_first。于是以开率先栽情况…
Monitor.Wait是给眼前经过睡眠在薄资源上连释放独占锁,它只是等待,并无脱离,当等了,就要继续执行剩下的代码。
3.0 使用Mutex类实现线程同步
Mutex的凸起特征是足以超越应用程序域边界对资源开展垄断访问,即好用来共同不同进程面临的线程,这种功效自然这是盖献身更多的系统资源为代价的。
主要常用之有限只法子:
public virtual bool WaitOne() 阻止当前线程,直到当前
System.Threading.WaitHandle 收到信号获取互斥锁。
public void ReleaseMutex() 释放 System.Threading.Mutex 一次。
使用实例:
static void Main(string[] args)
{
Thread[] thread = new Thread[3];
for (int i = 0; i < 3; i++)
{
thread[i] = new Thread(ThreadMethod1);
thread[i].Name = i.ToString();
}
for (int i = 0; i < 3; i++)
{
thread[i].Start();
}
Console.ReadKey();
}
public static void ThreadMethod1(object val)
{
mutet.WaitOne(); //获取锁
for (int i = 0; i < 500; i++)
{
Console.Write(Thread.CurrentThread.Name);
}
mutet.ReleaseMutex(); //释放锁
}
2、线程池
上面介绍了介绍了平时应用的多数的多线程的事例,但于实际支出中应用的线程往往是大度底与进一步复杂的,这时,每次都创造线程、启动线程。从性质上来讲,这样做并无优秀(因为各个使用一个线程就要创建一个,需要占用系统出);从操作上来讲,每次都设启动,比较费心。为之引入的线程池的定义。
好处:
1.减在开创与销毁线程上所花费的辰及系统资源的开销
2.比方不使用线程池,有或引致系统创造大气线程而招致消耗了系统内存和”过度切换”。
以什么状态下使用线程池?
1.单个任务处理的光阴较短
2.亟待处理的职责之数码大
线程池最多管理线程数量=“处理器数 *
250”。也就是说,如果您的机也2个2核CPU,那么CLR线程池的容量默认上限便是1000
经线程池创建的线程默认为后台线程,优先级默认为Normal。
代码示例:
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod1), new object()); //参数可选
Console.ReadKey();
}
public static void ThreadMethod1(object val)
{
for (int i = 0; i <= 500000000; i++)
{
if (i % 1000000 == 0)
{
Console.Write(Thread.CurrentThread.Name);
}
}
}
关于线程池的诠释请参见:
http://www.cnblogs.com/JeffreyZhao/archive/2009/07/22/thread-pool-1-the-goal-and-the-clr-thread-pool.html
大的老二维数据透视表(交叉表)通过横向和纵向展示数据,进行有简的集中运算,而传统的数目透视表功能单一,汇总方式大概,已经无力回天满足现代够呛数据量各种条件分析,因此多维透视表应运而生。
差不多维透视表在功能强大的同时,创建难度也会跟着提高
多叠分组嵌套的复杂性的团组织结构
复杂的汇集分析公式的编制
小计和共的分等等要面临的扑朔迷离问题
假使因此代码实现,可能复杂程度不堪想象,更不要提好数据量级别下表加载的属性问题。而使用现有的简便报表工具,功能单一无法对这无异于表征来满足复杂透视表的创立效能。
矩表控件能够满足多维透视表创建的错综复杂功能。本文为【商品销售额和送金额比重】这无异名列前茅的多维透视表为示例,使用葡萄城报表的矩表控件,通过拖拽来贯彻多维透视表。
行:
按照区域与省,嵌套2层分组。
列:按照月分组,动态列。
1.
下矩表控件
2.
加加2级行分组,首先以区域分组,其次按照省分组
3.
按部就班省进行小计;
4.
列应用“月份”分组,分组下面嵌套三列。
1.
新建报表模板
2.
丰富数据源和数据集
3.
上加矩表控件
长矩表控件到规划界面,会发觉来接近[
符号,表示分组,即可根据具体多少动态生成行。会发觉设计器下面的矩表分组管理器;
4.
填补加行分组
入选,行分组单元格,右击添加行分组,选择“子分组”
5.
补给加列分组
据悉上述剖析,列分组是根据月而定的,因此就待默认的一个列分组就够用了,所以未欲添加任何列分组;
添加“销售额”,“搭增”,“比例”静态列:
入选“列分组单元格”插入列,选择分组内-右侧,添加三列;
增长完成以后,插入行,选择分组内-下方;
6.
添加“总合计”列;
入选列分组单元格,插入列(三列),选择分组外—右侧
7.
绑定数据字段
发明结构都基本做到,接下便绑定数据字段;
1.
填补加行分组数据,首先从表资源管理器中甄选“区域”字段,拖拽到实施分组单元格;
2.
迁延拽“省份”字段及 子分组单元格;
3.
蘑菇拽“月份”字段及 列分组单元格;
作用使图:
8.
补加其余字段
不过经选中单元格,右上之字段logo来选择相应之数额字段:
9.
添加省份合计
当选:省份单元格,选择上加合计->分组后面;会自动添加合计行;
效果图:
10.
修改样式
报表设计虽做到了,接下去需要举行的就算是调整报表样式。
功能预览
转载请注明来源:葡萄城报表
连锁阅读:
【报表福利大放送】100不必要法报表模板免费下载
开放才能够提高!Angular和Wijmo一起走过的光阴
2017年前端框架、类库、工具十分比并
WCF(Windows Communication
Foundation)是由于微软开之一样密密麻麻支持数据通信的应用程序框架,可以翻为Windows通信开发平台
WCF整合了老的Windows通信的.net Remoting
,WebService,Socket机制,并融合有HTTP和FTP的系技能。WCF是指向这些技术的联合。
WCF的优点
统一性
互操作性
安全以及可凭借
兼容性
明白面向服务
SOA(Service Oriented Atchitecture)面向服务架构
。是恃以化解在Internel环境下业务集成的消,通过连接能够做到一定任务的单身功能实体实现之平等栽软件系统架构。SOA是一个零件模型,将应用程序的异功能单元(称为服务)通过这些劳务中间定义美的接口及契约关系起来
SOA指出目前系统应足够灵活,从而允许在无打乱当前打响运行的系布局与基本功结构前提下,改动已经有的体系布局。
SOA有如下原则
边界清楚
服务自治
兼容性基于政策
共享模式(schema)和契约
WCF框架组成
1.协定(契约)
契约来定义双方关系的协商,契约必须为接口的章程来反映,而实际上的服务代码必须要由这些契约接口派生并促成,
契约可分为以下4种:
1.数契约(Data
Contract):指定双方联系时之数码格式
2.劳务契约(Service Contract):指定服务之定义
3.操作契约(Opration Contract):指定服务提供的办法
4.信契约(MessageContract):指定在通信期间改写信息内容的正式
契约定义消息网的各个方面
(1).数据契约:服务中的参数
(2).消息契约:使用SOAP协议一定的音部分
(3).服务契约:服务中之不二法门
(4).策略与绑定:策略设置安全还是其它条件,绑定指定传输方式与编码。
2.劳务运作
服务运行期间的表现控制
(1).限制行为:控制处理的消息数
(2).错误行为:出现其中错误时所处理的操作
(3).元数据表现:是否为他提供元数据及元数据的供方式
(4).实例行为:可运行的劳务实例数目
(5).事务行为:处理事务
(6).调度行为:控制WCF处理消息之点子
3.消息传递
消息传递层说明数据的交换格式和导模式。消息传递层由通道(信道)组成,通道是对信息进行处理的零件,负责为同等的计对信息进行整及传递。通道用于传输层,协议层及信息得到。各层次之坦途组成了信道栈
通道对信息和消息头进行操作,服务运行时对信息正文进行操作。通道包括个别种植类型:传输通道以及磋商通道。
传输通道:读取和描写副来自网络的音,传输通道通过编码器将消息转换为网络传输使用的字节流以及用字节流转换为信息。传输通道包括HTTP通道,命名管道,TCP,MSMQ等
协议通道:通过读取或写副消息头的方法来实现信息协议。比如
WS-Security。WS-Reliability
4.宿主与激活
服务宿主负责WCF服务的生命周期和上下文的操作系统进程,负责启动暨已WCF服务,并提供控制服务的核心管理功能。
WCF的根底概念
1.地址
2.绑定(Binding)
3.契约(Contract)
4.终结点
用来发送或收受信息(或实施就简单种操作)的结构,终结点包含一个定义消息可以发送在的目的地位置节点,包含一个定义消息可以发送至之目的地位置(地址),一个叙述消息应怎样发送的通信机制规范(绑定)以及对可以当该岗位发送或收取(或双方都可)的平组消息的定义(服务协定)—该定义还描述了足发送何种消息
终结点的地方由EndpointAddress类表示,该类包含一个象征服务地址额统一资源一定符(URI),大多数传的地址URI包含4组成部分。
例:https://home.cnblogs.com/u/1147658/
方案:https
计算机:home.cnblogs.com
端口(可选):
路径:u/147658
5.元数据
6.宿主(Host)
NanUI据悉ChromiumFX项目进展付出,它会吃你当你的Winform应用程序中行使HTML5/CSS3/Javascript等网页技术来显现用户界面(类似Electron)。同时NanUI提供了原生窗口与定制化的无标题栏无边框窗口,你会利用任何底网页技术来计划和呈现你的应用程序界面。
NanUI基给MIT协议,所以无你下NanUI来开发商业类型或者开源、免费项目都用非让另限制,只需要遵循协议文本遇规定之,在你的软件中声称使用了NanUI技术即可。
乃可以经GitHub获取NanUI的源码以及示例代码,稳定版的NanUI包通过Nuget进行分发。NanUI支持.NET4.0/4.5/4.6/4.7及创新版本的Windows窗体应用。
取源码
git clone https://github.com/NetDimension/NanUI.git
Nuget包管理器
正规版(CEF 3.2987.1601.gf035232 / Chromium 57.0.2987.133)
PM> Install-Package NetDimension.NanUI
WindowXP版本(CEF 3.2526.1366.g8617e7c / Chromium 47.0.2526.80)
PM> Install-Package NetDimension.NanUI.XP
引进下Nuget包管理器安装NanUI程序集将自动安装相应的CEF依赖项,一键安装方便使用。
编译当前版本的NanUI需要支持C#7.0语法的编译器,推荐的编译工具有且只来Visual
Studio 2017。
初始化NanUI
namespace TestApplication
{
using NetDimension.NanUI;
static class Program
{
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//初始化CEF: 设置CEF的相关Path
//如果要使用Nuget自动下载的fx文件夹结构,需要手动指定各个文件夹的路径
var result = Bootstrap.Load(PlatformArch.Auto, System.IO.Path.Combine(Application.StartupPath, "fx"), System.IO.Path.Combine(Application.StartupPath, "fx\\Resources"), System.IO.Path.Combine(Application.StartupPath, "fx\\Resources\\locales"));
if (result)
{
// Load embedded html/css resources in assembly.
Bootstrap.RegisterAssemblyResources(System.Reflection.Assembly.GetExecutingAssembly());
Application.Run(new Form1());
Application.Exit();
}
}
}
}
采取原生的窗口样式来行使NanUI
namespace TestApplication
{
public partial class Form1 : Formium
{
public Form1()
//Load embedded resource index.html and not set form to no border style by the second parameter.
: base("http://res.app.local/index.html", false)
{
InitializeComponent();
}
}
}
使用无边框模式来运NanUI
namespace TestApplication
{
public partial class Form1 : Formium
{
public Form1()
//Load embedded resource index.html and set form to no border style by igrone the second parameter or set it to true.
: base("http://res.app.local/index.html")
{
InitializeComponent();
}
}
}
请注意:倘利用Visual Studio
2015或者又低之版开发暨调剂NanUI应用程序,需要在路性质的调试选项卡着关闭“启用VS承载进程”选项,否则调试时将出现页面不加载白屏的景况。如图所示:
GitHub
https://github.com/NetDimension/NanUI/
交流群QQ群
521854872
扶植作者
设若你喜欢自己的工作,并且期望NanUI持续的前进,请对NanUI项目开展补助为之来鼓励与支撑自己连续NanUI的开支工作。你得运用微信或者支付宝来围观下的亚维码进行资助。
于第一首的功底及,本文主要讲解基于EntityFramework 及SqlServer2012
实现核心的CRUD功能。
开创一个录入Form,用来管理UserAccount数据。
1.每当列文件及右键,选择Add->New Item..
2.取舍Windows 窗体 模板,将名字改成吧UserFrm.cs,点“Add”。
3.添加如下输入框
/// <summary>
/// 新增数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Btn_Save_Click(object sender, EventArgs e)
{
using (OrderDBContainer db = new OrderDBContainer())
{
UserAccout userAccout = new UserAccout();
userAccout.FirstName = this.FirstNameTxt.Text;
userAccout.LastName = this.LastNameTxt.Text;
userAccout.AuditFileds.UpdateDate = DateTime.Now;
userAccout.AuditFileds.InsertDate = DateTime.Now;
db.UserAccoutSet.Add(userAccout);
db.SaveChanges();
MessageBox.Show("保存成功!");
}
}
EF的创新自己询问的法子产生如下三栽(可能还发其他的点子)
【代码如下】
法相同、只有FirstName的值会修改,很显要字段比较多,每个字段都遍历赋值是否修改,显示不是挺便利,故不建议采取,如果是利用框架模板另外说吧。
主意二、只有InsertDate
的值不见面为涂改,其他的字段都见面吃修改,如果字段比较多,表面上看起来较便于(只要设置不要改动的排列就推行了),测试过程中吗意识弊端,如果实体中出不可也空字段,且不再排除不保留的排列的界定外,则会招致保存失败(如下图)。
计三,按自时的了解水平,感觉是极其负谱的,从数据库拿到数量后若拿用变更之值赋下就是足以了(从高并发、高性能方向也发出弊,因为添了数据库的支付,需要先要到数映射到实体对象,在改实体的属于性值,还要还保存到数据库,明显多矣一样浅数据库交互,而且一旦实体对象比较深,对网的出自然会增多).
仁者见仁智者见智吧
/// <summary>
/// 修改
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnUpdate_Click(object sender, EventArgs e)
{
using (OrderDBContainer db = new OrderDBContainer())
{
//方案一:只有Modified = true的才修改
/*
UserAccout userAccount = new UserAccout();
userAccount.FirstName = this.Txt_NewFirstName.Text;
db.UserAccoutSet.Attach(userAccount);
db.Entry(userAccount).Property(x => x.FirstName).IsModified = true;
*/
//方案二:只有Modified = true的才修改
/*
UserAccout userAccount = new UserAccout();
userAccount.FirstName = this.Txt_NewFirstName.Text;
userAccount.LastName = this.Txt_NewLastName.Text;
userAccount.Id = Convert.ToInt32(CBox_User.SelectedValue);
userAccount.AuditFileds.UpdateDate = DateTime.Now;
userAccount.AuditFileds.InsertDate = DateTime.Now;
db.Entry(userAccount).State = System.Data.Entity.EntityState.Modified;
db.Entry(userAccount).Property(item =>item.AuditFileds.InsertDate).IsModified = false;
//存在的问题复杂类型中有2个标量类型,设置其中一个标量属性的IsModified为False时,整个复杂类型中的字段都没有存储
*/
//方案三
int userId = Convert.ToInt32(CBox_User.SelectedValue);
var userSet = db.UserAccoutSet.Where(p => p.Id == userId).First();
userSet.FirstName = this.Txt_NewFirstName.Text;
userSet.LastName = this.Txt_NewLastName.Text;
userSet.AuditFileds.UpdateDate = DateTime.Now;
db.SaveChanges();
MessageBox.Show("修改完成!");
}
}
【遗留问题】//存在的题材错综复杂类型受到来2独标量类型,设置中一个标量属性之IsModified为False时,整个复杂类型中之字段都尚未存储
如果发先生了解怎么解决,求指点,不胜感谢。
/// <summary>
/// 查询数据绑定dataGirdView
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnQuery_Click(object sender, EventArgs e)
{
using (OrderDBContainer db = new OrderDBContainer())
{
List<UserAccout> list = db.UserAccoutSet.Where(x =>x.FirstName == "zhou").ToList();
dataGridView1.DataSource = list;
}
}
/// <summary>
/// 删除
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnDelete_Click(object sender, EventArgs e)
{
using (OrderDBContainer db = new OrderDBContainer())
{
//方式一、按员工的ID删除
int userId = Convert.ToInt32(CBox_User.SelectedValue);
UserAccout userSet = new UserAccout() { Id = userId };
db.Entry(userSet).State = System.Data.Entity.EntityState.Deleted;
db.SaveChanges();
MessageBox.Show("删除完成!");
}
}
链接: https://pan.baidu.com/s/1i5cRdy9 密码: z63m
打赏支付宝: