Update asp.net listview with LINQ, programmatically - c#

I'm trying to find a good code sample to update a database entry in my listview control. I suppose I would need to extract the ID from somewhere (some label control?). I am using LINQtoSQL to talk with the database.
protected void lvTargets_ItemUpdating(object sender, ListViewUpdateEventArgs e)
{
InventoryDataContext inventory = new InventoryDataContext();
//Target target = from target in inventory.Targets
// where target.ID == lvTargets.Items[e.ItemIndex].FindControl("ID")
// *** Not sure how to go about this ^^^
//inventory.Targets.InsertOnSubmit(target);
//inventory.SubmitChanges();
lvTargets.EditIndex = -1;
BindInventory();
}

You can get the ID from the event arguments either like
e.Keys["ID"]
e.OldValues["ID"]
depending on your situation.

Related

Can't upload data from DataTable to Database in WPF .NET 5.0?

I am writing an app WPF C# .NET 5.0 that converts numbers from metric to imperial (and vice-versa). I am having a weird issue with data not uploading to the database. I successfully downloaded data from the database, but I cannot display it in my data grid.
The database is connected via DataSetProj.xsd file.
Here's how my database looks like:
My app has 3 tabs, one for converter, one for datagrid, and one for other stuff. Whenever input in converter changes, it automatically converts, and adds a record to Stats table.
My app properly reads data from Converters, MetricUnits and ImperialUnits tables (not sure about Stats, because this table is empty).
FYI those are my fields I use to communicate with DB:
DataSetProj DBProj = new DataSetProj();
DataSetProjTableAdapters.ConvertersTableAdapter convertersTableAdapter = new();
DataSetProjTableAdapters.StatsTableAdapter statsTableAdapter = new();
DataSetProjTableAdapters.ImperialUnitsTableAdapter imperialUnitsTableAdapter = new();
DataSetProjTableAdapters.MetricUnitsTableAdapter metricUnitsTableAdapter = new();
DataSetProjTableAdapters.StatsViewTableAdapter statsViewTableAdapter = new();
Here's the launch-time code:
convertersTableAdapter.Fill(DBProj.Converters);
statsTableAdapter.Fill(DBProj.Stats);
imperialUnitsTableAdapter.Fill(DBProj.ImperialUnits);
metricUnitsTableAdapter.Fill(DBProj.MetricUnits);
When I want to add a record to my database, this code invokes:
private void addStat(double input, double output)
{
DataSetProj.ConvertersRow usedConverter = DBProj.Converters.Where(x => x.NameOf == (ConvertersList.SelectedItem as IConverter).ToString()).First();
DataSetProj.MetricUnitsRow metricUnit;
// this if statement exists, because ConvertLength has multiple metric units, like kilometre, metre, etc.
if (ConvertersList.SelectedItem is ConvertLength)
{
metricUnit = DBProj.MetricUnits.Where(x => x.NameOf == BoxUnitChoice.SelectedItem.ToString()).First();
}
else
{
metricUnit = DBProj.MetricUnits.Where(x => x.NameOf == (ConvertersList.SelectedItem as IConverter).MetricUnit(true)).First();
}
DataSetProj.ImperialUnitsRow imperialUnit = DBProj.ImperialUnits.Where(x => x.NameOf == (ConvertersList.SelectedItem as IConverter).ImperialUnit(true)).First();
DBProj.Stats.AddStatsRow(DBProj.Stats.Count, DateTime.Now, (metricToImperial ? 1 : 0), metricUnit, imperialUnit, usedConverter, input, output);
}
And it works - DBProj.Stats.Count increases every time a record is added. However, when I switch to the tab with the data grid (TabStats), it does not show any stats at all. It uses StatsView as a source, not Stats directly (or at least that's how I want it to work).
This code invokes when I switch to TabStats:
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if ((Tabs.SelectedItem as TabItem) == TabStats)
{
DBProj.Stats.AcceptChanges();
statsViewTableAdapter.Fill(DBProj.StatsView);
//neither of these 2 lines populate my datagrid
StatsDataGrid.ItemsSource = DBProj.StatsView;
//StatsDataGrid.ItemsSource = statsViewTableAdapter.GetData();
MessageBox.Show($"{DBProj.Stats.Count} this is stat count\n{DBProj.StatsView.Count} and this is statsView", "test");
}
}
Here's the output of the message box after I input a couple of values (note data grid is empty):
To my knowledge, it looks like the data is stored locally in DBProj.Stats table, but is not sent back to my database (where StatsView attempts to get data from). However, isn't .AcceptChanges() supposed to send any changes I made?
How do I send data back to the database using WPF .NET 5.0? All tutorials I found either used EF or only ever referenced .AcceptChanges() method.
EDIT: I forgot to add, but the data is never saved in the database - every time I run the program, Stats is empty. I want it to save when I switch to TabStats tab, as stated above.
Thanks to inspiration from #Andy, I managed to solve the issue. Instead of using .AcceptChanges() on the Data table, I had to .Update() Data table adapter - I found this doc, which explains how to add data to an existing data table using SQL INSERT command. Here's the working code:
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if ((Tabs.SelectedItem as TabItem) == TabStats)
{
//DBProj.Stats.AcceptChanges();
statsTableAdapter.Update(DBProj.Stats);
statsViewTableAdapter.Fill(DBProj.StatsView);
StatsDataGrid.ItemsSource = DBProj.StatsView;
//StatsDataGrid.ItemsSource = statsViewTableAdapter.GetData();
MessageBox.Show($"{DBProj.Stats.Count} this is stat count\n{DBProj.StatsView.Count} and this is statsView", "test");
}
}

