选择项目时列表中的数据网格崩溃
Datagrid from list crashes when item selected
BindingList 是正确答案,它解决了所有问题,包括能够格式化列。这是我必须更改的唯一几行,现在一切正常。
//This went at the top:
BindingList<Ingredient> selectedIngredients = new BindingList<Ingredient>();
//This went in the page Load method:
dgvRecipeIngredients.DataSource = new BindingSource() { DataSource = selectedIngredients};
//These three went as appropriate in methods that added or removed items from the list.
//The ResetBindings removed items from the list, which wasn’t happening before without resetting the page.
selectedIngredients.Add(ingr);
selectedIngredients.RemoveAt(idxSelectedIngr);
selectedIngredients.ResetBindings();
我将其他所有内容保持原样,以便人们可以看到问题以及如何解决这些问题。
Picture of UI with some data in second grid (bottom) and an ingredient ready to be added 我有一个 gridview,我正在将我的成分列表放入其中,它工作得很好。
我有第二个 gridvew,我希望能够从第一个 gridview 添加成分。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace HealthierRecipes
{
public partial class AddRecipe : Form
{
public static int ingrId = 0;
public static int availIngrId = -1;
private static int idxSelectedIngr = 0;
private static int idxSelectedAvailIngr = -1;
private List<Ingredient> selectedIngredients = new List<Ingredient>();
public AddRecipe()
{
InitializeComponent();
}
private void AddRecipe_Load(object sender, EventArgs e)
{
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
dgvAvailIngredients.DataSource = dbContext.Ingredients.OfType<Ingredient>().ToList();
this.dgvRecipeIngredients.DataSource = selectedIngredients;
formatPage();
txtTotCals.Text = "0";
txtTotCarbs.Text = "0";
txtTotProtein.Text = "0";
txtTotFat.Text = "0";
}
}
private void dgvRecipeIngredients_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
idxSelectedIngr = e.RowIndex;
ingrId = Convert.ToInt32(dgvRecipeIngredients.Rows[e.RowIndex].Cells[0].Value);
//var ingr = (from r in dbContext.Ingredients where r.IngredientId == ingrId select r).First();
//txtAddIngredient.Text = ingr.Name;
//txtAddUnit.Text = ingr.Units;
//txtAddAmount.Text = ingr.Amount.ToString();
}
}
private void dgvAvailIngredients_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
idxSelectedAvailIngr = e.RowIndex;
availIngrId = Convert.ToInt32(dgvAvailIngredients.Rows[e.RowIndex].Cells[0].Value);
var ingr = (from r in dbContext.Ingredients where r.IngredientId == availIngrId select r).First();
txtAddIngredient.Text = ingr.Name;
txtAddUnit.Text = ingr.Units;
txtAddAmount.Text = ingr.Amount.ToString();
}
}
private void bnAddIngredient_Click(object sender, EventArgs e)
{
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
var ingr = (from r in dbContext.Ingredients where r.IngredientId == availIngrId select r).First();
if (availIngrId > 0)
{
float amountNumber = 0;
bool amountValid = float.TryParse(txtAddAmount.Text, out amountNumber);
if (amountValid == false)
{
MessageBox.Show("Please only use numbers in the amount box.");
return;
}
ingr.Amount = amountNumber;
selectedIngredients.Add(ingr);
txtAddIngredient.Text = "";
txtAddUnit.Text = "";
txtAddAmount.Text = "";
dgvRecipeIngredients.DataSource = null;
dgvRecipeIngredients.DataSource = selectedIngredients;
//TODO This is where the code to multiply the amount happens, then add the ingredient to the recipe.
//Includes updating recipe nutrients.
float ingrcals = ingr.Calories * ingr.Amount;
float ingrcarbs = ingr.Calories * ingr.Amount;
float ingrpro = ingr.Protein * ingr.Amount;
float ingrfat = ingr.Fat * ingr.Amount;
float totcals = float.Parse(txtTotCals.Text);
float totcarbs = float.Parse(txtTotCarbs.Text);
float totpro = float.Parse(txtTotProtein.Text);
float totfat = float.Parse(txtTotFat.Text);
txtTotCals.Text = (totcals + ingrcals).ToString();
txtTotCarbs.Text = (totcarbs + ingrcarbs).ToString();
txtTotProtein.Text = (totpro + ingrpro).ToString();
txtTotFat.Text = (totfat + ingrfat).ToString();
}
else { MessageBox.Show("Please select an ingredient to add."); }
}
}
private void bnSaveRecipe_Click_1(object sender, EventArgs e)
{
//TODO save recipe
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
Recipe r = new Recipe();
if (ValidateForm())
{
r.Name = txtRecName.Text;
r.Dish = cbDish.SelectedItem.ToString();
r.Servings = Int32.Parse(txtServings.Text);
r.TotalCalories = Int32.Parse(txtTotCals.Text);
r.TotalFat = Int32.Parse(txtTotFat.Text);
r.TotalCarbs = Int32.Parse(txtTotCarbs.Text);
r.TotalProtein = Int32.Parse(txtTotProtein.Text);
r.Instructions = rtxtInstructions.Text;
dbContext.Recipes.InsertOnSubmit(r);
dbContext.SubmitChanges();
MessageBox.Show("Record is saved", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
int id = r.RecipeId;
// r.IngredientList = selectedIngredients;
IngredientList il = new IngredientList();
foreach (Ingredient ingr in selectedIngredients)
{
il.RecipeId = id;
il.IngredientId = ingr.IngredientId;
il.IngredientAmount = ingr.Amount;
}
txtRecName.Text = "";
txtServings.Text = "";
txtTotCals.Text = "0";
txtTotFat.Text = "0";
txtTotCarbs.Text = "0";
txtTotProtein.Text = "0";
rtxtInstructions.Text = "";
dgvRecipeIngredients.DataSource = null;
dgvRecipeIngredients.DataSource = selectedIngredients;
}
else
{
MessageBox.Show("Please fill in all boxes on form with valid values.");
}
}
}
private bool ValidateForm()
{
bool output = true;
if (txtRecName.Text.Length == 0)
{
output = false;
}
if (cbDish.SelectedItem == null)
{
output = false;
}
int servingsNumber = 0;
bool servingsValid = int.TryParse(txtServings.Text, out servingsNumber);
if (servingsValid == false)
{
output = false;
}
int caloriesNumber = 0;
bool caloriesValid = int.TryParse(txtTotCals.Text, out caloriesNumber);
if (caloriesValid == false)
{
output = false;
}
int fatNumber = 0;
bool fatValid = int.TryParse(txtTotFat.Text, out fatNumber);
if (fatValid == false)
{
output = false;
}
int carbsNumber = 0;
bool carbsValid = int.TryParse(txtTotCarbs.Text, out carbsNumber);
if (carbsValid == false)
{
output = false;
}
int proteinNumber = 0;
bool proteinValid = int.TryParse(txtTotProtein.Text, out proteinNumber);
if (proteinValid == false)
{
output = false;
}
return output;
}
private void btnAddCancel_Click(object sender, EventArgs e)
{
//TODO Change from exit to cancel
Application.Exit();
}
private void bnDelIngr_Click(object sender, EventArgs e)
{
//TODO - Add code to remove Nutrition info for removed ingredient - this is done, but it doesn't reomove the item from the list yet.
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
var ingr = (from r in dbContext.Ingredients where r.IngredientId == ingrId select r).First();
if (ingrId > 0)
{
float ingrcals = ingr.Calories * ingr.Amount;
float ingrcarbs = ingr.Calories * ingr.Amount;
float ingrpro = ingr.Protein * ingr.Amount;
float ingrfat = ingr.Fat * ingr.Amount;
float totcals = float.Parse(txtTotCals.Text);
float totcarbs = float.Parse(txtTotCarbs.Text);
float totpro = float.Parse(txtTotProtein.Text);
float totfat = float.Parse(txtTotFat.Text);
txtTotCals.Text = (totcals - ingrcals).ToString();
txtTotCarbs.Text = (totcarbs - ingrcarbs).ToString();
txtTotProtein.Text = (totpro - ingrpro).ToString();
txtTotFat.Text = (totfat - ingrfat).ToString();
ingr.Amount = 1;
selectedIngredients.Remove(ingr);
dgvRecipeIngredients.DataSource = null;
dgvRecipeIngredients.DataSource = selectedIngredients;
}
else { MessageBox.Show("Please select an ingredient to delete."); }
}
}
private void bnEdit_Click(object sender, EventArgs e)
{
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
//TODO - Add code to remove Nutrition info for Edited ingredient - this is done, but it doesn't reomove the item from the list yet.
var ingr = (from r in dbContext.Ingredients where r.IngredientId == ingrId select r).First();
if (ingrId >0)
{
txtAddIngredient.Text = ingr.Name;
txtAddUnit.Text = ingr.Units;
txtAddAmount.Text = ingr.Amount.ToString();
float ingrcals = ingr.Calories * ingr.Amount;
float ingrcarbs = ingr.Calories * ingr.Amount;
float ingrpro = ingr.Protein * ingr.Amount;
float ingrfat = ingr.Fat * ingr.Amount;
float totcals = float.Parse(txtTotCals.Text);
float totcarbs = float.Parse(txtTotCarbs.Text);
float totpro = float.Parse(txtTotProtein.Text);
float totfat = float.Parse(txtTotFat.Text);
txtTotCals.Text = (totcals - ingrcals).ToString();
txtTotCarbs.Text = (totcarbs - ingrcarbs).ToString();
txtTotProtein.Text = (totpro - ingrpro).ToString();
txtTotFat.Text = (totfat - ingrfat).ToString();
selectedIngredients.Remove(ingr);
dgvRecipeIngredients.DataSource = null;
dgvRecipeIngredients.DataSource = selectedIngredients;
}
else { MessageBox.Show("Please select an ingredient to edit."); }
}
}
private void formatPage()
{
dgvAvailIngredients.Columns[0].Width = 25;
dgvAvailIngredients.Columns[1].Width = 150;
dgvAvailIngredients.Columns[2].Width = 75;
dgvAvailIngredients.Columns[3].Width = 25;
dgvAvailIngredients.Columns[4].Width = 50;
dgvAvailIngredients.Columns[5].Width = 50;
dgvAvailIngredients.Columns[6].Width = 50;
dgvAvailIngredients.Columns[7].Width = 50;
dgvRecipeIngredients.Columns[0].Width = 25;
dgvRecipeIngredients.Columns[1].Width = 150;
dgvRecipeIngredients.Columns[2].Width = 75;
dgvRecipeIngredients.Columns[3].Width = 25;
dgvRecipeIngredients.Columns[4].Width = 50;
dgvRecipeIngredients.Columns[5].Width = 50;
dgvRecipeIngredients.Columns[6].Width = 50;
dgvRecipeIngredients.Columns[7].Width = 50;
}
private void btnSearchIngr_Click(object sender, EventArgs e)
{
string srch = txtSearchIngr.Text;
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
var ingrlist = from r in dbContext.Ingredients where r.Name.Contains(srch) select r;
dgvAvailIngredients.DataSource = ingrlist;
}
}
}
}
成分正在从 LINQ 提取到 SQL tables。 Ingredient其实是一个抽象class,有HealthyIngredient和RegularIngredient子class,但是两个子class都存储在同一个SQLtable里,有null其他子class有其特定值的地方的值。
CREATE TABLE [dbo].[Ingredient] (
[IngredientId] INT IDENTITY (1, 1) NOT NULL,
[Name] VARCHAR (50) NOT NULL,
[Units] NCHAR (10) NOT NULL,
[Amount] FLOAT DEFAULT ((1)) NOT NULL,
[Calories] INT NOT NULL,
[Fat] INT NOT NULL,
[Carbs] INT NOT NULL,
[Protein] INT NOT NULL,
[Discriminator] NVARCHAR (50) NOT NULL,
[HealthyVariant1] NVARCHAR (50) NULL,
[HealthyVariant2] NVARCHAR (50) NULL,
[HealthyType] NVARCHAR (50) NULL,
[RegularVariant] NVARCHAR (50) NULL,
[HealthyVar1Id] INT NULL,
[HealthyVar2Id] INT NULL,
[RegVarId] INT NULL,
PRIMARY KEY CLUSTERED ([IngredientId] ASC)
这似乎也工作得很好,包括一堆相当复杂的数学运算,涉及乘以 table 的插入字段并将它们添加到表单其他地方的文本框,并更改第一个网格之间的一些信息第二个,所以数据都被正确传递到第二个数据网格。
但是,如果我尝试 select 来自第二个数据网格的任何内容,我会收到一个错误,导致整个程序崩溃并将其一路发送回 Program.cs。
奇怪的是,每隔一段时间,如果我将数据网格设置为 RowHeadderSelect 并且我只单击行 header,它会正常工作,包括让我使用编辑按钮并正确地进行数学计算再次,然后它在 session 期间工作,无论我点击哪里,但是当我重新启动程序时它再次给我同样的错误。
我已经尝试过 List、IList、ICollection 和 IEnumerable,以防万一是我的列表类型导致了问题,但似乎并非如此。有人对我做错了什么有什么建议吗?
我添加了更多相关代码。这些是目前影响任何事情的仅有的三种方法 - 加载、添加,然后尝试单击数据网格视图。
我不知道把调试代码放在哪里,因为它在进入 CellContentClick 方法之前就崩溃了。我在那里有一个断点,但它永远不会到达它。我在想这是我加载数据的内容或方式,但它在页面上的数据网格中看起来都是正确的。是否有其他方法可以将数据设置到数据网格?感谢您的帮助。
System.IndexOutOfRangeException
HResult=0x80131508
Message=Index -1 does not have a value.
Source=System.Windows.Forms
at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)
at System.Windows.Forms.CurrencyManager.get_Current()
at System.Windows.Forms.DataGridView.DataGridViewDataConnection.OnRowEnter(DataGridViewCellEventArgs e)
at System.Windows.Forms.DataGridView.OnRowEnter(DataGridViewCell& dataGridViewCell, Int32 columnIndex, Int32 rowIndex, Boolean canCreateNewRow, Boolean validationFailureOccurred)
at System.Windows.Forms.DataGridView.SetCurrentCellAddressCore(Int32 columnIndex, Int32 rowIndex, Boolean setAnchorCellAddress, Boolean validateCurrentCell, Boolean throughMouseClick)
at System.Windows.Forms.DataGridView.OnRowHeaderMouseDown(HitTestInfo hti, Boolean isShiftDown, Boolean isControlDown)
at System.Windows.Forms.DataGridView.OnCellMouseDown(DataGridViewCellMouseEventArgs e)
at System.Windows.Forms.DataGridView.OnMouseDown(MouseEventArgs e)
at System.Windows.Forms.Control.WmMouseDown(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.DataGridView.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at HealthierRecipes.Program.Main() in C:\Users\Tania\source\repos\Old\HealthierRecipes\HealthierRecipes\Program.cs:line 25
经过多次测试,我将其分解并可以 post 一个非常简单的示例来重现您描述的内容。但是对于笑容...
在表单“加载”事件中,有一行设置配方成分网格的数据源……
this.dgvRecipeIngredients.DataSource = selectedIngredients;
// Comment out that line.
此时我们不需要设置网格数据源,因为列表是空的。单击添加按钮时,它将被设置。
请试试这个,如果有帮助请告诉我。
This looks like another good example where a BindingList<T>
is a
better choice.
BindingList 是正确答案,它解决了所有问题,包括能够格式化列。这是我必须更改的唯一几行,现在一切正常。
//This went at the top:
BindingList<Ingredient> selectedIngredients = new BindingList<Ingredient>();
//This went in the page Load method:
dgvRecipeIngredients.DataSource = new BindingSource() { DataSource = selectedIngredients};
//These three went as appropriate in methods that added or removed items from the list.
//The ResetBindings removed items from the list, which wasn’t happening before without resetting the page.
selectedIngredients.Add(ingr);
selectedIngredients.RemoveAt(idxSelectedIngr);
selectedIngredients.ResetBindings();
我将其他所有内容保持原样,以便人们可以看到问题以及如何解决这些问题。
Picture of UI with some data in second grid (bottom) and an ingredient ready to be added 我有一个 gridview,我正在将我的成分列表放入其中,它工作得很好。 我有第二个 gridvew,我希望能够从第一个 gridview 添加成分。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace HealthierRecipes
{
public partial class AddRecipe : Form
{
public static int ingrId = 0;
public static int availIngrId = -1;
private static int idxSelectedIngr = 0;
private static int idxSelectedAvailIngr = -1;
private List<Ingredient> selectedIngredients = new List<Ingredient>();
public AddRecipe()
{
InitializeComponent();
}
private void AddRecipe_Load(object sender, EventArgs e)
{
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
dgvAvailIngredients.DataSource = dbContext.Ingredients.OfType<Ingredient>().ToList();
this.dgvRecipeIngredients.DataSource = selectedIngredients;
formatPage();
txtTotCals.Text = "0";
txtTotCarbs.Text = "0";
txtTotProtein.Text = "0";
txtTotFat.Text = "0";
}
}
private void dgvRecipeIngredients_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
idxSelectedIngr = e.RowIndex;
ingrId = Convert.ToInt32(dgvRecipeIngredients.Rows[e.RowIndex].Cells[0].Value);
//var ingr = (from r in dbContext.Ingredients where r.IngredientId == ingrId select r).First();
//txtAddIngredient.Text = ingr.Name;
//txtAddUnit.Text = ingr.Units;
//txtAddAmount.Text = ingr.Amount.ToString();
}
}
private void dgvAvailIngredients_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
idxSelectedAvailIngr = e.RowIndex;
availIngrId = Convert.ToInt32(dgvAvailIngredients.Rows[e.RowIndex].Cells[0].Value);
var ingr = (from r in dbContext.Ingredients where r.IngredientId == availIngrId select r).First();
txtAddIngredient.Text = ingr.Name;
txtAddUnit.Text = ingr.Units;
txtAddAmount.Text = ingr.Amount.ToString();
}
}
private void bnAddIngredient_Click(object sender, EventArgs e)
{
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
var ingr = (from r in dbContext.Ingredients where r.IngredientId == availIngrId select r).First();
if (availIngrId > 0)
{
float amountNumber = 0;
bool amountValid = float.TryParse(txtAddAmount.Text, out amountNumber);
if (amountValid == false)
{
MessageBox.Show("Please only use numbers in the amount box.");
return;
}
ingr.Amount = amountNumber;
selectedIngredients.Add(ingr);
txtAddIngredient.Text = "";
txtAddUnit.Text = "";
txtAddAmount.Text = "";
dgvRecipeIngredients.DataSource = null;
dgvRecipeIngredients.DataSource = selectedIngredients;
//TODO This is where the code to multiply the amount happens, then add the ingredient to the recipe.
//Includes updating recipe nutrients.
float ingrcals = ingr.Calories * ingr.Amount;
float ingrcarbs = ingr.Calories * ingr.Amount;
float ingrpro = ingr.Protein * ingr.Amount;
float ingrfat = ingr.Fat * ingr.Amount;
float totcals = float.Parse(txtTotCals.Text);
float totcarbs = float.Parse(txtTotCarbs.Text);
float totpro = float.Parse(txtTotProtein.Text);
float totfat = float.Parse(txtTotFat.Text);
txtTotCals.Text = (totcals + ingrcals).ToString();
txtTotCarbs.Text = (totcarbs + ingrcarbs).ToString();
txtTotProtein.Text = (totpro + ingrpro).ToString();
txtTotFat.Text = (totfat + ingrfat).ToString();
}
else { MessageBox.Show("Please select an ingredient to add."); }
}
}
private void bnSaveRecipe_Click_1(object sender, EventArgs e)
{
//TODO save recipe
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
Recipe r = new Recipe();
if (ValidateForm())
{
r.Name = txtRecName.Text;
r.Dish = cbDish.SelectedItem.ToString();
r.Servings = Int32.Parse(txtServings.Text);
r.TotalCalories = Int32.Parse(txtTotCals.Text);
r.TotalFat = Int32.Parse(txtTotFat.Text);
r.TotalCarbs = Int32.Parse(txtTotCarbs.Text);
r.TotalProtein = Int32.Parse(txtTotProtein.Text);
r.Instructions = rtxtInstructions.Text;
dbContext.Recipes.InsertOnSubmit(r);
dbContext.SubmitChanges();
MessageBox.Show("Record is saved", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
int id = r.RecipeId;
// r.IngredientList = selectedIngredients;
IngredientList il = new IngredientList();
foreach (Ingredient ingr in selectedIngredients)
{
il.RecipeId = id;
il.IngredientId = ingr.IngredientId;
il.IngredientAmount = ingr.Amount;
}
txtRecName.Text = "";
txtServings.Text = "";
txtTotCals.Text = "0";
txtTotFat.Text = "0";
txtTotCarbs.Text = "0";
txtTotProtein.Text = "0";
rtxtInstructions.Text = "";
dgvRecipeIngredients.DataSource = null;
dgvRecipeIngredients.DataSource = selectedIngredients;
}
else
{
MessageBox.Show("Please fill in all boxes on form with valid values.");
}
}
}
private bool ValidateForm()
{
bool output = true;
if (txtRecName.Text.Length == 0)
{
output = false;
}
if (cbDish.SelectedItem == null)
{
output = false;
}
int servingsNumber = 0;
bool servingsValid = int.TryParse(txtServings.Text, out servingsNumber);
if (servingsValid == false)
{
output = false;
}
int caloriesNumber = 0;
bool caloriesValid = int.TryParse(txtTotCals.Text, out caloriesNumber);
if (caloriesValid == false)
{
output = false;
}
int fatNumber = 0;
bool fatValid = int.TryParse(txtTotFat.Text, out fatNumber);
if (fatValid == false)
{
output = false;
}
int carbsNumber = 0;
bool carbsValid = int.TryParse(txtTotCarbs.Text, out carbsNumber);
if (carbsValid == false)
{
output = false;
}
int proteinNumber = 0;
bool proteinValid = int.TryParse(txtTotProtein.Text, out proteinNumber);
if (proteinValid == false)
{
output = false;
}
return output;
}
private void btnAddCancel_Click(object sender, EventArgs e)
{
//TODO Change from exit to cancel
Application.Exit();
}
private void bnDelIngr_Click(object sender, EventArgs e)
{
//TODO - Add code to remove Nutrition info for removed ingredient - this is done, but it doesn't reomove the item from the list yet.
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
var ingr = (from r in dbContext.Ingredients where r.IngredientId == ingrId select r).First();
if (ingrId > 0)
{
float ingrcals = ingr.Calories * ingr.Amount;
float ingrcarbs = ingr.Calories * ingr.Amount;
float ingrpro = ingr.Protein * ingr.Amount;
float ingrfat = ingr.Fat * ingr.Amount;
float totcals = float.Parse(txtTotCals.Text);
float totcarbs = float.Parse(txtTotCarbs.Text);
float totpro = float.Parse(txtTotProtein.Text);
float totfat = float.Parse(txtTotFat.Text);
txtTotCals.Text = (totcals - ingrcals).ToString();
txtTotCarbs.Text = (totcarbs - ingrcarbs).ToString();
txtTotProtein.Text = (totpro - ingrpro).ToString();
txtTotFat.Text = (totfat - ingrfat).ToString();
ingr.Amount = 1;
selectedIngredients.Remove(ingr);
dgvRecipeIngredients.DataSource = null;
dgvRecipeIngredients.DataSource = selectedIngredients;
}
else { MessageBox.Show("Please select an ingredient to delete."); }
}
}
private void bnEdit_Click(object sender, EventArgs e)
{
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
//TODO - Add code to remove Nutrition info for Edited ingredient - this is done, but it doesn't reomove the item from the list yet.
var ingr = (from r in dbContext.Ingredients where r.IngredientId == ingrId select r).First();
if (ingrId >0)
{
txtAddIngredient.Text = ingr.Name;
txtAddUnit.Text = ingr.Units;
txtAddAmount.Text = ingr.Amount.ToString();
float ingrcals = ingr.Calories * ingr.Amount;
float ingrcarbs = ingr.Calories * ingr.Amount;
float ingrpro = ingr.Protein * ingr.Amount;
float ingrfat = ingr.Fat * ingr.Amount;
float totcals = float.Parse(txtTotCals.Text);
float totcarbs = float.Parse(txtTotCarbs.Text);
float totpro = float.Parse(txtTotProtein.Text);
float totfat = float.Parse(txtTotFat.Text);
txtTotCals.Text = (totcals - ingrcals).ToString();
txtTotCarbs.Text = (totcarbs - ingrcarbs).ToString();
txtTotProtein.Text = (totpro - ingrpro).ToString();
txtTotFat.Text = (totfat - ingrfat).ToString();
selectedIngredients.Remove(ingr);
dgvRecipeIngredients.DataSource = null;
dgvRecipeIngredients.DataSource = selectedIngredients;
}
else { MessageBox.Show("Please select an ingredient to edit."); }
}
}
private void formatPage()
{
dgvAvailIngredients.Columns[0].Width = 25;
dgvAvailIngredients.Columns[1].Width = 150;
dgvAvailIngredients.Columns[2].Width = 75;
dgvAvailIngredients.Columns[3].Width = 25;
dgvAvailIngredients.Columns[4].Width = 50;
dgvAvailIngredients.Columns[5].Width = 50;
dgvAvailIngredients.Columns[6].Width = 50;
dgvAvailIngredients.Columns[7].Width = 50;
dgvRecipeIngredients.Columns[0].Width = 25;
dgvRecipeIngredients.Columns[1].Width = 150;
dgvRecipeIngredients.Columns[2].Width = 75;
dgvRecipeIngredients.Columns[3].Width = 25;
dgvRecipeIngredients.Columns[4].Width = 50;
dgvRecipeIngredients.Columns[5].Width = 50;
dgvRecipeIngredients.Columns[6].Width = 50;
dgvRecipeIngredients.Columns[7].Width = 50;
}
private void btnSearchIngr_Click(object sender, EventArgs e)
{
string srch = txtSearchIngr.Text;
using (RecipeClassesDataContext dbContext = new RecipeClassesDataContext())
{
var ingrlist = from r in dbContext.Ingredients where r.Name.Contains(srch) select r;
dgvAvailIngredients.DataSource = ingrlist;
}
}
}
}
成分正在从 LINQ 提取到 SQL tables。 Ingredient其实是一个抽象class,有HealthyIngredient和RegularIngredient子class,但是两个子class都存储在同一个SQLtable里,有null其他子class有其特定值的地方的值。
CREATE TABLE [dbo].[Ingredient] (
[IngredientId] INT IDENTITY (1, 1) NOT NULL,
[Name] VARCHAR (50) NOT NULL,
[Units] NCHAR (10) NOT NULL,
[Amount] FLOAT DEFAULT ((1)) NOT NULL,
[Calories] INT NOT NULL,
[Fat] INT NOT NULL,
[Carbs] INT NOT NULL,
[Protein] INT NOT NULL,
[Discriminator] NVARCHAR (50) NOT NULL,
[HealthyVariant1] NVARCHAR (50) NULL,
[HealthyVariant2] NVARCHAR (50) NULL,
[HealthyType] NVARCHAR (50) NULL,
[RegularVariant] NVARCHAR (50) NULL,
[HealthyVar1Id] INT NULL,
[HealthyVar2Id] INT NULL,
[RegVarId] INT NULL,
PRIMARY KEY CLUSTERED ([IngredientId] ASC)
这似乎也工作得很好,包括一堆相当复杂的数学运算,涉及乘以 table 的插入字段并将它们添加到表单其他地方的文本框,并更改第一个网格之间的一些信息第二个,所以数据都被正确传递到第二个数据网格。
但是,如果我尝试 select 来自第二个数据网格的任何内容,我会收到一个错误,导致整个程序崩溃并将其一路发送回 Program.cs。
奇怪的是,每隔一段时间,如果我将数据网格设置为 RowHeadderSelect 并且我只单击行 header,它会正常工作,包括让我使用编辑按钮并正确地进行数学计算再次,然后它在 session 期间工作,无论我点击哪里,但是当我重新启动程序时它再次给我同样的错误。
我已经尝试过 List、IList、ICollection 和 IEnumerable,以防万一是我的列表类型导致了问题,但似乎并非如此。有人对我做错了什么有什么建议吗?
我添加了更多相关代码。这些是目前影响任何事情的仅有的三种方法 - 加载、添加,然后尝试单击数据网格视图。
我不知道把调试代码放在哪里,因为它在进入 CellContentClick 方法之前就崩溃了。我在那里有一个断点,但它永远不会到达它。我在想这是我加载数据的内容或方式,但它在页面上的数据网格中看起来都是正确的。是否有其他方法可以将数据设置到数据网格?感谢您的帮助。
System.IndexOutOfRangeException
HResult=0x80131508
Message=Index -1 does not have a value.
Source=System.Windows.Forms
at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)
at System.Windows.Forms.CurrencyManager.get_Current()
at System.Windows.Forms.DataGridView.DataGridViewDataConnection.OnRowEnter(DataGridViewCellEventArgs e)
at System.Windows.Forms.DataGridView.OnRowEnter(DataGridViewCell& dataGridViewCell, Int32 columnIndex, Int32 rowIndex, Boolean canCreateNewRow, Boolean validationFailureOccurred)
at System.Windows.Forms.DataGridView.SetCurrentCellAddressCore(Int32 columnIndex, Int32 rowIndex, Boolean setAnchorCellAddress, Boolean validateCurrentCell, Boolean throughMouseClick)
at System.Windows.Forms.DataGridView.OnRowHeaderMouseDown(HitTestInfo hti, Boolean isShiftDown, Boolean isControlDown)
at System.Windows.Forms.DataGridView.OnCellMouseDown(DataGridViewCellMouseEventArgs e)
at System.Windows.Forms.DataGridView.OnMouseDown(MouseEventArgs e)
at System.Windows.Forms.Control.WmMouseDown(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.DataGridView.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at HealthierRecipes.Program.Main() in C:\Users\Tania\source\repos\Old\HealthierRecipes\HealthierRecipes\Program.cs:line 25
经过多次测试,我将其分解并可以 post 一个非常简单的示例来重现您描述的内容。但是对于笑容...
在表单“加载”事件中,有一行设置配方成分网格的数据源……
this.dgvRecipeIngredients.DataSource = selectedIngredients;
// Comment out that line.
此时我们不需要设置网格数据源,因为列表是空的。单击添加按钮时,它将被设置。
请试试这个,如果有帮助请告诉我。
This looks like another good example where a
BindingList<T>
is a better choice.