做一个项目是遇到的问题与求解!
8.20-8.21 完成客户资料和套餐资料相关模块。
难点:在界面的左侧显示标签页。并且在增加套餐这个环节,会涉及到在主界面显示的新增套餐的问题(如何实时更新主界面的套餐表?)。
遇到的问题:在操作中发现,在左侧显示标签页,其实很简单,tabcontrol控件中有一个属性就是设置在何处显示标签的(其中包括top、left、right、bottom),这个属性是alignment。
1. 但也遇到了另一个问题:发现标签页不显示文本! (9:58) 不过如果appearance属性为button或flatbutton时则可显示文本,但也存在一定的问题。
2. 在增加客户这个处理时,如何验证是否输入了足够多的信息(用户名、电话、地址)? (11:36) 可以简单地判断该字段是否为空。
3. 在增加客户时,如何确定该客户的ID,可以是在原有ID的基础上增加1,那么如何获取最后一个客户的ID。而且当有客户被删除时,该ID就会空缺,如何进行填补? (12:29) 设置ID的为自动编号。
4. 如何使得在添加了客户后,在客户资料汇总这个标签页下的信息能够实时地显示? (16:30)
这个问题是因为DataGridView与数据库绑定后,在程序运行过程中,无法知道数据库中的数据是否发生变化。从而不能实时更新。可以考虑用一个时间函数刷新(重新定义数据源):this.dataGridView1.DataSource = …..
遇到一个比较麻烦的事是我不知道为什么给DataSource重新赋值后,其中三列始终不显示数据。如果一开始就不要绑定,而是通过赋值给DataSource的话,那么DataGridView中表头显示的是数据库中的字段名。
我的选择是,索性不要绑定,在程序运行时,如果需要显示这些数据,才去从数据库中取出这些数据,将它们放入DataGridView。当有资料得到更新后,调用RefreshData()函数,重新从数据库中取出这些数据,现在在DataGridView中。首先设置好DataGridView表头要显示的每列的标题。然后把从数据库中取出的listCustomer逐项对应放入DataGridView。
public void RefreshMenuData()
{
this.dataGridView2.Rows.Clear();
int id;
string dishName;
decimal price;
List<Dish> listDish = menuDAO.getAllDishes();
for (int i = 0; i < listDish.Count; i++)
{
id = listDish[i].Id;
dishName = listDish[i].Name;
price = listDish[i].Price;
this.dataGridView2.Rows.Add();
this.dataGridView2.Rows[i].Cells[0].Value = id;
this.dataGridView2.Rows[i].Cells[1].Value = dishName;
this.dataGridView2.Rows[i].Cells[2].Value = price;
}
}
5. 如何使得双击一行客户信息,弹出一个该客户信息的窗口,可以进行修改和删除操作。或者是增加右键功能,在右键中有删除选项? (17:27) 此处选择添加右键菜单(其中包括删除和修改),同时如果双击则显示修改的对话框。
6.
在右键删除中,如何确定右键所选的用户? (17:49) if (e.RowIndex >= 0 &&
e.ColumnIndex >= 0 && e.Button == MouseButtons.Right)
{
dgvBookmarks.Rows[e.RowIndex].Selected = true;
Rectangle r = dgvBookmarks.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex,
true);
contextMenu.Show((Control)sender, r.Left + e.X, r.Top + e.Y); 将上面的代码加入CellMouseDown事件.
这个问题仍旧没有解决,上面的代码只是高亮显示了所选的行,但是焦点并没有在这一行上。(18:00)
7. 在客户资料中的右键时有一个Bug (17:46) 原来是在显示右键菜单时,此事件同时关联两个函数dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)和dataGridView2_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)。而这两个函数应该是分别响应客户和套餐信息的右键事件才对;而且,由于客户信息和套餐信息的ColumnIndex不一样(客户的多),所以导致,但右键点击客户信息时,如果其ColumnIndex值超过套餐信息的ColumnIndex值,就会报告异常。 此处,改为把两个函数合并为一个dataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)函数,在函数内部判断sender对象的发出者:DataGridView dataSender = (DataGridView)sender; if (dataSender.Name == "dataGridView1"){} else if(dataSender.Name == "dataGridView2"){}
8. 如何实现右键按钮减少一份? (8-28 13:22)
8.22-8.24 完成订餐模块,这是整个系统的主界面和最重要的模块。
难点:如何动态显示菜单(以按钮的形式)?如何把下拉框加到ListView中,使得可以让用户修改订餐的份数?如何做到多次点击相同的菜单,使得只显示一个套餐项,而只是更改其订餐的份数?另外,需要在每个套餐的后面加个“删除”按钮。如何自动接入打进来的电话?如果是新用户,在输入了相关资料后提交,如何将这些数据写入数据库。
1. 如何自动根据数据库生成按钮。(15:00) 在Form1_Load函数中添加如下代码:
List<Dish> listDish = menuDAO.getAllDishes();
// 得到数据库中所有的套餐信息
int numberOfColumn = this.tableLayoutPanel1.ColumnCount;
// 一行显示的按钮数
this.tableLayoutPanel1.RowCount = (listDish.Count + 1) / numberOfColumn;
// 根据数据库中的套餐数,设定显示的行数
// 动态生成按钮
for (int tempX = 0; tempX < listDish.Count; tempX++)
{
int tempY = tempX / numberOfColumn;
int column = tempX % numberOfColumn;
int row = tempY;
Button btn = new Button();
this.tableLayoutPanel1.Controls.Add(btn, column, row);
btn.Location = new Point(3 + tempX * 75, 3 + tempY * 75);
btn.Size = new Size(75, 50);
btn.Text = listDish[tempX].Name;
btn.UseVisualStyleBackColor = true;
btn.Click += new EventHandler(btn_Click);
// 按钮关联事件
}
2. 在点击菜单按钮之后,会在右侧的ListView中显示相应的菜单,问题是如何显示关于份数的下拉框?
private
void listView1_MouseUp(object
sender, MouseEventArgs e)
{
// 取得列中被按下的项目
lvItem = this.listView1.GetItemAt(e.X, e.Y);
if (lvItem != null)
{
// 取得被按下之项目的周框。
Rectangle ClickedItem = lvItem.Bounds;
ClickedItem.X += this.listView1.Left +
this.listView1.Columns[0].Width +
this.listView1.Columns[1].Width +
this.listView1.Columns[2].Width;
ClickedItem.Y += this.listView1.Top;
// 确定comboBox的位置
this.comboBox4.Bounds = ClickedItem;
this.comboBox4.Width = this.listView1.Columns[3].Width;
this.comboBox4.Text = lvItem.SubItems[3].Text;
// 使comboBox可见,并获得焦点
this.comboBox4.Visible = true;
this.comboBox4.BringToFront();
this.comboBox4.Focus();
}
}
private void comboBox4_KeyPress(object sender, KeyPressEventArgs e)
{
// 确认使用者按下 ESC 键。
if (e.KeyChar == (char)(Keys.Escape))
{
// 重设原始文字值并将 comboBox 隐藏起来。
this.comboBox4.Text = lvItem.SubItems[3].Text;
this.comboBox4.Visible = false;
}
// 确认使用者按下 ENTER 键。
else if (e.KeyChar == (char)(Keys.Enter))
{
// 将 ComboBox 隐藏起来。
this.comboBox4.Visible = false;
}
}
private void comboBox4_Leave(object sender, EventArgs e)
{
// 设定 ListView 项目的文字使其符合comboBox
lvItem.SubItems[3].Text = this.comboBox4.Text;
textBox12.Text = getTotalPrice().ToString();
// 将comboBox隐藏起来
this.comboBox4.Visible = false;
}
private void comboBox4_SelectedValueChanged(object sender, EventArgs e)
{
// 设定 ListView 项目的文字使其符合comboBox
lvItem.SubItems[3].Text = this.comboBox4.Text;
textBox12.Text = getTotalPrice().ToString();
// 将comboBox隐藏起来
this.comboBox4.Visible = false;
}
3. 怎样求和?怎样求listView控件中订单的总价? (16:44)
private decimal
getTotalPrice()
{
decimal totalPrice = 0;
for (int i = 0; i < listView1.Items.Count; i++)
{
totalPrice += Decimal.Parse(listView1.Items[i].SubItems[tempPrice].Text) *
Decimal.Parse(listView1.Items[i].SubItems[tempAmount].Text);
}
return totalPrice;
}
4. 今天一整天都被这个问题缠着:在其他表中都可以插入,可是在order表中却不能执行insert语句,总是提示说语法错误。(8-24) 后来,还是晓鸣发现那个表名(order)居然是关键字,真是搞死我了!
8.27-8.28完成销售统计这个模块。
难点:如何确定订单的日期,从而来统计每天的销售分数,如何自定义设定时间,并从中读取设定的时间范围?
1. 如何确定本周的第一天是哪一天?
2. 如何显示统计时间范围内的各种套餐,即怎样加到listView中。
3. 在向orderContent表中插入数据时,由于以为orderContentID(主键)是自动编号的,不会重复,故没有指定值。可事实上,如果不指定值,不能插入同样的订单。 解决方法:指定orderContentID的值
4. 如何指定orderContentID的值? 如何获取表中最后一项的ID?
5. 在显示本周、本月的订单的时候,只能显示最后一个订单号的内容。 (12:00) 原来在根据订单号获得订单内容的时候,每次都会重新new List<Tongji>();从而导致前面取出来的订单内容在被放入listTongji之后又被清空了,只剩下最后一次的内容。解决的方法是把List<Tongji> listTongji = new List<Tongji>();放在了循环的外面。
6. 在显示统计内容的时候,如何把相同的套餐内容合并为一条记录。conn.Open();
OleDbCommand cmd = new OleDbCommand(strCommand, conn);
OleDbDataReader reader;
reader = cmd.ExecuteReader();
while (reader.Read())
{
tempTongji = new Tongji();
tempTongji.Amount = Int32.Parse(reader["amount"].ToString());
tempTongji.DishName = reader["dishName"].ToString();
if (listTongji.Count == 0)
{
listTongji.Add(tempTongji);
}
else
{
for (int j = 0; j < listTongji.Count; j++)
{
if (tempTongji.DishName == listTongji[j].DishName)
{
listTongji[j].Amount += Int32.Parse(reader["amount"].ToString());
break;
}
else if(j == (listTongji.Count - 1))
{
listTongji.Add(tempTongji);
}
}
}
}
如何使点餐中的套餐按钮和订单内容之间的位置固定不可变:this.splitContainer1.IsSplitterFixed = true;
8. 在listView中显示订单内容时,每次触发相应的事件都会从数据库中取出数据增加到listView中,而不清楚原来的数据,使得listView中的数据会有很多组。 解决方法:在向ListView的Items中添加数据之前先使用ListView.Items.Clear()清空原来的数据,然后再添加Item。
9.
如何设置listView与右键菜单关联?如果在一开始的设计视图中设置ContextMenuStrip属性关联,那么即使在listview中无内容的地方鼠标右键也会出来菜单? 解决方法:对Listview的菜单,在开始的时候不要设置,而是通过下面的代码来设置:
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
if (this.listView1.GetItemAt(e.X,
e.Y) != null)
{
this.listView1.ContextMenuStrip
= this.contextMenuStrip1;
}
else
{
this.listView1.ContextMenuStrip
= null;
}
}
}
10. 虽然解决了第9个疑问,但是,我在显示了这个右键菜单后,如何确定到底是哪一行被选中了呢? 即我要删除这一行,该怎么办? this.listView1.FocusedItem 获取所选项!
11.
程序启动后就最大化显示:
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
12. 在统计时,出现“未知的错误”,调式时显示:InvalidOperationException。发现数据库访问时,到一定程度后,无法继续访问! 出错原因:在统计时,由于是循环从数据库中取出相关信息,所以需要建立很多连接,可是在连接用完之后,没有及时关闭,导致连接数达到上限。在循环体最后加了语句:conn.close(); 问题解决!
13. 在统计这一块,发现每次显示都很慢,性能很差。原因分析:在执行查询操作时,由于涉及到上张表,在查询时,是每张表都建立一个查询语句。这样使得在用查询时,每个表的查询都要建立连接,并在连接用完之后将其关闭,开销极大。另外,由于如果是相同的套餐的话,还要将其amount相加更新。所以,在每次取出一个套餐时,都要遍历整个List判断这个套餐是否已经存在。 解决方法:在进行查询时,使用join,先将这些表连接起来,并且根据套餐名进行排序。这样只需要一次查询即可,而且在将套餐添加进List中时,不需要再遍历整个List,而是判断前面一项是否与新项的套餐名一致,如果一致,则更新amount,否则,在List中新增一项。