Changing column name dynamically

I have a Header / Detail custom screen where I'm manipulating which grid columns display based on a dropdown selection in the header. This works fine, but now I'd like to change a few column names as well. Using the documented syntax, I cannot get this to work. I can't see what I'm doing wrong - nothing seems to make any difference. I've attached to process and put a break point at this event, and it's hitting the line - but the system seems to just ignore it:
protected virtual void ACMappingHeader_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
var mh = (ACMappingHeader)e.Row;
if (mh == null) return;
if (mh.MappingType == "Option1")
{
PXUIFieldAttribute.SetDisplayName<ACMappingDetail.target1CD>(this.MappingDetail.Cache, "Target");
Thanks...
Your display name routine looks correct however to make sure the column names actually update you need to do the following:
In the page source, you need to set the "RepaintColumns=true" value on the grid. This can be done via customization manager or directly from your ASPX source. - This tells the grid to refresh the columns after a callback allowing the headers to actually redisplay.
You can refer below example to dynamically change Grid Column Header.
Below example works with Screen PM401000 – Project Transactions Inquiry
public class TransactionInquiryExt : PXGraphExtension<TransactionInquiry>
{
public void TranFilter_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected baseInvoke)
{
if (baseInvoke != null)
baseInvoke(cache, e);
PX.Objects.PM.TransactionInquiry.TranFilter row = e.Row as PX.Objects.PM.TransactionInquiry.TranFilter;
if (row == null) return;
PXUIFieldAttribute.SetDisplayName<PMTran.description>(Base.Transactions.Cache,
row.ProjectID.HasValue ? "Description for Project Tran" : "Description");
}
}
Make sure to set RepaitColumns property to True of PXGrid Control.

Generic list of Objects, passed through a HTML text writer class to output html. Now trying to implement paging

I have a list of objects which have been taken form a stored procedure. I then take this list pass it through a method I created which wraps it in HTML and then out puts to the webform.
I'm looking to create paging for this list. I have stored the list in a session and have two buttons ( next and previous ) I'm using LINQ to skip and take form the list on each button click.
Button Click
protected void lnkNext_Click(object sender, EventArgs e)
{
ListOfAdvertAndUsers = (List<Advert_User>)Session["list"];
var list = from item in ListOfAdvertAndUsers select item;
var pgNo = 1;
var pgRec = 6;
list = list.Skip(pgRec * pgNo).Take(pgRec).ToList();
ListOfAdvertAndUsers = list.ToList();
PopulateData(ListOfAdvertAndUsers);
}
I don't have enough rep to make a comment so I will just post my comments as an answer.
I presume that you are using Asp.Net WebForms, so how are you outputting the final html, Response.Write or setting Text on a Literal?
But if you are using WebForms, would it not be easier to use some of the builtin Controls. I don´t exactly know how your data looks like, but maybe a GridView would be a good solution as it has builtin support for paging. Here is an example from MS on how it can be used: http://www.asp.net/web-forms/overview/presenting-and-managing-data/model-binding/sorting-paging-and-filtering-data
Not a direct answer, but you're overwriting queries and lists, which seem to convolute the code unnecessarily. Your method could be simplified to:
protected void lnkNext_Click(object sender, EventArgs e)
{
ListOfAdvertAndUsers = (List<Advert_User>)Session["list"];
var pgNo = 1; // don't you need to increment the page number somewhere?
var pgRec = 6; // should this be defined somewhere other than this method?
var page = ListOfAdvertAndUsers.Skip(pgRec * pgNo).Take(pgRec);
PopulateData(page);
}
Perhaps that will help you determine what the real problem is...

