选择项目时,列表中的数据网格崩溃



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();

我把其他的东西都保持原样,这样人们就可以看到问题,以及这样做是如何解决问题的。

UI的图片与一些数据在第二个网格(底部)和一个成分准备添加我有一个gridview,我把我的成分列表进入工作只是很好。我有第二个gridview,我希望能够从第一个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表。Ingredient实际上是一个抽象类,有HealthyIngredient和RegularIngredient两个子类,但是这两个子类都存储在同一个SQL表中,在另一个子类具有其特定值的地方使用空值。

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)

这似乎也工作得很好,包括一堆相当复杂的数学涉及乘法表的插入字段,并将它们添加到表单的其他地方的文本框,并在第一个网格和第二个网格之间改变一些信息,所以数据都被正确地传递到第二个数据网格。

然而,如果我尝试从第二个数据网格中选择任何东西,我会得到一个错误,导致整个程序崩溃,并将其一直发送回program .cs。

奇怪的是,每隔一段时间,如果我有数据网格设置为RowHeadderSelect,我只点击行标题,它工作正确,包括让我使用编辑按钮并再次正确地做数学,然后它在该会话期间工作,无论我在哪里点击,但是当我重新启动程序时,它给了我同样的错误。

我已经尝试过列表,IList, ICollection和IEnumerable,以防万一它是我的列表类型导致的问题,但它似乎不是。谁有什么建议,我做错了吗?

我添加了更多的相关代码。这是目前仅有的三个影响任何事情的方法——加载,添加,然后尝试点击datagridview。

我不知道在哪里放置任何调试代码,因为它在进入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:UsersTaniasourcereposOldHealthierRecipesHealthierRecipesProgram.cs:line 25

经过多次测试后,我将其分解,并可以发布一个非常简单的示例来复制您所描述的内容。但是对于微笑…

在表单的" Load "事件中有一行设置了配方成分网格的数据源…

this.dgvRecipeIngredients.DataSource = selectedIngredients;

//注释掉那行


由于列表为空,因此此时不需要设置网格数据源。当添加按钮被点击时,它将被设置。

请尝试一下,如果有帮助,请告诉我。

这看起来像是另一个很好的例子,其中BindingList<T>是a更好的选择。

相关内容

  • 没有找到相关文章

最新更新