Immediately update DataGridViewCheckBoxCell - winforms

I am programmatically updating my WinForm DataGridView
Problem, DataGridViewCheckBoxCell doesn't get updated !!!
I was google, it seams like knowing case but whatever I've tried did not help yet.
private void InitializeFunctionsDataGrid()
{
System.Data.DataSet ds = func.GetFunctions();
this.FunctionsDataGrid.DataSource = ds.Tables[0];
this.FunctionsDataGrid.Columns["FunctionId"].Visible = false;
this.FunctionsDataGrid.Columns["DESCRIPTION"].Width = 370;
DataGridViewCheckBoxColumn column = new DataGridViewCheckBoxColumn();
column.Name = "enable";
column.HeaderText = "enable";
column.FalseValue = 0;
column.TrueValue = 1;
FunctionsDataGrid.Columns.Add(column);
foreach(DataGridViewRow row in FunctionsDataGrid.Rows)
{
(( DataGridViewCheckBoxCell)row.Cells["enable"]).Value = 1;
}
FunctionsDataGrid.CurrentCell = null;
}

enable is an unbound column. This means that you need to provide cell value yourself.
You can set the VirtualMode property to true and handle the CellValueNeeded event.
If you want to enable the user to check a cell then you need to handle the CellValuePushed event.
DataGridView samples that are part of the DataGridView FAQ has a specific example of an unbound checkbox column along with databound columns.

OK basically easiest way for me was to work with datasource.
I've add the column to the DataTable and fill it with data.
And then last thing this.FunctionsDataGrid.DataSource = ds.Tables[0];

Related

show blank in combobox bind to data base