How to bind data to telerik muticolumn combo box?

I'm trying to add a dataset into it for binding but i couldn't do it cause i get some errors that lead me to undo everything that i had done
i read telerik site and i studied their program too but it didn't help at all
in their site this was the code for binding
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
NwindDataSet nwindDataSet = new NwindDataSet();
CustomersTableAdapter customersTableAdapter = new CustomersTableAdapter();
customersTableAdapter.Fill(nwindDataSet.Customers);
this.radMultiColumnComboBox1.DataSource = nwindDataSet.Customers;
foreach (GridViewDataColumn column in this.radMultiColumnComboBox1.MultiColumnComboBoxElement.Columns)
{
column.BestFit();
}
}
void SetUpGrid()
{
RadGridView gridViewControl = this.radMultiColumnComboBox1.EditorControl;
gridViewControl.MasterTemplate.AutoGenerateColumns = false;
gridViewControl.Columns.Add(new GridViewTextBoxColumn("CustomerID"));
gridViewControl.Columns.Add(new GridViewTextBoxColumn("ContactName"));
gridViewControl.Columns.Add(new GridViewTextBoxColumn("ContactTitle"));
gridViewControl.Columns.Add(new GridViewTextBoxColumn("Country"));
gridViewControl.Columns.Add(new GridViewTextBoxColumn("Phone"));
}
is this code enough?
can someone pls help me with it
That's the programatically way to do it. If you have a bindingsource you can bind it with a pair of clicks, if not you can do it manual passing the values to the DatSource property
BUT, if you wanna add it to a gridview you can do it using the editor of RadGridView, and bind it in the same way as described above
Seems that you don't have clear how do it programatically, so I recomend you the easy way: do it with the RadMultiColumnBox Task (1st image) or RadGridViewEditor (2nd image), depend if you need it in a grid
I would also suggest looking in the column documentation: link

EF Don't save using IQueryable in BindingSource

I've created a code first context with a DbSet property
I work with Windows form. If I bind as follow:
_context.Schedules.Load();
scheduleBindingSource.DataSource = _context.Schedules.Local.ToBindingList();
All works great and when I save as follow:
this.Validate();
scheduleBindingSource.EndEdit();
_context.SaveChanges();
The data persists; But when I bind the data like this:
var res = _context.Schedules.Where(k => k.EmployeeName.Equals(employeeComboBox.Text)).ToList();
scheduleBindingSource.DataSource = res;
When I save data doesn't persis!
I'm thinking that the ToList() method is not good, but I can't find alternative to get a BindingList connected to the Local set of data inside the context.
Thanks,
Andrea
You can try this:
_context.Schedules.Where(k => k.EmployeeName.Equals(employeeComboBox.Text)).Load();
scheduleBindingSource.DataSource = _context.Schedules.Local.ToBindingList();
That should only bring the schedules that meet the condition. When you call the Load method after the Where method, it is going to bring to memory only the records that meet the condition. Later, when you call the Local property,it will give you an ObservableCollection<Schedule> that contains all the objects that are currently tracked by the DbContext which thy are going to be the elements you loaded before. At the end, when you call the ToBindingList extension method, it will returns an BindingList<Schedule> that stays in sync with the given ObservableCollection<Schedules>.
The reason that caused the non-persistance of the data is caused by DataGridView (or the BindingSource), that don't add to context the new istance of the just added row.
So I've disabled the AllowUserToAddRow property (now I'm using BindingNavigator Add Button)
And implemented these two events as follow:
private void scheduleBindingSource_AddingNew(object sender, AddingNewEventArgs e)
{
_scheduleAdding = true;
}
private void scheduleBindingSource_CurrentChanged(object sender, EventArgs e)
{
if (_scheduleAdding)
{
Schedule s = (Schedule)scheduleBindingSource.Current;
s.EmployeeName = employeeComboBox.Text;
s.From = new DateTime(dateTimePicker1.Value.Year, dateTimePicker1.Value.Month, 1);
_context.Schedules.Add(s);
_scheduleAdding = false;
}
}

Categories