For the purposes of invoicing, I'm keeping track of timesheet entries that are associated with an invoice by storing the selected timesheets in the browser Session and adding/removing entries to that list as the user updates:
The GridView loads all timesheets for the selected company and then indicates by changing row style and select button text:
private void HighlightInvoiceTimesheets()
{
var timesheets = Session["invoiceTimesheets"] as List<Timesheet>;
var invoiceTotalHours = 0;
foreach (var timesheet in timesheets)
{
var tid = timesheet.Id.ToString();
foreach (GridViewRow row in ItemsGrid.Rows)
{
var btn = row.Cells[ItemsGrid.Columns.Count - 1].Controls[0] as LinkButton;
if (ItemsGrid.DataKeys[row.RowIndex].Values["Id"].ToString() == tid)
{
row.CssClass = "success";
btn.Text = "Remove";
int.TryParse(row.Cells[5].Text, out int timesheetHours);
invoiceTotalHours += timesheetHours;
}
}
}
Session["invoiceTotalHours"] = invoiceTotalHours;
BillableHoursLabel.Text = invoiceTotalHours.ToString();
}
When the user "selects" an item in the GridView, it adds or removes the item from the collection in the Session and updates the GridView accordingly:
protected void ItemsGrid_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
{
// Get the list of timesheets associated with the invoice.
var list = (Session["invoiceTimesheets"] == null) ? new List<Timesheet>() : Session["invoiceTimesheets"] as List<Timesheet>;
// Get the selected timesheet.
int.TryParse(ItemsGrid.DataKeys[e.NewSelectedIndex].Values["Id"].ToString(), out int timesheetId);
var timesheet = timesheetService.GetClearTimesheet(timesheetId);
// Get the select button to update its text.
var btn = ItemsGrid.Rows[e.NewSelectedIndex].Cells[ItemsGrid.Columns.Count - 1].Controls[0] as LinkButton;
// Get the total hours billable for the invoice based on the total hours of the timesheets.
var invoiceTotalHours = (Session["invoiceTotalHours"] == null) ? 0 : int.Parse(Session["invoiceTotalHours"].ToString());
if (list.Find(x => x.Id == timesheetId) != null)
{
// The list contains the selected item, remove it and indicate removed.
list.Remove(timesheet);
ItemsGrid.Rows[e.NewSelectedIndex].CssClass = "";
btn.Text = "Select";
int.TryParse(Session["invoiceTotalHours"].ToString(), out invoiceTotalHours);
invoiceTotalHours -= timesheet.BillableHours;
}
else
{
// The list doesn't contain the selected item, add it and indicate added.
list.Add(timesheet);
ItemsGrid.Rows[e.NewSelectedIndex].CssClass = "success";
btn.Text = "Remove";
int.TryParse(Session["invoiceTotalHours"].ToString(), out invoiceTotalHours);
invoiceTotalHours += timesheet.BillableHours;
}
BillableHoursLabel.Text = invoiceTotalHours.ToString();
// Update the collection in the session.
Session["invoiceTimesheets"] = list;
}
This works without any errors but I'm very confused why list.Remove(timesheet); doesn't actually update the list in memory.
As a result of this, the collection in the session doesn't get updated and changes made don't reflect on the database.
It's because the timesheet you're trying to remove isn't the same object as the one you get from
var timesheet = timesheetService.GetClearTimesheet(timesheetId);
instead of this:
if (list.Find(x => x.Id == timesheetId) != null)
{
// The list contains the selected item, remove it and indicate removed.
list.Remove(timesheet);
Do this:
var timeSheetSession=list.FirstOrDefault(x => x.Id == timesheetId);
if(timeSheetSession!=null) list.Remove(timeSheetSession);
it's pseudo code, i didn't test it.
Related
I have this table structure
patients:
PK_Patient
PatientID
PatientName
items:
PK_Item
ItemID
ItemDesc
enrolleditems:
PK_EnrollMeds
FK_User_Add
DateTimeAdded
FK_Item
I have a form which has the user included on the form, and datagridview which displays the items enrolled to patient (binded to enrolleditems but items datamember is only displayed on grid), then add and delete button.
The entry on the screenshot is manually added on the database ([MED0001] enrolleditems table) for sample purposes.
On the add button will open another forms which will load all the items and a checkbox to select which item to be added, then a select button which copy the selected datarows to datatable.
I have the below code for the Add button on Enroll Medication form
M3dEntities m3d = new M3dEntities();
enrollmeds _enrollmeds = new enrollmeds();
EnrollMedSelectionFrm enrollselectfrm;
public DataTable SelectedItems { get; set; }
private void AddBtn_Click(object sender, EventArgs e)
{
enrollselectfrm = new EnrollMedSelectionFrm();
var pxdetails = (from adm in m3d.admission
join pxDC in m3d.datacenter
on adm.FK_DC_Patient equals pxDC.PK_Datacenter
where adm.admissionNo == SelectedAdmNo
select new
{
adm,
pxDC
}).FirstOrDefault();
if (enrollselectfrm.ShowDialog() == DialogResult.OK)
{
if (SelectedItems == null)
{
enrollmedsBindingSource.Clear();
}
else
{
enrollmedsBindingSource.Clear();
foreach (DataRow dr in SelectedItems.Rows)
{
_enrollmeds = new enrollmeds();
_enrollmeds.items = new items();
_enrollmeds.FK_DC_Patient = pxdetails.pxDC.PK_Datacenter;
_enrollmeds.FK_DC_userAdd = mainfrm.PK_DC_UserLoggedIn;
var svrDT = ((IObjectContextAdapter)m3d).ObjectContext.CreateQuery<DateTime>("CurrentDateTime() ");
DateTime currdatetime = svrDT.AsEnumerable().First();
_enrollmeds.AddDateTime = currdatetime;
_enrollmeds.FK_Admission = pxdetails.adm.PK_Admission;
int pkItems = int.Parse(dr.Field<string>("PK_Items").ToString());
var itemdtls = (from i in m3d.items
where i.PK_Items == pkItems
select i).FirstOrDefault();
_enrollmeds.FK_Items = pkItems;
_enrollmeds.items.ItemID = itemdtls.ItemID;
_enrollmeds.items.ItemDesc = itemdtls.ItemDesc;
_enrollmeds.items.GenericName = itemdtls.GenericName;
_enrollmeds.items.ItemGroup = itemdtls.ItemGroup;
enrollmedsBindingSource.Add(_enrollmeds);
}
}
}
}
My problem with this is only the first selected item on the itemselection form.
I want to display all the items selected on the itemselection form to the enrollmedsDataGridView of enrollmedicines form.
Thank You in advance..
I am having problem with GridView on row command and stack up the data in another GridView:
private List<DistributionStandardPackingUnitItems> tempDistSPUI
{
get
{
if (ViewState["tempDistSPUI"] == null)
{
return new List<DistributionStandardPackingUnitItems>();
}
else
{
return (List<DistributionStandardPackingUnitItems>)ViewState["tempDistSPUI"];
}
}
set
{
ViewState["tempDistSPUI"] = value;
}
}
protected void gvSPU_OnRowCommand(object sender, GridViewCommandEventArgs e)
{
int packagesNeeded = prodPackBLL.getPackagesNeededByDistributionID(distributionID);
//Get selected standard packing name
int rowNo = int.Parse(e.CommandArgument.ToString());
SPUname = this.gvSPU.DataKeys[rowNo].Value.ToString();
lblSPUname.Text = SPUname;
//Get the record from view state
itemList = tempDistSPUI;
itemList = packBLL.getAllDistSPUItemByDistributionIDnSPUName(distributionID, SPUname);
gvFinalised.DataSource = itemList;
gvFinalised.DataBind();
//Save the last record to view state
this.tempDistSPUI = itemList;
}
Let's say when I first selected a row from gvSPU, it returns an itemList filled with data and display in gvFinalised. What I am trying to do is if I selected another row from gvSPU, the previous records in gvFinalised will still there and stack up another itemList from the secondly selected row instead of wiping up the record previously and display the latest itemList data.
I am using viewState but it does not work.
EDIT
protected void lbnAdd_Click(object sender, EventArgs e)
{
List<DistributionStandardPackingUnitItems> prodVariantDetail = new List<DistributionStandardPackingUnitItems>();
int packagesNeeded = prodPackBLL.getPackagesNeededByDistributionID(distributionID);
// get the last product variant IDs from ViewState
prodVariantIDList = this.SelectedVariantDetailIDs;
foreach (RepeaterItem ri in Repeater1.Items)
{
GridView gvProduct = (GridView)ri.FindControl("gvProduct");
foreach (GridViewRow gr in gvProduct.Rows)
{
CheckBox cb = (CheckBox)gr.FindControl("cbCheckRow");
//Prevent gvFinalised to store duplicate products
if (cb.Checked && !prodVariantIDList.Any(i => i == gvProduct.DataKeys[gr.RowIndex].Value.ToString()))
{
// add the corresponding DataKey to idList
prodVariantIDList.Add(gvProduct.DataKeys[gr.RowIndex].Value.ToString());
}
}
}
for (int i = 0; i < prodVariantIDList.Count; i++)
{
prodVariantDetail.Add(packBLL.getProdVariantDetailByID(prodVariantIDList[i]));
}
//Check if itemList and prodVariantDetail list contains any duplicate records
var Gdupes = itemList.GroupBy(x => new { x.id }).Where(x => x.Skip(1).Any()).ToList();
List<DistributionStandardPackingUnitItems> dupes = Gdupes.SelectMany(x => x).ToList();
prodVariantDetail = itemList.Except(dupes).ToList();
gvFinalised.DataSource = prodVariantDetail;
gvFinalised.DataBind();
foreach (GridViewRow gr in gvFinalised.Rows)
{
//Get the product packaging quantity by productName
string name = gr.Cells[1].Text;
int productQuantity = packBLL.getProductQuantityByName(name, distributionID);
TextBox tb = (TextBox)gr.Cells[5].FindControl("tbQuantity");
if (productQuantity == 0)
{
tb.Text = productQuantity.ToString();
}
else
{
tb.Text = (productQuantity / packagesNeeded).ToString();
}
}
// save prodVariantIDList to ViewState
this.SelectedVariantDetailIDs = prodVariantIDList;
}
private List<string> SelectedVariantDetailIDs
{
get
{
if (ViewState["SelectedVariantDetailIDs"] == null)
{
return new List<string>();
}
else
{
return (List<string>)ViewState["SelectedVariantDetailIDs"];
}
}
set
{
ViewState["SelectedVariantDetailIDs"] = value;
}
}
The problem is the following lines:
//Get the record from view state
itemList = tempDistSPUI;
// here itemList will be replaced
itemList = packBLL.getAllDistSPUItemByDistributionIDnSPUName(distributionID, SPUname);
First you assign tempDistSPUI from ViewState to itemList, but then you replace itemList at the next line. You need to add the elements returned from packBLL.getAllDistSPUItemByDistributionIDnSPUName to itemList instead of replacing itemList. Here's what I would do using List.AddRange Method:
itemList = tempDistSPUI;
// add the returned elements to itemList
itemList.AddRange(packBLL.getAllDistSPUItemByDistributionIDnSPUName(distributionID, SPUname));
UPDATE
To prevent duplication with the previous elements:
itemList = tempDistSPUI;
List<DistributionStandardPackingUnitItems> itemListNew = new List<DistributionStandardPackingUnitItems>();
itemListNew = packBLL.getAllDistSPUItemByDistributionIDnSPUName(distributionID, SPUname);
// get all previous IDs in a List<int>
List<int> previousIDs = itemList.Select(x => x.id).ToList();
// filter itemListNew and add the elements to itemList
itemList.AddRange(itemListNew.Where(x => !previousIDs.Contains(x.id));
Look at the following code example.
What it does:
Iterates a bunch of customers. If it already knows the customer, it retrieves the existing database object for that customer (this is the problem-ridden part). Otherwise, it creates a new object (this works fine).
All loans where the social security number matches (CPR) will be added to the new or existing customer.
The problem: it works for new customer objects, but when I retrieve an existing customer object, the loans lose their relation to the customer when saved (CustomerID = null). They are still saved to the database.
Any ideas?
protected void BuildCustomerData()
{
Console.WriteLine(" Starting the customer build.");
var counter = 0;
var recycleCount = 100;
var reportingCount = 100;
var sTime = DateTime.Now;
var q = from c in db.IntermediaryRkos
select c.CPR;
var distincts = q.Distinct().ToArray();
var numbersToProcess = distincts.Count();
Console.WriteLine(" Identified " + numbersToProcess + " customers. " + (DateTime.Now - sTime).TotalSeconds);
foreach (var item in distincts)
{
var loans = from c in db.IntermediaryRkos
where c.CPR == item
select c;
var existing = db.Customers.Where(x => x.CPR == item).FirstOrDefault();
if (existing != null)
{
this.GenerateLoanListFor(existing, loans);
db.Entry(existing).State = System.Data.EntityState.Modified;
}
else
{
var customer = new Customer
{
CPR = item,
};
this.GenerateLoanListFor(customer, loans);
db.Customers.Add(customer);
db.Entry(customer).State = System.Data.EntityState.Added;
}
counter++;
if (counter % recycleCount == 0)
{
this.SaveAndRecycleContext();
}
if (counter % reportingCount == 0)
{
Console.WriteLine(" Processed " + counter + " customers of " + numbersToProcess + ".");
}
}
db.SaveChanges();
}
protected void GenerateLoanListFor(Customer customer, IQueryable<IntermediaryRko> loans)
{
customer.Loans = new List<Loan>();
foreach (var item in loans.Where(x => x.DebtPrefix == "SomeCategory").ToList())
{
var transformed = StudentLoanMap.CreateFrom(item);
customer.Loans.Add(transformed);
db.Entry(transformed).State = System.Data.EntityState.Added;
}
}
EDIT 1:
As pointed out, I am manually setting the state. This is due to the RecycleContext call, which is implemented for maximum db transaction performance:
protected void SaveAndRecycleContext()
{
db.SaveChanges();
db.Dispose();
db = new SolutionDatabase();
db.Configuration.AutoDetectChangesEnabled = false;
db.Configuration.ValidateOnSaveEnabled = false;
}
Existing loan or not, you wipe out the customer.Loans Property when you call
customer.Loans = new List<Loan>();
I have performed enormous amount of Google search on this topic but couldn't really find the proper answer to this question. The solution might be simple, but I am a beginner to C# ASP.NET.
I have some code that is taking and storing user inputs from a dropdown list and a textbox into its individual List. I am trying to display both lists in a single gridview as individual columns. For an example, when a user selects a product and type in the quantity and hits the add button, it should display the details in a single row of a gridview. Now I have achieved saving the data into a list but cannot get it to display it in a single row.
Here is my code:
List<string> productIdList = new List<string>();
List<string> productTemp = new List<string>();
List<string> quantityList = new List<string>();
List<string> quantityTemp = new List<string>();
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
productTemp = (List<string>)ViewState["productId"];
quantityTemp = (List<string>)ViewState["quantity"];
string str1 = Convert.ToString(productTemp);
string str2 = Convert.ToString(quantityTemp);
if (str1 != "")
{
if (productTemp.Count != 0)
{
foreach (string ids in productTemp)
{
productIdList.Add(ids);
}
}
}
if (str2 != "")
{
if (quantityTemp.Count != 0)
{
foreach (string qtys in quantityTemp)
{
quantityList.Add(qtys);
}
}
}
}
}
protected void btnContinue_Click(object sender, EventArgs e)
{
productIdList.Add(ddlProduct.SelectedValue.ToString());
quantityList.Add(txtQuantity.Text);
ViewState["productId"] = productIdList;
ViewState["quantity"] = quantityList;
txtQuantity.Text = "";
ArrayList testList = new ArrayList();
testList.AddRange(productIdList);
testList.AddRange(quantityList);
grdTest.DataSource = testList;
grdTest.DataBind();
grdProduct.DataSource = productIdList;
grdProduct.DataBind();
grdQuantity.DataSource = quantityList;
grdQuantity.DataBind();
}
}
The gridview currently present are for test purpose to check if data persists after every click of button. grdTest is what I am using for trying to display my list as columns.
Final would be something like this:
Name Qty
----- -----
Name1(list1) 5(list2)
Thanks!
You can use Linq to create List of object with Name and Qty from two lists like below
var temp = productIdList.Zip(quantityList, (n, w) => new { Name = n, Qty = w });
grdTest.DataSource = temp.ToList();
grdTest.DataBind();
Gridview you have to show both name and quantity in one row, if you join name and quantity to a one list it will not display as you expected ( all will show in one column)
we can create new class with Name and Qty as properties and create List of items by iterating though productIdList and quantityList.
Read more about Enumerable.Zip
i have placed a gridview on my page and linked it to LinqDataSourceFemale (Female Table of Database) and i have a search event code like the below one
protected void ButtonSearch_Click(object sender, EventArgs e)
{
using(BerouDataContext Data = new BerouDataContext())
{
if (DropDownListGender.SelectedItem.Text == "Male")
{
int age = Convert.ToInt32(DropDownListAge.Text);
string education = DropDownListEducation.Text.ToString();
string maritalstatus = DropDownListMaritalStatus.Text.ToString();
//var religion = DropDownListReligion.Text.ToString();
string caste = DropDownListCaste.Text.ToString();
string city = DropDownListCity.ToString();
var SearchResultBoys = Data.Males.Where(tan =>
(tan.Age == age)
&& (tan.Education == education)
&& (tan.Group == maritalstatus)
&& (tan.Caste == caste));
GridViewMale.DataSourceID = "";
GridViewMale.DataSource = SearchResultBoys;
GridViewMale.DataBind();
}
else if (DropDownListGender.SelectedItem.Text == "Female")
{
int age = Convert.ToInt32(DropDownListAge.Text);
string education = DropDownListEducation.Text.ToString();
string maritalstatus = DropDownListMaritalStatus.Text.ToString();
//var religion = DropDownListReligion.Text.ToString();
string caste = DropDownListCaste.Text.ToString();
string city = DropDownListCity.ToString();
var SearchResultGirls = Data.Females.Where(tan =>
(tan.Age == age)
&& (tan.Education == education)
&& (tan.Group == maritalstatus)
&& (tan.Caste == caste));
GridViewFemale.DataSourceID = "";
GridViewFemale.DataSource = SearchResultGirls;
GridViewFemale.DataBind();
}
}
}
grid view doesnt appear after button click, please help me.
You have to persist the data in some fashion. It appears that after the button is clicked, a postback occurs and you lose it. One thing you might check on where the databinding fires, ensure that it is caught on subsequent postbacks.
Another thing you could do is simply store the data in a session variable, and upon postback re-bind the gridview with the data.
When the data is first retrieved, you could assign it to a session variable:
Session.Add("searchResultBoys", SearchResultBoys);
Session.Add("searchResultGirls", SearchResultGirls);
Then for example on subsuquent pageloads you could:
GridViewMale.DataSource = (DataTable)Session[searchResultBoys]; //be sure to cast whatever the datasource is, in my example I just used DataTable
GridViewFemale.DataSource = (DataTable)Session[searchResultGirls];
EDIT:
So in order to persist the data in a session variable, we have to save the var SearchResultBoys and SearchResultGirls into a type (in this case a datatable). Becuase saving the var in a session will just save the query expression and not the result set. Try converting your var SearchResultBoys and SearchResultGirls to this:
IEnumerable<DataRow> SearchResultsBoys = Data.Males.Where(tan =>
(tan.Age == age)
&& (tan.Education == education)
&& (tan.Group == maritalstatus)
&& (tan.Caste == caste));
Then what we can do is assign that result to a datatable - where it can be stored in memory) and persisted.
DataTable dt = SearchResultsBoys.CopyToDataTable<DataRow>();
Now you can bind the data as before:
GridViewMale.DataSourceID = "";
GridViewMale.DataSource = SearchResultBoys;
GridViewMale.DataBind();
Once that is working for you on the girls and boys data, then I can show you how to persist using a session or global variable.
Remove this GridViewFemale.DataSourceID = ""; line
And are you bind gridview in page load inside of !IsPostBack?
If it not bind,Please bind gridview in inside of !IsPostBack in pageload event
Edit
the coding for
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
// here is Bind gridview code .
}
}