i am binding my combobox to the database and i am able to populate the combobox from my database.But when i am opening the page the combobox contains one value by default from the database. I want to show blank in my combobox, How can do that?
my code:
datatable dt;
DataAccess.Connect();
dt = DataAccess.Select("select * from CompanyMainActivity");
cmbMainActivity.DisplayMember = ("name");
cmbMainActivity.ValueMember = "MainActivityCode";
cmbMainActivity.DataSource = dt;
I try this code, but in dosent work
cmbMainActivity.Items.Insert(0, "select name from CompanyMainActivity");
You can add a blank value at the first.
dt = DataAccess.Select("select name, MainActivityCode from CompanyMainActivity");
//Insert default row
DataRow dr = dt.NewRow();
dr["name"] = String.Empty;
dr["MainActivityCode"] = -1; //I have set -1 because it should not be duplicate and this record is fake. so, we can determine that the record is fake from the -1 value.
dt.Rows.InsertAt(dr, 0); //Insert the blank record at the top of the all records.
cmbMainActivity.DisplayMember = ("name");
cmbMainActivity.ValueMember = "MainActivityCode";
cmbMainActivity.DataSource = dt;
I guess what u r looking for are called place holders.Please refer these few links which might help.
[Combo box's different properties][1](http://www.dotnetperls.com/combobox)
[If u r using wpf controls][2](http://pwlodek.blogspot.in/2009/11/watermark-effect-for-wpfs-textbox.html)
[check this also][3](http://msdn.microsoft.com/en-us/library/windows/apps/bg182878.aspx)
Assuming you are using WPF
On the combobox's section on your xaml file add a SelectedIndex
<ComboBox>
...
SelectedIndex = -1
...
</ComboBox>

DataGridViewComboBoxCell Value Not Updating When Set Programmatically C# Winforms

I've read all the similiar posts about this darn control (DataGridViewComboBoxCell) and setting it's value programmatically but implementing all the suggestions hasn't worked. I could probably change the UI to get around this problem but I don't like to be beat!
private void PopulateAreaForRoleAssociation()
{
// If businessRoleList is null then no data has been bound to the dgv so return
if (businessRoleList == null)
return;
// Ensure businessArea repository is instantiated
if (businessAreaRepository == null)
businessAreaRepository = new BusinessAreaRespository();
// Get a reference to the combobox column of the dgv
DataGridViewComboBoxColumn comboBoxBusinessAreaColumn = (DataGridViewComboBoxColumn)dgvBusinessRole.Columns["BusinessArea"];
// Set Datasource properties to fill combobox
comboBoxBusinessAreaColumn.DisplayMember = "Name";
comboBoxBusinessAreaColumn.ValueMember = "Id";
comboBoxBusinessAreaColumn.ValueType = typeof(Guid);
// Fill combobox with businessarea objects from list out of repository
comboBoxBusinessAreaColumn.DataSource = businessAreaRepository.GetAll();
// loop through the businessRoles list which the dgv is bound to and get out each dgv row based upon the current id in the loop
businessRoleList.Cast<BusinessRole>().ToList().ForEach(delegate(BusinessRole currentRole)
{
DataGridViewRow currentRowForRole = dgvBusinessRole.Rows.Cast<DataGridViewRow>().ToList().Find(row => ((BusinessRole)row.DataBoundItem).Id == currentRole.Id);
// Get a reference to the comboBox cell in the current row
DataGridViewComboBoxCell comboBoxCell = (DataGridViewComboBoxCell)currentRowForRole.Cells[2];
// Not sure if this is necessary since these properties should be inherited from the combobox column properties
comboBoxCell.DisplayMember = "Name";
comboBoxCell.ValueMember = "Id";
comboBoxCell.ValueType = typeof(Guid);
// Get the business area for the current business role
BusinessArea currentAreaForRole = businessAreaRepository.FetchByRoleId(currentRole.Id);
// if the role has an associated area then set the value of the cell to be the appropriate item in the combobox
// and update the cell value
if (currentAreaForRole != null)
{
foreach (BusinessArea area in comboBoxCell.Items)
{
if (currentAreaForRole.Id == area.Id)
{
comboBoxCell.Value = area.Id;
dgvBusinessRole.UpdateCellValue(2, comboBoxCell.RowIndex);
}
}
}
});
}
The dgv is first bound to a binding list holding BusinessRole objects, then the combobox column is bound to a basic list of BusinessArea objects that come out of a repository class. I then loop through the bindinglist and pull out the row of the dgv that is bound to the current item in the bindinglist loop.
With that row I make a database call to see if the BusinessRole entity is associated with a BusinessArea entity. If it is then I want to select the item in the combobox column that holds the BusinessAreas.
The problem is that when the grid is loaded, all the data is there and the comboboxes are populated with a list of available areas, however any values that are set are not displayed. The code that sets the value is definately getting hit and the value I am setting definately exists in the list.
There are no data errors, nothing. It's just refusing to update the UI with the value I programmatically set.
Any help would be greatly appreciated as always.
Thanks
This code works for my first combo box I have in my row with the following code, but I try it with the next one in the row and it doesn't work. I could use the help with the rest I have 3 more to do. I do set the combo boxes on a second form from this form with the same code as is on the last line of the try block but using the cell information instead of the dataset
try
{
string strQuery = "select fundCode from vwDefaultItems where IncomeType = '" + stIncome + "'";
SqlDataAdapter daDefault = new SqlDataAdapter(strQuery, conn);
DataSet dsDefault = new DataSet();
daDefault.Fill(dsDefault);
strDefFund = dsDefault.Tables[0].Rows[0].ItemArray[0].ToString();
dgvCheckEntry.Rows[curRow].Cells[7].Value = dsDefault.Tables[0].Rows[0].ItemArray[0].ToString();
}
catch (Exception eq)
{
}

Add button column in a databound datagridview

i have a datagridview. i bound it to a list. now i want to show a column at the end of it. but that column apprear in wrong possition.
this is my code
grdPatientAppointment.DataSource = lst;
grdPatientAppointment.Columns["ID"].Visible = false;
//grdPatientAppointment.Columns["AdmitDate"].Visible = false;
//grdPatientAppointment.Columns["DischargeDate"].Visible = false;
grdPatientAppointment.Columns["AppointmentID"].Visible = false;
grdPatientAppointment.Columns["PatientrName"].DisplayIndex = 0;
grdPatientAppointment.Columns["Age"].DisplayIndex = 1;
grdPatientAppointment.Columns["Address"].DisplayIndex = 2;
grdPatientAppointment.Columns["ContactNo"].DisplayIndex = 3;
grdPatientAppointment.Columns["Dieseas"].DisplayIndex = 4;
grdPatientAppointment.Columns["AppointmentDate"].DisplayIndex = 5;
DataGridViewButtonColumn btnColumn = new DataGridViewButtonColumn();
btnColumn.HeaderText = "Treat";
btnColumn.Text = "Treat";
btnColumn.UseColumnTextForButtonValue = true;
grdPatientAppointment.Columns.Insert(6,btnColumn);
here is output:
but i want that button to the end of datagrid view
Add column instead of inserting it to the GridView. It will automaticallyy append it to the end of column collection.
grdPatientAppointment.Columns.Add(btnColumn);
Use DisplayIndex property to change the order of the columns:
http://msdn.microsoft.com/en-us/library/wkfe535h.aspx
just add code below
grdPatientAppointment.Columns.Insert(I, btnColumn)
I is index of column you want to add
Use grdPatientAppointment.AutoGenerateColumns = false;
Then add all columns your grid will receive from DataSource and bind them from editor.

Add a hyperlink column for a Winforms DataGrid control

How can I add a hyperlink column for a Winforms DataGrid control?
Right now I am adding a string column like this
DataColumn dtCol = new DataColumn();
dtCol.DataType = System.Type.GetType("System.String");
dtCol.ColumnName = columnName;
dtCol.ReadOnly = true;
dtCol.Unique = false;
dataTable.Columns.Add(dtCol);
I just need it to be a hyperlink instead of a String. I am using C# with framework 3.5
Use a DataGridViewLinkColumn.
The link shows an example of setting up the column and adding it to a DGV::
DataGridViewLinkColumn links = new DataGridViewLinkColumn();
links.UseColumnTextForLinkValue = true;
links.HeaderText = ColumnName.ReportsTo.ToString();
links.DataPropertyName = ColumnName.ReportsTo.ToString();
links.ActiveLinkColor = Color.White;
links.LinkBehavior = LinkBehavior.SystemDefault;
links.LinkColor = Color.Blue;
links.TrackVisitedState = true;
links.VisitedLinkColor = Color.YellowGreen;
DataGridView1.Columns.Add(links);
You'll probably be interested in this example that shows how the snippet above fits into a more complete example of configuring DGV columns at runtime.

How to maintain ComboBox.SelectedItem reference when DataSource is resorted?

This really seems like a bug to me, but perhaps some databinding gurus can enlighten me? (My WinForms databinding knowledge is quite limited.)
I have a ComboBox bound to a sorted DataView. When the properties of the items in the DataView change such that items are resorted, the SelectedItem in my ComboBox does not keep in-sync. It seems to point to someplace completely random. Is this a bug, or am I missing something in my databinding?
Here is a sample application that reproduces the problem. All you need is a Button and a ComboBox:
public partial class Form1 : Form
{
private DataTable myData;
public Form1()
{
this.InitializeComponent();
this.myData = new DataTable();
this.myData.Columns.Add("ID", typeof(int));
this.myData.Columns.Add("Name", typeof(string));
this.myData.Columns.Add("LastModified", typeof(DateTime));
this.myData.Rows.Add(1, "first", DateTime.Now.AddMinutes(-2));
this.myData.Rows.Add(2, "second", DateTime.Now.AddMinutes(-1));
this.myData.Rows.Add(3, "third", DateTime.Now);
this.myData.DefaultView.Sort = "LastModified DESC";
this.comboBox1.DataSource = this.myData.DefaultView;
this.comboBox1.ValueMember = "ID";
this.comboBox1.DisplayMember = "Name";
}
private void saveStuffButton_Click(object sender, EventArgs e)
{
DataRowView preUpdateSelectedItem = (DataRowView)this.comboBox1.SelectedItem;
// OUTPUT: SelectedIndex = 0; SelectedItem.Name = third
Debug.WriteLine(string.Format("SelectedIndex = {0:N0}; SelectedItem.Name = {1}", this.comboBox1.SelectedIndex, preUpdateSelectedItem["Name"]));
this.myData.Rows[0]["LastModified"] = DateTime.Now;
DataRowView postUpdateSelectedItem = (DataRowView)this.comboBox1.SelectedItem;
// OUTPUT: SelectedIndex = 2; SelectedItem.Name = second
Debug.WriteLine(string.Format("SelectedIndex = {0:N0}; SelectedItem.Name = {1}", this.comboBox1.SelectedIndex, postUpdateSelectedItem["Name"]));
// FAIL!
Debug.Assert(object.ReferenceEquals(preUpdateSelectedItem, postUpdateSelectedItem));
}
}
To clarify:
I understand how I would fix the simple application above--I only included that to demonstrate the problem. My concern is how to fix it when the updates to the underlying data rows could be happening anywhere (on another form, perhaps.)
I would really like to still receive updates, inserts, deletes, etc. to my data source. I have tried just binding to an array of DataRows severed from the DataTable, but this causes additional headaches.
Just add a BindingContext to the ComboBox :
this.comboBox1.DataSource = this.myData.DefaultView;
this.comboBox1.BindingContext = new BindingContext();
this.comboBox1.ValueMember = "ID";
this.comboBox1.DisplayMember = "Name";
By the way, try not keeping auto-generated names for your widgets (comboBox1, ...), it is dirty. :-P
The only promising solution I see at this time is to bind the combo box to a detached data source and then update it every time the "real" DataView changes. Here is what I have so far. Seems to be working, but (1) it's a total hack, and (2) it will not scale well at all.
In form declaration:
private DataView shadowView;
In form initialization:
this.comboBox1.DisplayMember = "Value";
this.comboBox1.ValueMember = "Key";
this.shadowView = new DataView(GlobalData.TheGlobalTable, null, "LastModified DESC", DataViewRowState.CurrentRows);
this.shadowView.ListChanged += new ListChangedEventHandler(shadowView_ListChanged);
this.ResetComboBoxDataSource(null);
And then the hack:
private void shadowView_ListChanged(object sender, ListChangedEventArgs e)
{
this.ResetComboBoxDataSource((int)this.comboBox1.SelectedValue);
}
private void ResetComboBoxDataSource(int? selectedId)
{
int selectedIndex = 0;
var detached = new KeyValuePair<int, string>[this.shadowView.Count];
for (int i = 0; i < this.shadowView.Count; i++)
{
int id = (int)this.shadowView[i]["ID"];
detached[i] = new KeyValuePair<int, string>(id, (string)this.shadowView[i]["Name"]);
if (id == selectedId)
{
selectedIndex = i;
}
}
this.comboBox1.DataSource = detached;
this.comboBox1.SelectedIndex = selectedIndex;
}
Must detach event handler in Dispose:
this.shadowView.ListChanged -= new ListChangedEventHandler(shadowView_ListChanged);
Your example sorts the data on the column it updates. When the update occurs, the order of the rows changes. The combobox is using the index to keep track of it's selected items, so when the items are sorted, the index is pointing to a different row. You'll need to capture the value of comboxBox1.SelectedItem before updating the row, and set it back once the update is complete:
DataRowView selected = (DataRowView)this.comboBox1.SelectedItem;
this.myData.Rows[0]["LastModified"] = DateTime.Now;
this.comboBox1.SelectedItem = selected;
From an architecture perspective, the SelectedItem must be cleared when rebinding the DataSource because the DataBinder don't know if your SelectedItem will persist or not.
From a functional perspective, the DataBinder may not be able to ensure that your SelectedItem from you old DataSource is the same in your new DataSource (it can be a different DataSource with the same SelectedItem ID).
Its more an application feature or a custom control feature than a generic databinding process.
IMHO, you have theses choices if you want to keep the SelectedItem on rebind :
Create a reusable custom control / custom DataBinder with a persistance option which try to set the SelectedItem with all your data validation (using a DataSource / item identification to ensure the item validity)
Persist it specifically on your Form using the Form/Application context (like ViewState for ASP.NET).
Some controls on the .NET market are helping you by rebinding (including selections) the control from their own persisted DataSource if the DataSource is not changed and DataBind not recalled. That's the best pratice.

Resources