[Note : I've simplified my example for clarity]
Let's say that I have a Sqlite database with two tables: Items and Sectors:
Items:
id_items : INTEGER PRIMARY KEY
name_item : VARCHAR(...)
id_sector : INTEGER
Sectors:
id_sector : INTEGER PRIMARY KEY
name_sector : VARCHAR(...)
I currently have a datagridview that is bound to the Items table. It gets fed alright, and the table displays the sector as a datagridviewcomboboxcolumns.
Hence, in my Winforms CustomControl, I have all the data loading and binding that occurs in the load() method:
colSector.DataSource = m_dataContext.SectorTable;
colSector.DisplayMember = "name_sector";
colSector.ValueMember = "id_sector";
ItemsGrid.DataSource = new DataView(m_dataContext.ItemsTable);
The comboboxes of my dataview are well loaded with the data from the Sectors table.
I now would like a button on my form that would allow the creation of a new sector:
I created a txtbox (txtNewSector) and a button that triggers the creation:
private void btnAddNewSector_Click(object sender, EventArgs e)
{
// Add new sector to db
m_dataContext.AddNewSector(newSectorName);
// refresh dataview so that comboboxes are updated with the new entry
???
}
How can I perform that refresh?
I hope the edit made the question more clear, please advise....
best regards
Instead of
???
add
ItemsGrid.DataSource = new DataView(m_dataContext.ItemsTable);
You can use a timer for that. It will accomplish the task after a certain time interval.
Have a look at the example Timer in C#.
You will find the idea of using it.
I am give some rough sketch
private DataTable LoadData()
{
DataTable dt = LoadDatabaseData();
return dt;
}
private void timer1_Tick(object sender, System.EventArgs e)
{
myDataGrid.DataSource = LoadData();
myDataGrid.Databind();
or
your combo box's datasource what ever.
}
Note- you are using SQLite regarding which I don't have any idea apart from it is a database. I have only showed you how to call the function that will be the datasource for your grid and after every 1 sec(I mean what ever time interval you specify) the datawill be refreshed.
Hope this helps.
Related
i am programming a piece of software for a loyalty scheme. I have basically finished all of it. The only thing i am stuck on for ages is programming the buttons for the datagridview which i am using for my redeem offers page. I have gotten it to add a button to the end of each row automatically when you add a new offer but i am clueless on how to program it to recognize each row.
for e.g.)
Row1) Offer 1 is X name and costs Y
Row2) offer 2 is Z Name and costs F
I can only seem to find the ability to program every single button at once and not individual and even so, i need it to work automatically so when i can add a offer i can immediately purchase it. How would i get it to recognize which row i am on?
here is what my form and database looks like.
Picture Of Form - (picture link)
What my database looks like - (picture link)
below ur class
make public int id;
//adding button
DataGridViewButtonColumn col = new DataGridViewButtonColumn();
col.UseColumnTextForButtonValue = True;
col.Text = "ADD";
col.Name = "Btn_add";
DataGridView1.Columns.Add(col);
//pass id values here to do functions..
private void Btn_add_Click(object sender, EventArgs e)
{
}
//this gets selected index of selected row value
private void DataGridView1_SelectionChanged(object sender, EventArgs e)
{
int id = DataGridView1.SelectedRows(0).Cells(0).Value;
}
In Datagrid please bind OfferId in buy button. When press button then automatically gives id onclick event.
You can simply hook into the RowDataBound Event. This event is called, each time a new entry is put into the table. At this point, you can add a button to the tabe and add a custom action/url to the url.
I'm writing a WPF application connected to a local Access database. In one of the application screens, one table data (named Service) is shown in individual textboxes, like a form, and the user can navigate through records, create new ones, delete, edit or search. Everything is done on the same table.
After a intensive research on how to navigate through records displayed in textboxes, I ended up using a DataSet and a CollectionView.
public partial class Entries : Window
{
AgendaDataSet agendaDataSet = new AgendaDataSet();
AgendaDataSetTableAdapters.ServiceTableAdapter serviceAdapter = new AgendaDataSetTableAdapters.ServiceTableAdapter();
CollectionView workSheetView;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.serviceAdapter.FillByDateAsc(agendaDataSet.Service);
this.DataContext = agendaDataSet.Service;
this.workSheetView = (CollectionView)CollectionViewSource.GetDefaultView(agendaDataSet.Service);
this.workSheetView.MoveCurrentToLast();
}
I got record navigation working using the CollectionView methods MoveCurrentToFirst(), MoveCurrentToNext(), etc. I also can create new records, edit and delete.
This is the method I use to create a new record:
private void btnNovo_Click(object sender, RoutedEventArgs e)
{
dynamic row = this.agendaDataSet.Service.NewMainRow();
this.agendaDataSet.Service.AddMainRow(row);
this.workSheetView.MoveCurrentToLast();
}
My problem is with record searching. I have a button that, when the user presses it, it asks for the PatientName he is searching. Then, the data about that Patient must appear on the various textboxes, ready to be consulted, edited or deleted.
Through the CollectionView, I only found the method GetItemAt() that gets a record based on it's row index. Since I am working with an Access database, I can't use the predicate ROW_NUMBER. And I don't think this approach would be the best.
So, how can I get an item based on it's ID, or PatientName, or any other field, and pass it as a row to the CollectionView?
Probably you don't need to get an item based on its ID or PatientName property.
Suppose that the user looks for "Andrew" as PatientName. Your code finds that the second row of your DataTable (called "Service") is the one the user is looking for.
You can use a simple static method to look for a DataRowView, something like this:
private static DataRowView FindDataRowView(DataView dataView, DataRow dataRow)
{
foreach (DataRowView dataRowView in dataView)
{
if (dataRowView.Row == dataRow)
{
return dataRowView;
}
}
return null;
}
and then you can select the object in your CollectionView:
collectionView.MoveCurrentTo(FindDataRowView(agendaDataSet.Service.DefaultView,
agendaDataSet.Service.Rows[2]));
Of course you can find the real DataRow index by using a foreach cycle or the Select method of DataTable.
I have a master-detail layout with a section of popup menus (the Details) and a section with a DataGridView which holds the rows.
The popup-menu state is updated when the selected row in the DataGridView changes and the state in the DGV's selected row should update when the popup-menu changes.
All of this works except the row in the DataGridView doesn't immediately update when I change the value of the popup-menu. I have to select a different row in order to see my edits.
I'm assuming this is because the edit hasn't been committed until the selection changes.
My question is: How do I make the change to the popup become immediately reflected in the DataGridView?
I have experimented with calling EndEdit() in the SelectionChangeCommitted handler for the popup-menu, but this has no effect. I'm interested in a technique that would allow me to create a DataGridView that would behave as if there were no Undo mechanism to begin with. Ideally the solution would be generic and transplantable to other projects.
It looks like existing answers work well with BindingSource. In my case, where DataTable was directly used as a DataSource, they didn't work for some reason.
// Other answers didn't work in my setup...
private DataGridView dgv;
private Form1()
{
var table = new DataTable();
// ... fill the table ...
dgv.DataSource = table;
}
After some hair-pulling, I got it work without adding BindingSource indirection:
// Add this event handler to the DataGridView
private void dgv_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
dgv.BindingContext[dgv.DataSource].EndCurrentEdit();
}
private Form1()
{
dgv.CellEndEdit += dgv_CellEndEdit;
// ...
}
Here's what was going on. The answer was in the properties of the ComboBox instances. I needed to change their DataSourceUpdateMode from OnValidation to OnPropertyChanged. This makes sense. The DataGridView was very likely showing the current state of the data. It was just that the data hadn't been edited yet because focus had not left the ComboBox, validating the input.
Thanks to everyone for your responses.
this works well for me:
private void CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
var dgw = (DataGridView) sender;
dgw.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
Use this extension method. It works for all columns types, not just ComboBoxes:
public static void ChangeEditModeToOnPropertyChanged(this DataGridView gv)
{
gv.CurrentCellDirtyStateChanged += (sender, args) =>
{
gv.CommitEdit(DataGridViewDataErrorContexts.Commit);
if (gv.CurrentCell == null)
return;
if (gv.CurrentCell.EditType != typeof(DataGridViewTextBoxEditingControl))
return;
gv.BeginEdit(false);
var textBox = (TextBox)gv.EditingControl;
textBox.SelectionStart = textBox.Text.Length;
};
}
This method commits every change just after the change is made.
When we have a text column, after typing a character, its value will commit to the DataSource and the editmode of the cell will end.
Therefore current cell should return to edit mode, and position of the cursor set to end of text in order to enable user to continue typing reminder of the text.
Call the DataGridView.EndEdit method.
following will work
_dataGrid.EndEdit()
s fine once you set the value.
when i click Add button i need to create gridview dynamically, where the gridview has to contain Textbox,DatePicker and dropdownlist.where as the values entered in each row of the gridview have to store it in database and retrive.
To get you started, an object is generally created dynamically in C# like this:
DataGridView g = new DataGridView();
The rest of the stuff you're asking - the textbox, datepicker, dropdownlist columns and reading/writing to the database - is quite involved and can't be answered here in any simple way.
You can just Bind the GridView onClick of Add Button
Like this
protected void btnADD_Click(object sender, EventArgs e)
{
objENT = new ENT();//using n-tier Architecture
objENT.ProcType = "ProcedureType";
DataSet ds = BLL.ProcessGrid(objENT);
GridviewDisplay.DataSource = ds;
GridviewDisplay.DataBind();//GridviewBind
}
I have used stored Procedure here,You can use any other methods as u wish
I have a windows forms application containing a datagridview control. The datagridview is populated by the contents of an xml file. At the moment, all of the columns are displayed as datagridviewtextboxcolumns. I want to select one that is populated by a particular xml tag and display it's content in a datagridviewcomboboxcolumn along with 2 other options.
EXAMPLE:
<SMS>
<Number>+447931663542</Number>
<DateTime>2009-07-12T17:00:02</DateTime>
<Message>YES</Message>
<FollowedUpBy>Unassigned</FollowedUpBy>
<Outcome>Resolved</Outcome>
</SMS>
The OUTCOME tag is the column that I would like to be displayed as a comboboxcolumn in the datagridview. If for example the tag is empty and contains no data, then I want to display nothing, but have the comboboxcolumn populated with 3 possible options to choose from (Unresolved, Resolved, Pending). If however the tag contains data, I want that particular item to be displayed in the comboboxcolumn, and have the other two options available to be selected.
Help in achieving this would be appreciated greatly!
Regards,
EDIT:
Currently I use this code:
colOutcome = new DataGridViewComboBoxColumn();
colOutcome.HeaderText = "Outcome";
colOutcome.Width = 90;
colOutcome.Items.AddRange("Resolved", "Unresolved", "Pending");
this.dataGridView1.Columns.Insert(1, colOutcome);
this.dataGridView1.Columns[1].Name = "OutcomeColumn";
This code above populates the combobox. THE PROBLEM IS: When The xml document populates the datagridview, the outcome column just appears as a textbox column, containing the data inbetween the outcome tags in the xml file. My point is, how can i get the datagridview to realise when it reads the outcome column that it needs to be changed into a combobox column and then display the data that way, along with the other potentially selectable options in the combobox?! Currently the datagridview gets populated with all columns as textboxcolumns containing the data, as well as a seperate combobox column which is not what I want. I need the application to merge the outcome column and its data with the code above.
Any ideas?
Updated Answer
You could pass in the XML document to a function that will loop through each node and determine whether it should be a ComboBox one or not i.e. if the name is "Outcome".
private void CreateColumns(XmlDocument doc)
{
foreach (...) // loop through each node in xml document
{
if (node.Name == "Outcome")
{
var items = new List<string>() { "Resolved", "Unresolved", "Pending" };
this.dataGridView1.Columns.Add(CreateComboBoxColumn(node.Name, items));
}
else
{
this.dataGridView1.Columns.Add(String.Format("col{0}", node.Name), node.Name);
}
}
}
Then your code for creating the Outcome column would be:
private DataGridViewComboBoxColumn CreateComboBoxColumn(string colHeaderText, List<string> items)
{
var colOutcome = new DataGridViewComboBoxColumn();
colOutcome.HeaderText = colHeaderText;
colOutcome.Width = 90;
colOutcome.Items.AddRange(items.ToArray());
colOutcome.Name = String.Format("col{0}", colHeaderText);
return colOutcome;
}
You would then just call CreateColumns on the form load event and pass in your XML. You should only need to create the columns once.
My advice would be to have a similar function that will find all the SMS elements and add a new row populating it with the information in each node.
public void MyForm_Load(object sender, EventArgs e)
{
var doc = new XmlDocument(filename);
CreateColumns(doc);
CreateRows(doc);
}
Hope that helps.
Answer #2 for me, based on the updated question.
The problem you are experiencing is with the AutoGeneratedColumns functionality of the DataGridView. You will need to create your columns manually before databinding. This can be done at design-time or run-time. I prefer design-time because it gives you a bit more direction with the look/feel of the grid but either way works.
You will need to disable the AutoGeneratedColumns property of the grid:
private void Form1_Load(object sender, EventArgs e)
{
// Define your columns at run-time here if that's what you prefer
this.dataGridView1.AutoGeneratedColumns = false;
this.dataGridView1.DataSource = myDataSource;
}
I'm not sitting in front of VS so this might not compile but should give you direction.
You need to either pre-populate the ResolvedColumn with the 3-4 possible values at design-time or assign it to another datasource at runtime. If you chose the design-time approach, simply open the DataGridView "Edit Columns" dialog, find the ResolvedColumn, go to Items, and add your values ("", "Unresolved", "Pending", "Resolved"). The empty value might help the ComboBox to render if there is the possiblity of rendering the grid with SMS records that have no Outcome.
To bind the possible options at runtime do something like this:
private List<string> _outcomeDataSource;
private void Form1_Load(object sender, EventArgs e)
{
_outcomeDataSource = new List<string>;
_outcomeDataSource.Add("");
_outcomeDataSource.Add("Unresolved");
_outcomeDataSource.Add("Pending");
_outcomeDataSource.Add("Resolved");
ResolvedColumn.DataSource = _outcomeDataSource;
ResolvedColumn.PropertyName = "Outcome";
}