I'm creating a WPF C# application that has a datagrid hooked up to a SQL Server database. The user has the option of editing data in the datagrid by highlighting a row and clicking an edit button which then populates several textboxes with the data from the highlighted row. At this point, the user can then edit the data, click save and the datagrid reflects the changes. Until recently that feature was working fine. However, I was asked to add a feature that displays a highlighted row of data somewhere else on the screen (as looking at a datagrid for too long can become tiresome). So when a user clicks on a row a series of textblocks to the right of the datagrid change to show the data of the highlighted row in an easier to view format. That feature also works fine. The issue I'm having now, is that when a row is highlighted and automatically displays the data in the textblocks, if the user also tries to edit that row, the application crashes. The data displays just fine in the textboxes after the user clicks edit (while simultaneously displaying the same highlighted row in the textblocks); it's just when save is clicked that I run into an issue.
Debugging the program shows that everything is running smoothly. However after clicking save, the debugger jumps back up to my myGridSelectionChanged event and say's "NullReferenceException was unhandled -- Object reference not set to instance of an object" When I reload the program however, the datagrid reflects the changes that I tried to make before the application crashed. I'm assuming that means that the issue doesn't have to do with actually editing the database, rather the problem is with the textblocks not being able to reflect those edits. Below is some of my code:
Here is the code for the save button:
private void saveBtn_Click(object sender, RoutedEventArgs e)
{
var stqmDC = new SqtmLinqDataContext();
var selectedRow = EditGrid.GetSelectedRow(myGrid);
var ID = EditGrid.GetCell(myGrid, selectedRow, 0);
string selectedID = ((TextBlock)ID.Content).Text;
int convertedID = Convert.ToInt32(selectedID);
int newQuantity = int.Parse(quantityTxt.Text);
var query = from info in stqmDC.General_Infos
where info.Quote_ID == convertedID
select info;
foreach (General_Info info in query)
{
info.Customer_Name = customerNameTxt.Text;
info.OEM_Name = oemNameTxt.Text;
info.Qty = newQuantity;
info.Quote_Num = quoteNumberTxt.Text;
info.Fab_Drawing_Num = fabDrawingNumTxt.Text;
info.Rfq_Num = rfqNumberTxt.Text;
info.Rev_Num = revNumberTxt.Text;
}
try
{
stqmDC.SubmitChanges();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
var mainTable = from generalInfo in stqmDC.GetTable<General_Info>()
select new
{
generalInfo.Quote_ID,
generalInfo.Open_Quote,
generalInfo.Customer_Name,
generalInfo.OEM_Name,
generalInfo.Qty,
generalInfo.Quote_Num,
generalInfo.Fab_Drawing_Num,
generalInfo.Rfq_Num,
generalInfo.Rev_Num
};
myGrid.ItemsSource = mainTable;
leftSP.Visibility = Visibility.Hidden;
rightSP.Visibility = Visibility.Hidden;
cancelBtn.Visibility = Visibility.Hidden;
submitBtn.Visibility = Visibility.Hidden;
saveBtn.Visibility = Visibility.Hidden;
sendBtn.Visibility = Visibility.Hidden;
}
And the code for displaying the highlighted row in textblocks:
private void myGridSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var rowSelection = EditGrid.GetSelectedRow(myGrid);
var quoteID = EditGrid.GetCell(myGrid, rowSelection, 0);
string quoteIDEdit = ((TextBlock)quoteID.Content).Text;
QuoteIDtxtblk.Text = quoteIDEdit;
var date = EditGrid.GetCell(myGrid, rowSelection, 1);
string dateEdit = ((TextBlock)date.Content).Text;
Datetxtblk.Text = dateEdit;
var custName = EditGrid.GetCell(myGrid, rowSelection, 2);
string custNameEdit = ((TextBlock)custName.Content).Text;
CustomerNametxtblk.Text = custNameEdit;
var OemName = EditGrid.GetCell(myGrid, rowSelection, 3);
string OemNameEdit = ((TextBlock)OemName.Content).Text;
OemNametxtblk.Text = OemNameEdit;
var Quantity = EditGrid.GetCell(myGrid, rowSelection, 4);
string QuantityEdit = ((TextBlock)Quantity.Content).Text;
Quantitytxtblk.Text = QuantityEdit;
var quoteNum = EditGrid.GetCell(myGrid, rowSelection, 5);
string quoteNumEdit = ((TextBlock)quoteNum.Content).Text;
QuoteNumbertxtblk.Text = quoteNumEdit;
var fabDrawing = EditGrid.GetCell(myGrid, rowSelection, 6);
string fabDrawingEdit = ((TextBlock)fabDrawing.Content).Text;
FabDrawingNumbertxtblk.Text = fabDrawingEdit;
var rfqNum = EditGrid.GetCell(myGrid, rowSelection, 7);
string rfqNumEdit = ((TextBlock)rfqNum.Content).Text;
RfqNumbertxtblk.Text = rfqNumEdit;
var revNum = EditGrid.GetCell(myGrid, rowSelection, 8);
string revNumEdit = ((TextBlock)revNum.Content).Text;
RevNumbertxtblk.Text = revNumEdit;
}
Thanks in advance to anyone who can help.
Where exactly would you think it's handled?
To handle exceptions that cause app crashes you need to exception-proof every "entry point", defined as every spot in your app where unmanaged code can call in or a the code starts running on a different thread.
This includes button click handlers. Add a try/catch in your button handler and show some UI message that an error happened and write a log message or at least a 'Debug.WriteLine(exceptionObjectHere);' so you can see where did the exception come from
You change ItemsSource of a DataGrid in saveBtn_Click which means that your selection will disapear and SelectionChanged will be fired.
So you need to handle this case (myGrid.SelectedItem == null) somewhere, and just do nothing (return) if so.
Related
This is my Form 1
When I click on the last row it shows data on the second grid control, Now I Want to Show this Data on the following Form (form 2 (Form with Purchase Written on Orange Color)) datagridview How can I do this.
table.Columns.Add("Item Name", Type.GetType("System.String"));
table.Columns.Add("Main Qty", Type.GetType("System.Decimal"));
table.Columns.Add("Price", Type.GetType("System.Decimal"));
table.Columns.Add("Per", Type.GetType("System.String"));
table.Columns.Add("Basic Amount", Type.GetType("System.Decimal"));
table.Columns.Add("Dis Amount", Type.GetType("System.Decimal"));
table.Columns.Add("Dis Percentage", Type.GetType("System.Decimal"));
table.Columns.Add("Tax Amount", Type.GetType("System.Decimal"));
table.Columns.Add("Net Value", Type.GetType("System.Decimal"));
dataGridView1.DataSource = table;
Above is the Form Load of (form 2)
And Below is the RowClick of Form 1
private void gridView1_RowClick(object sender, DevExpress.XtraGrid.Views.Grid.RowClickEventArgs e)
{
try
{
FRM_Purchase frm = new FRM_Purchase();
var ctx = new BizPlusEntities();
int GettingIdForShowing = (int)gridView1.GetRowCellValue(e.RowHandle, "PurchaseID");
var GettinginToDatabase = ctx.Purchases.Where(x => x.PurchaseID == GettingIdForShowing).ToList();
foreach (var item in GettinginToDatabase)
{
frm.txtPartyName.Text = item.PartyName;
frm.txtDate.Text = item.Date.ToString();
frm.txtTerms.Text = item.Terms;
frm.txtSeries.Text = item.Series;
frm.txtDueDate.Text = item.DueDate.ToString();
frm.txtPinvoice.Text = item.Pinvoice.ToString();
UniqueIdentifier = item.UniquePurchaseNumber;
string SelectingUniqueIdentfier = ctx.Purchases.SingleOrDefault(x => x.PurchaseID == item.PurchaseID)?.UniquePurchaseNumber ?? "Nulled";
var GettingInItems = ctx.ItemPurchaseDatas.Where(x => x.UniquePurchaseNumber == SelectingUniqueIdentfier).ToList();
foreach (var Sam in GettingInItems)
{
TItemName = Sam.ItemName;
TMainQty = Sam.MainQty ?? 0;
TPrice = Sam.Price ?? 0;
TPer = Sam.Per;
TBasicAmount = Sam.BasicAmount ?? 0;
TDisAmt = Sam.DisAmount ?? 0;
TDisP = Sam.DecimalPercentage ?? 0;
TTaxAmount = Sam.Gst ?? 0;
TTotalAmount = Sam.TotalAmount ?? 0;
}
frm.Show();
}
}
catch (Exception)
{
throw;
}
}
The problem is When I do frm.Table.Rows.Add(TItem,TMainQty...) on Form1
it shows input array is longer than the number of columns in this table
and when I create a new column it says the column already exists.
My advice would be to separate your data from the way that the data is displayed. Apart from that this makes it easier to unit test your data handling, it gives the displayer of the data the freedom to change how this data is being displayed.
In WPF this separation of model and view is almost forced, in Winforms you really have to pay attention otherwise you mix your data handling with the way that it is displayed, making it hard to change this.
In your case: should Form1 care about how the data is displayed in Form2, should it know that Form2 uses a DataGridView? Or should Form1 only care about what data is displayed in Form2, not in what format?
A proper interface with Form2 would be, that other Forms tell what data should be displayed, and if the data can be changed, that the other Form can ask afterwards the value of the data. Something like this:
private void ShowForm2()
{
var dataToShow = this.FetchDataToShow();
using (var dlg = new Form2())
{
dlg.Data = dataToShow;
var dlgResult = dlg.ShowDialog(this);
if (dlgResult == DialogResult.OK)
{
var dataToProcess = dlg.Data;
this.ProcessData(dataToProcess);
}
}
}
This way, you only tell Form2 what data to show, other forms don't really care about how Form2 shows its data. This gives Form2 the freedom to change how the data is displayed. Every user of this Form will have the same human interface.
By the way: did you notice that I also separated where Form1 gets the data for Form2 from and where it stores the results? This procedure also does not care about how the data is displayed in Form1, and gives you the freedom to change Form1, without having to change this procedure.
Use Databinding
It is usually way easier to use DataBinding to handle the rows in a DataGridView than to access the rows and the cells of the DataGridView directly.
To use databinding, your columns need to know which property of your Class should be displayed in this column. This is usually done in visual studio designer.
In your case, it seems that the DataGridView of Form2 needs to show ItemPurchaseDatas: every Row in the DataGridView will show several properties of one ItemPurchaseData. Using visual studio designer you will have added columns, and in every column you select the name of the property that needs to be displayed in that column:
DataGridView dataGridView1 = new DataGridView();
DataGridViewColumn columnName = new DataGridViewColumn();
columName.HeaderText = "Item Name";
columName.DataPropertyName = nameof(ItemPurchaseData.Name);
...
DataGridViewColumn columnPrice = new DataGridViewColumn();
columnPrice.HeaderText = "Price";
columnPrice.DataPropertyName = nameof(ItemPurchaseData.Price);
...
We earlier saw that the dialog had a property Data, that contains the data to be shown.
The form needs a method to extract the ItemPurchaseDatas that must be shown in the DataGridView:
public IEnumerable<ItemPurchaseData> GetInitialItemPurchaseDatas()
{
// TODO: use property Data to extract the ItemPurchaseDatas that must be shown
// in the DataGridView
}
Now all you have to do is on the event handler of FormLoad, get the data and put it in the DataSource of dataGridView1:
private void OnFormLoading(object sender, ...)
{
List<ItemPurchaseData> itemPurchaseDatas = GetInitialItemPurchaseDatas().ToList();
this.dataGridView1.DataSource = itemPurchaseDatas;
}
This is enough to show the data. However, it will be readonly: any changes that the operator makes: edits, addition of rows, removal of rows etc, are not reflected in itemPurchaseDatas. If you want that, you need an object that implements IBindingList like BindingList<T>.
If you want to know the changes that the operator made, it is usually wise to add the following methods:
private BindingList<ItemPurchaseData> DisplayedData
{
get => (BindingList<ItemPurchaseData>)this.dataGridView1.DataSource;
set => this.dataGridView1.DataSource = value;
}
Now every change that the operator makes to the displayed data: add / remove rows, change cells, etc are reflected in property DisplayedData. Again, the display of the data is separated from the data itself: If the operator changes the looks of how the data is displayed, sorting the rows, rearranging the columns has no influence on the DisplayedData.
If you regularly have to handle SelectedRows, consider to add the following properties:
private ItemPurchaseData CurrentItemPurchaseData =>
(ItemPurchaseData)this.dataGridView1.CurrentRow?.DataBoundItem;
private IEnumerable<ItemPurchaseData> SelectedItemPurchaseData =>
this.dataGridView1.DataSource.SelectedRows.Cast<DataGridViewRow>()
.Select(row => row.DataBoundItem)
.Cast<ItemPurchaseData>();
Usage: on form loading displaying the data in the DataGridView and after a button press process the edited data:
private void OnFormLoading(object sender, ...)
{
IEnumerable<ItemPurchaseData> itemPurchaseDatas = GetInitialItemPurchaseDatas();
this.DisplayedData = new BindingList<ItemPurchaseData>(itemPurchaseDatas.ToList());
}
private void OnButtonOk_Clicked(object sender, ...)
{
ICollection<ItemPurchaseData> editedData = this.DisplayedData;
// if needed: check which items are changed
this.ProcessChangedData(editedData);
}
Again: due to the separation of view and model, the code in the view are one-liners
If you only want to Display the data, it is
I am trying to load multiple DataTables into DataGridViews in separate tabpages of a TabControl, the DataTables are stored in a Dictionary which is in turn stored in a DataObject class.
I can get everything displaying correctly but when I try to add loop through the Datagridview Header to add a contextmenustrip, for some reason I can get it to work for the first DataGridView but subsequent DataGridViews do not have the context menu applied? I have tried adding a print statentment just before the foreach loop and the DataGridView gets a column count of zero…so im guessing that’s why the foreach loop isn’t doing anything…but all the data is still displayed correctly in the dataGridViews in their respective tabs…any help in pointing out what I’m missing would be greatly appreciated.
Regards
Amarino
Code given below
List<ImportObject> lImportObjects = new List<ImportObject>();
private void loadImportFilesToScreen(List<ImportObject> lImportObjects)
{
foreach (ImportObject lImportObject in lImportObjects) {
DisplayImportFiles(lImportObject);
}
}
public void DisplayImportFiles(ImportObject pImportObject)
{
string lTabName="";
//load DataGridView with DataTable
/*
foreach (KeyValuePair<string, DataTable> lDT in pImportObject.DataTableDictionary)
{
lTabName = DisplayTabsInApp(pImportObject.FileName + "_" + lDT.Key, lDT.Key);
LoadDatatableIntoGrid(lDT.Value, lTabName);
}
*/
for (int i = 0; i < pImportObject.DataTableDictionary.Count; i++)
{
KeyValuePair<string, DataTable> lItem = pImportObject.DataTableDictionary.ElementAt(i);
string lKey = lItem.Key;
DataTable lDT = lItem.Value;
lTabName = DisplayTabs(pImportObject.FileName + "_" + lKey, lKey);
LoadDatatableIntoGrid(lDT, lTabName);
lDT = null;
}
}
public string DisplayTabs(string pTabName, string pSheetName)
{
// Create a new Tab Page for this file. Set heading, set name.
TabPage lTabPage_NewFile = new TabPage();
lTabPage_NewFile.Text = pTabName;
lTabPage_NewFile.Name = "TAB_PAGE_" + pTabName;
tabControl_ImportFiles.TabPages.Add(lTabPage_NewFile);
return lTabPage_NewFile.Name;
}
public void LoadDatatableIntoGrid(DataTable pDataTable, string pTabName) {
DataGridView lDGV = new DataGridView();
lDGV.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing;
lDGV.RowHeadersVisible = false;
BindingSource BindingSource1 = new BindingSource(); //create new data binding source
BindingSource1.DataSource = pDataTable; //SetData source
lDGV.DataSource = BindingSource1;
lDGV.RowHeadersVisible = true;
tabControl_ImportFiles.TabPages[pTabName].Controls.Add(lDGV);
//DataGridView lDGV = tabControl_ImportFiles.TabPages[pTabName].Controls[0] as DataGridView;
PrintToConsoleInARD("DataGridView Column Count: " + lDGV.Columns.Count.ToString());
bool runOnce = true;
foreach (DataGridViewColumn lDGVColumn in lDGV.Columns) {
lDGVColumn.HeaderCell.ContextMenuStrip = lCMS_ColumnHeaders;
}
lDGV.Dock = DockStyle.Fill;
lDGV.VirtualMode = true;
BindingSource1 = null;
lDGV = null;
}
I am confident the reason for this is because the “tab page” is not displayed. As the trace is described inside the LoadDatatableIntoGrid method… if you put a breakpoint at the line…
tabControl_ImportFiles.TabPages[pTabName].Controls.Add(lDGV);
Add a watch to the variable lDGV.Columns.Count… will show that IDGV has zero (0) columns. Execute the line above and magically, the grid IDGV has columns. This appears correct since this is the first “tab page” and it is the active (displayed) tab page. Point being… if you do not add the grid to a “Active/Shown/Displayed” tab page most UI code will be ignored. This is why the next time around; the grid will be empty because the grid is added to a non “active/shown/displayed” tab page.
A simple solution is to simply “Show” the tab page before you add the grid to it. This appears to fix the issue you describe. Add the line below before the line above…
tabControl_ImportFiles.TabPages[pTabName].Show();
Hope this helps.
Windows UWP app in C#. I have a method that checks a condition and depending on the condition, it may need to show a listview to the user so they can select an item from the list. I have more code in the method, after I potentially show the list view that needs to run after. However, because the listview shows and I have to wait for the SelectionChanged event handler to fire, I cannot figure out how to pause the calling method on that line until the event handler is completed for SelectionChanged. I don't have code written yet, so here is some pseduo code to illustrate:
private void LookupEmployee(string searchCriteria)
{
List<string> matches = GetEmployeeNameMatchesFromCriteria(searchCriteria);
if(matches.Count == null || matches.Count == 0)
{
//No matches found, warn user
return;
}
if(matches.Count == 1)
{
//We are good, we have just one match which is desirable.
}
if(matches.Count > 1)
{
//This means we have more than one match and we need to popup list view to have user select one
ShowListView(matches);
}
//Process Employee data here.
}
I know one option is to "daisy chain" calls by breaking out the final processing of employee data to another method and call that from the event handler for SelectionChanged of the listview. However, this has two issues. First, if I just have one match, then I will not be showing the listview or getting the SelectionChanged anyway. Second, if I had a bunch of variables and other things at the beginning of the method to be used at the end of the method, I don't want to (nor do I know how to) pass all of that through and back from the event handler in the event I need to show it.
I guess what I am looking for in a way is how the MessageDialog is handled.
var md = new MessageDialog("My Message");
md.Commands.Add(new UICommand("Okay")
{
});
var result = await md.ShowAsync();
if (result.Label == "Okay")
{
DoStuff;
}
Where using this will wait on the line:
await md.ShowAsync();
Until the user clicks the button, at which point the method can continue from there.
I guess I am looking for something similar to that where I can hold on the line of the method in the case that I need to show the listview until the user selects and item and grab the item that was selected.
Thoughts?
Thanks!
Okay, I think I found what I was looking for so I wanted to post the code. This is similar to how a modal window worked in the old days. Basically, you can use a ContentDialog which will allow you to "wrap" any controls you want in it. In my case, I want to show a ListView, so I wrap that in the ContentDialog. Here is what I have:
First we can do our tests and based on the tests, we can create the ContentDialog/ListView if needed. If we do create the ContentDialog, we can also setup the Display parameters so it fits the way we want it to.
private async void checkProductMatches()
{
var selectedItem = string.Empty;
//Check our results from DB.
if (productResults.Count == 0)
{
//This means we didn't find any matches, show message dialog
}
if (productResults.Count == 1)
{
//We found one match, this is ideal. Continue processing.
selectedItem = productResults.FirstOrDefault().Name;
}
if (productResults.Count > 1)
{
//Multiple matches, need to show ListView so they can select one.
var myList = new ListView
{
ItemTemplate = Create(),
ItemsSource =
productResults,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
var bounds = Window.Current.Bounds;
var height = bounds.Height;
var scroll = new ScrollViewer() { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, Height = height - 100 };
var grid = new StackPanel();
grid.Children.Add(myList);
scroll.Content = grid;
var dialog = new ContentDialog { Title = "Title", Content = scroll };
Now, we wire up the event handler for the ListView SelectionChanged event and grab the selectedItem should this event raise.
myList.SelectionChanged += delegate (object o, SelectionChangedEventArgs args)
{
if (args.AddedItems.Count > 0)
{
MyProducts selection = args.AddedItems[0] as MyProducts;
if (selection != null)
{
selectedItem = selection.Name;
}
}
dialog.Hide();
};
Finally, we await the showing of the ContentDialog.
var s = await dialog.ShowAsync();
What this will do is, if we have one item, there is no need to popup the content dialog. So, we can assign the one result to our selectedItem variable and proceed. However, if we have multiple matches, we want to display a list for the user to select the one item. In this case, we create the ContentDialog, ListView and display parameters. They key is to wire up the event handler before we call to show the dialog and inside of the event handler, we make sure to cancel or close the dialog. Then we call to await the dialog showing. This will pause execution of this method on that line while the dialog is showing. Once the user selects an item, the event handler will raise, get the selected item and then close the dialog, which will then allow the method to continue execution from the awaited line.
Here is the full method:
private async void checkProductMatches()
{
var selectedItem = string.Empty;
//Check our results from DB.
if (productResults.Count == 0)
{
//This means we didn't find any matches, show message dialog
}
if (productResults.Count == 1)
{
//We found one match, this is ideal. Continue processing.
selectedItem = productResults.FirstOrDefault().Name;
}
if (productResults.Count > 1)
{
//Multiple matches, need to show ListView so they can select one.
var myList = new ListView
{
ItemTemplate = Create(),
ItemsSource =
productResults,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
var bounds = Window.Current.Bounds;
var height = bounds.Height;
var scroll = new ScrollViewer() { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, Height = height - 100 };
var grid = new StackPanel();
grid.Children.Add(myList);
scroll.Content = grid;
var dialog = new ContentDialog { Title = "Title", Content = scroll };
myList.SelectionChanged += delegate (object o, SelectionChangedEventArgs args)
{
if (args.AddedItems.Count > 0)
{
MyProducts selection = args.AddedItems[0] as MyProducts;
if (selection != null)
{
selectedItem = selection.Name;
}
}
dialog.Hide();
};
var s = await dialog.ShowAsync();
}
//Test furter execution. Ideally, selected item will either be the one record or we will
//get here after the list view allows user to select one.
var stringTest = string.Format("Selected Item: {0}", selectedItem);
}
Hope this helps someone.
I am using c# and VS2012 on a lightswitch web-application,
I wish to export my data to CSV (on a search screen!), but can't reach any POC,
As i understand there are 2 main problems - a savefiledialog must be caused directly from a user button and in it must happened in the main dispatcher,
I used this code :
partial void mySearchScreen_Created()
{
var CSVButton = this.FindControl("ExportToCSV");
CSVButton.ControlAvailable += ExportCSV_ControlAvailable;
}
private void ExportCSV_ControlAvailable(object sender, ControlAvailableEventArgs e)
{
this.FindControl("ExportToCSV").ControlAvailable -= ExportCSV_ControlAvailable;
Button Button = (Button)e.Control;
Button.Click += ExportCSV_Click;
}
private void ExportCSV_Click(object sender, System.Windows.RoutedEventArgs e)
{
Microsoft.LightSwitch.Details.Client.IScreenCollectionProperty collectionProperty = this.Details.Properties.mySearch;
var intPageSize = collectionProperty.PageSize;
//Get the Current PageSize and store to variable
collectionProperty.PageSize = 0;
var dialog = new SaveFileDialog();
dialog.Filter = "CSV (*.csv)|*.csv";
if (dialog.ShowDialog() == true) {
using (StreamWriter stream = new StreamWriter(dialog.OpenFile())) {
string csv = GetCSV();
stream.Write(csv);
stream.Close();
this.ShowMessageBox("Excel File Created Successfully. NOTE: When you open excel file and if you receive prompt about invalid format then just click yes to continue.", "Excel Export", MessageBoxOption.Ok);
}
}
collectionProperty.PageSize = intPageSize;
//Reset the Current PageSize
}
private string GetCSV()
{
StringBuilder csv = new StringBuilder();
int i = 0;
foreach (var orderRow_loopVariable in mySearch) {
var orderRow = orderRow_loopVariable;
////HEADER
if (i == 0) {
int c = 0;
foreach (var prop_loopVariable in orderRow.Details.Properties.All().OfType<Microsoft.LightSwitch.Details.IEntityStorageProperty>()) {
var prop = prop_loopVariable;
if (c > 0) {
csv.Append(",");//Constants.vbTab
}
c = c + 1;
csv.Append(prop.DisplayName);
}
}
csv.AppendLine("");
////DATA ROWS
int c1 = 0;
foreach (var prop_loopVariable in orderRow.Details.Properties.All().OfType<Microsoft.LightSwitch.Details.IEntityStorageProperty>()) {
var prop = prop_loopVariable;
if (c1 > 0) {
csv.Append(",");//Constants.vbTab
}
c1 = c1 + 1;
csv.Append(prop.Value);
}
i = i + 1;
}
if (csv.Length > 0) {
return csv.ToString(0, csv.Length - 1);
} else {
return "";
}
}
This works, but it only get's me the first page items,
On another thing i had to do i solved that problem by using this code :
this.DataWorkspace.myDataContextData.MySearch(...).Execute();
Yet trying that instead of just using 'MySearch' gives me the following error :
t is not valid to call Execute() on a different Dispatcher than the ExecutableObject's Logic Dispatcher.
Why is it so difficult to do such a basic thing related to data (export to csv/excel) on a system build for handling data ?
Any ideas ?
The simplest workaround if this is the only use of the search screen would be to turn off paging. To do this go to the screen designer, highlight the query on the left, and in properties uncheck 'support paging.'
I'm not sure what the limitations are, but you can run some code in a different dispatcher using:
this.Details.Dispatcher.BeginInvoke(() =>
{
//This runs on main dispatcher
});
I don't think there's anything wrong with your code, but I've noticed that it takes a while to reset the page size on a large collection, in which time the rest of your code continues to execute. I think that's why you only get the first page. The only solution I've found is to wait.
When the "File Download - Security Warning" dialog pops up, keep an eye on the 'busy' indicator on the screen's tab and also the 'Page x of y' status at the bottom of the grid if you can see it. Only when the busy indicator has gone and the status just says 'Page' should you click OK to continue.
I haven't figured out a way of doing this programmatically so it's not a very helpful feature unless you have a very tightly controlled user population. But if it's just you and a couple of power users, it is workable. I'm also not sure if this has been improved on in versions after VS2012.
There can be a downside to the other answer of taking the paging off the query entirely. I've tried that workaround when the grid collection was being displayed in a modal window and the window became uncloseable if there were too many rows in the grid.
Phil
I have looked extensively to find an answer to this question but I only get extremely close. I have a web form that I use to add and edit records. When a record is selected in the gridview, a session variable is set and then used on page load to populate the text fields. If the session variable is not set, the form will be blank and the logic run as a new record. My problem is that I can add a new record successfully - I debugged and checked to make sure the asp controls passed the proper values to the code behind - but I cannot edit a record successfully. For some reason, the code behind file does not retrieve the proper values from the text boxes. Instead, it keeps the original populated values thus defeating the purpose of the edit. I imagine it is a binding issue but I am unsure and have searched upon end. Here is my code behind file:
protected void Page_Load(object sender, EventArgs e)
{
resultOutput.Visible = false;//Output results as to whether or not a record was added successfully is automatically hidden at page load
//Checking to see if session variable has been created
if (Session["editID"] != null)
{
//Create objects to get recipe data
dbCRUD db = new dbCRUD();
Recipe editRecipe = new Recipe();
//Grabbing session ID
var id = Convert.ToInt32(Session["editID"]);
//Call method to retrieve db data
editRecipe = db.SelectRecord(id);
//Populate results to text boxes
recordID.Text = editRecipe.Recipe_ID.ToString();
addName.Text = editRecipe.Name;
addTypeDDL.SelectedValue = editRecipe.Meal;
addDifficultyDDL.SelectedValue = editRecipe.Difficulty;
addCookTime.Text = editRecipe.Cook_Time.ToString();
addDirections.Text = editRecipe.Directions;
//Change Button Text
submitRecord.Text = "Edit Record";
//Change Title Text
addEditTitle.Text = "Edit Recipe";
}
}
protected void submitRecord_Click(object sender, EventArgs e)
{
Recipe recipe = new Recipe();
dbCRUD newRecord = new dbCRUD();
//Variables for execution results
var modified = "";
int returned = 0;
//Creating the recipe Object to pull the values from the form and
//send the recipe object as a parameter to the method containing insert stored procedure
//depending on Add or Edit
//recipe.Recipe_ID = int.Parse(recordID.Text);
recipe.Name = addName.Text.ToString();
recipe.Meal = addTypeDDL.SelectedValue.ToString();
recipe.Difficulty = addDifficultyDDL.SelectedValue.ToString();
recipe.Cook_Time = int.Parse(addCookTime.Text);
recipe.Directions = addDirections.Text.ToString();
//Checking to see if the page is loaded for edit or new addition
if (Session["editID"] != null)
{
recipe.Recipe_ID = Convert.ToInt32(Session["editID"]);
//If recordID exists, recipe will be passed to UpdateRecord method
returned = newRecord.UpdateRecord(recipe);
modified = "has been edited.";
Session.Remove("editID");
}
else
{
//If recordID does not exist, record will be passed to InsertRecord method (new recipe)
returned = newRecord.InsertRecord(recipe);
modified = "added";
}
//Method returns 0 if successful, 1 if sql error, 2 if other error
if (returned == 1)
{
resultOutput.Text = "There was an sql exception";
resultOutput.Visible = true;
}
else if (returned == 2)
{
resultOutput.Text = "There was a non sql exception";
resultOutput.Visible = true;
}
else
{
resultOutput.Text = "\"" + addName.Text + "\" recipe " + modified;
resultOutput.Visible = true;
}
}
Any object passed to my edit method is successful, however, as I mentioned, it does not grab the newly updated text box values.
Did you try checking PostBack property , Your code is loading the data everytime the page is posted back. So when you update the values in the form and hit update button. The Page_Load method is called first and it reloads all the data (replaces your updated values on the form) and then hit the update button event handler. So everytime your old values are being saved.
You may remove the code from page_load method and put it where you are setting the Session["EditId"] value. This will solve your problem.
I would suggest using a static dataset and bind it to the recordsource of the gridview control. Whenever you wanna edit a record update the dataset simultaneously and rebind it to the gridview control....hope that helps:)