|
Actually, I don't just have the issue mentioned above, I want to manipulate the datagridview minutely on multiple levels. I'll post all of them in this thread.
First, as I mentioned, I need to make individual cells (and not entire columns) in the DataGrid View read-only. Is this possible?
I have 3 columns. Based on the value of the first column (of only two possible values), I want to make either the second or the third column for that particular row as read-only.
pseudocode for my problem:
Event - cell value for column1 changed/ new value entered If column1.value = CStr("ab") Then column2 = readonly column3 = not readonly Else If column1.value = CStr("cd") Then column2 = not readonly column3 = readonly
My second problem is, I want to dynamically rearrange all columns alphabetically as each value is entered in column1 on each new row. For instance, if the table has 4 rows and the values for all cells in column1 are - ab ab cd cd; and then if anyone enters a fifth row to the datagridview, and starts by typing "ab" into column1, I want the entire thing to be reordered to read: ab ab ab 'which is the row that was just entered cd cd
Again, is this possible?
I'm using Visual Basic 2008 Express
| | reachrishikh Monday, February 02, 2009 4:37 PM |
Hi reachrishikh,
You can set the ReadOnly for each individual cell in DataGridView. Here is the sample code
| PublicClassForm1 |
| PrivatedtAsDataTable |
|
| PublicSubNew() |
| 'ThiscallisrequiredbytheWindowsFormDesigner. |
| InitializeComponent() |
|
| 'AddanyinitializationaftertheInitializeComponent()call. |
| dt=NewDataTable() |
| dt.Columns.Add("Column1") |
| dt.Columns.Add("Column2") |
|
| dt.Rows.Add(1,"Item1") |
| dt.Rows.Add(2,"Item2") |
| dt.Rows.Add(3,"Item3") |
|
| DataGridView1.DataSource=dt |
| DataGridView1.Sort(DataGridView1.Columns("Column2"),System.ComponentModel.ListSortDirection.Ascending) |
| EndSub |
|
| PrivateSubDataGridView1_DataBindingComplete(ByValsenderAsSystem.Object,ByValeAsSystem.Windows.Forms.DataGridViewBindingCompleteEventArgs)HandlesDataGridView1.DataBindingComplete |
| ForiAsInteger=0ToDataGridView1.Rows.Count-1 |
| ForjAsInteger=0ToDataGridView1.Columns.Count-1 |
| IfNotDataGridView1(j,i).ValueIsNothingThen |
| IfDataGridView1(j,i).Value.ToString()="Item1"Then |
| DataGridView1(j,i).ReadOnly=True |
| EndIf |
| EndIf |
| Next |
| Next |
| EndSub |
| EndClass |
You need to handle the DataBindingComplete event to check each cell if its value is equal to a special value, then set that cell's ReadOnly property to True.
The second question: Yes you can. You can use Sort method of DataGridView to set a column as sort column with Ascending or Descending. So when a new row is added, it will be sort automatically. Put the following code in the "New" method right after set the DataSource of DataGridView.
| DataGridView1.DataSource=dt |
| DataGridView1.Sort(DataGridView1.Columns("Column2"),System.ComponentModel.ListSortDirection.Ascending) |
Sincerely, Kira Qian
Please mark the replies as answers if they help and unmark if they don't. - Marked As Answer byKira QianMSFT, ModeratorFriday, February 06, 2009 2:08 AM
- Unmarked As Answer byreachrishikh Friday, February 06, 2009 8:11 AM
- Marked As Answer byreachrishikh Friday, February 06, 2009 9:06 AM
-
| | Kira Qian Wednesday, February 04, 2009 3:18 AM | When you ask to do something programmatically/ dynamically, do you think Visual Studio Windows Form Designer will create the code for you? If not, or you have already read the sticky thread named " Please read before posting", then you know you are in the wrong forum.
MSMVP VC++ | | Sheng Jiang 蒋晟 Monday, February 02, 2009 7:46 PM | My apologies if I am in the wrong forum. Hopefully you would be able to point me to the right forum for my question, or if this board supports it, move my thread there.
Also, I did read the forum sticky before posting, but it's possible the thread poster is not a native english speaker, so his message got lost in translation. It did mention "These posts should contain programming questions only." so I thought I'm in the right section. | | reachrishikh Monday, February 02, 2009 7:53 PM | Just search thenameof thecontrol you want to customize and see where people ask questions. My guess is the Windows Form Data Binding controls forum. MSMVP VC++ | | Sheng Jiang 蒋晟 Monday, February 02, 2009 8:53 PM |
Hi reachrishikh,
You can set the ReadOnly for each individual cell in DataGridView. Here is the sample code
| PublicClassForm1 |
| PrivatedtAsDataTable |
|
| PublicSubNew() |
| 'ThiscallisrequiredbytheWindowsFormDesigner. |
| InitializeComponent() |
|
| 'AddanyinitializationaftertheInitializeComponent()call. |
| dt=NewDataTable() |
| dt.Columns.Add("Column1") |
| dt.Columns.Add("Column2") |
|
| dt.Rows.Add(1,"Item1") |
| dt.Rows.Add(2,"Item2") |
| dt.Rows.Add(3,"Item3") |
|
| DataGridView1.DataSource=dt |
| DataGridView1.Sort(DataGridView1.Columns("Column2"),System.ComponentModel.ListSortDirection.Ascending) |
| EndSub |
|
| PrivateSubDataGridView1_DataBindingComplete(ByValsenderAsSystem.Object,ByValeAsSystem.Windows.Forms.DataGridViewBindingCompleteEventArgs)HandlesDataGridView1.DataBindingComplete |
| ForiAsInteger=0ToDataGridView1.Rows.Count-1 |
| ForjAsInteger=0ToDataGridView1.Columns.Count-1 |
| IfNotDataGridView1(j,i).ValueIsNothingThen |
| IfDataGridView1(j,i).Value.ToString()="Item1"Then |
| DataGridView1(j,i).ReadOnly=True |
| EndIf |
| EndIf |
| Next |
| Next |
| EndSub |
| EndClass |
You need to handle the DataBindingComplete event to check each cell if its value is equal to a special value, then set that cell's ReadOnly property to True.
The second question: Yes you can. You can use Sort method of DataGridView to set a column as sort column with Ascending or Descending. So when a new row is added, it will be sort automatically. Put the following code in the "New" method right after set the DataSource of DataGridView.
| DataGridView1.DataSource=dt |
| DataGridView1.Sort(DataGridView1.Columns("Column2"),System.ComponentModel.ListSortDirection.Ascending) |
Sincerely, Kira Qian
Please mark the replies as answers if they help and unmark if they don't. - Marked As Answer byKira QianMSFT, ModeratorFriday, February 06, 2009 2:08 AM
- Unmarked As Answer byreachrishikh Friday, February 06, 2009 8:11 AM
- Marked As Answer byreachrishikh Friday, February 06, 2009 9:06 AM
-
| | Kira Qian Wednesday, February 04, 2009 3:18 AM | Hi Kira Qian, Thanks a lot, the read-only solution is working fine. I had to change the databindingcomplete method as it didn't work, but used the cellendedit method instead. And I shifted the whole thing to a separate subprocedure, and can now call the same code from any number of events that I want to set the read-only properties.
But I only have one minor issue now. With all the various methods I could use to achieve what I want (including the databindingcomplete and the cellendedit), it will be highly inefficient, as it will run the whole code every time any cell changes. I just want it to run the code when the values in the cells of the first column change, not every time any value in any column changes. Any ideas how I could do that?
| PrivateSubDataGridView2_DataBindingComplete(ByValsenderAsSystem.Object,ByValeAsSystem.Windows.Forms.DataGridViewBindingCompleteEventArgs)HandlesDataGridView2.DataBindingComplete |
| Sub1() |
| EndSub |
|
|
| PrivateSubDataGridView2_CellEndEdit(ByValsenderAsSystem.Object,ByValeAsSystem.Windows.Forms.DataGridViewCellEventArgs)HandlesDataGridView2.CellEndEdit |
| Sub1() |
| EndSub |
|
| SubSub1() |
| ForiAsInteger=0ToDataGridView2.Rows.Count-1 |
| DimfAsInteger=0 |
| DimdAsInteger=2 |
| DimcAsInteger=3 |
| IfNotDataGridView2(f,i).ValueIsNothingThen |
| IfDataGridView2(f,i).Value.ToString()="ab"Then |
| DataGridView2(d,i).ReadOnly=False |
| DataGridView2(c,i).ReadOnly=True |
| ElseIfDataGridView2(f,i).Value.ToString()="cd"Then |
| DataGridView2(d,i).ReadOnly=True |
| DataGridView2(c,i).ReadOnly=False |
| EndIf |
| EndIf |
| Next |
| EndSub |
The sort solution also works, as long as I use the datatable method of populating the datagrid view. But if I define the entire datagrid view in designer mode, including setting all the columns and their properties, and skip binding a datatable to the datagridview, then the sort code you gave does not seem to work.
Also, assuming that I stick to the datatable method to use my datagridview, how do I set the sort order for the column to ascending, and prevent users from clicking the column header to change the sort order during runtime? I want to set the sort order to asc during design time and then lock changes to it. | | reachrishikh Wednesday, February 04, 2009 10:29 AM | Okay I have one more question. I use the arrow keys on the keyboard to navigate through the datagrid view cells. In my current example,when I'm entering data for a row, I use the right arrow key to navigate to the next column in the row once I'm done adding/editing data for the current cell. But once I reachthe end of the row, and I want to go down to the next row to start adding data, I press the down arrow key, and instead of the datagridview focusing the first column of the next row, it gives focus to the cell in the column directly below the current cell upon pressing the down arrow key. (I think MS Access has it right, it goes to the first column if you press the up or the down arrow key to navigate between successive records)
How do I change this behaviour in the datagridview? I know I have to use the rowenter, rowleave or the rowstatechanged events to build this functionality but I'm not quite sure how to do it.
Edit: Just checked, Access does not encapsulate the behaviour I described when clicking the down arrow key on the keyboard, but does go to the first column of the next/previous record if using the right/left arrow keys at the first or last column of a row when navigating using the keyboard. However, the datagrid view does go to the first column of the next row if at the last column of the current row, and the 'tab' button is clicked.
But I would still like the functionality of using the down/up arrow keys to go to the first column of a record when navigating in a datagridview, along with the tab and shift+tab navigating,if anyone could help me out.
Also, when using either the in-built tab/shift+tab navigating more, or using the arrow-key navigating mode that I'm trying to build, is it possible to skip over individual cells that have been made read-only, so that they do not recieve focus at all? | | reachrishikh Wednesday, February 04, 2009 12:18 PM |
Hi reachrishikh,
Please look at this thread. http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/54b1a182-f926-4c82-8817-2e9ba8f798b2/
Use the code given by the thread starter sam.m. The sample override the ProcessDialogKey and OnKeyDown method to capture the key press.
Sincerely, Kira Qian
Please mark the replies as answers if they help and unmark if they don't. - Unmarked As Answer byreachrishikh Friday, February 06, 2009 8:11 AM
- Marked As Answer byKira QianMSFT, ModeratorFriday, February 06, 2009 2:08 AM
-
| | Kira Qian Thursday, February 05, 2009 1:50 AM | Thanks, I'll move all my queries related to keyboard navigation to that thread. But coming back to my original issues, I still have a few unresolved things, if you would be patient and kind enough to help me out with them. 1) Using the databindingcomplete or the cellendedit event handlers to run the code is inefficient, since I only want to check for changes in one column, not all the columns. How do I restrict that checking? I guess right after the handler declaration, I would have to put in something like If column-of-cell-in-question = DataGridView1.Columns(0) Then Sub1() End If 2) The sorting code you gave me doesn't work anymore. I have made changes to the code, and I can no longer call the sort method from the initialize component call, because the entire datagridview itself is created a bit after the new() sub. Okay, here is the code so far:
| PublicClassForm3 |
|
| PrivatedtAsDataTable |
| PublicWithEventsDataGridView1AsNewDataGridView |
|
| PublicSubNew() |
| 'ThiscallisrequiredbytheWindowsFormDesigner. |
|
| InitializeComponent() |
|
| 'AddanyinitializationaftertheInitializeComponent()call. |
| EndSub |
|
| PrivateSubForm3_Load(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesMyBase.Load |
| SetupDataTable() |
| SetupDataGridView() |
| FillDataGridView() |
| EndSub |
|
| SubSetupDataTable() |
| dt=NewDataTable() |
| dt.Columns.Add("Column1") |
| dt.Columns.Add("Column2") |
| dt.Columns.Add("Column3") |
| dt.Columns.Add("Column4") |
|
| dt.Rows.Add("ab","data","figures","") |
| dt.Rows.Add("ab","data","figures","") |
| dt.Rows.Add("cd","data","","figures") |
| EndSub |
|
| SubSetupDataGridView() |
| Me.Controls.Add(DataGridView1) |
|
| WithDataGridView1 |
| .Name="DataGridView1" |
| .Location=NewPoint(0,0) |
| .Size=NewSize(926,190) |
| .RowHeadersVisible=False |
| .BorderStyle=BorderStyle.None |
| .AutoGenerateColumns=False |
| EndWith |
|
| DimCol1AsNewDataGridViewComboBoxColumn() |
| WithCol1 |
| .Name="Column1" |
| .HeaderText="" |
| .Width=55 |
| .SortMode=DataGridViewColumnSortMode.NotSortable |
| .Items.Add("ab") |
| .Items.Add("cd") |
| EndWith |
|
| DimCol2AsNewDataGridViewTextBoxColumn() |
| WithCol2 |
| .Name="Column2" |
| .HeaderText="Column2" |
| .Width=500 |
| .SortMode=DataGridViewColumnSortMode.NotSortable |
| EndWith |
|
| DimCol3AsNewDataGridViewTextBoxColumn() |
| WithCol3 |
| .Name="Column3" |
| .HeaderText="Column3" |
| .Width=150 |
| .SortMode=DataGridViewColumnSortMode.NotSortable |
| EndWith |
|
| DimCol4AsNewDataGridViewTextBoxColumn |
| WithCol4 |
| .Name="Column4" |
| .HeaderText="Column4" |
| .Width=150 |
| .SortMode=DataGridViewColumnSortMode.NotSortable |
| EndWith |
|
| WithDataGridView1 |
|
| .Columns.Insert(0,Col1) |
| .Columns.Insert(1,Col2) |
| .Columns.Insert(2,Col3) |
| .Columns.Insert(3,Col4) |
|
| .Sort(DataGridView1.Columns("Column1"),System.ComponentModel.ListSortDirection.Ascending) |
|
| EndWith |
|
| EndSub |
|
| SubFillDataGridView() |
| DataGridView1.DataSource=dt |
| EndSub |
|
| PrivateSubDataGridView1_DataBindingComplete(ByValsenderAsSystem.Object,ByValeAsSystem.Windows.Forms.DataGridViewBindingCompleteEventArgs)HandlesDataGridView1.DataBindingComplete |
| Sub1() |
| EndSub |
|
| PrivateSubDataGridView1_CellEndEdit(ByValsenderAsSystem.Object,ByValeAsSystem.Windows.Forms.DataGridViewCellEventArgs)HandlesDataGridView1.CellLeave |
| Sub1() |
| EndSub |
|
| SubSub1() |
| ForiAsInteger=0ToDataGridView1.Rows.Count-1 |
| DimfAsInteger=0 |
| DimdAsInteger=2 |
| DimcAsInteger=3 |
| IfNotDataGridView1(f,i).ValueIsNothingThen |
| IfDataGridView1(f,i).Value.ToString()="ab"Then |
| DataGridView1(d,i).ReadOnly=False |
| DataGridView1(c,i).ReadOnly=True |
| ElseIfDataGridView1(f,i).Value.ToString()="cd"Then |
| DataGridView1(d,i).ReadOnly=True |
| DataGridView1(c,i).ReadOnly=False |
| EndIf |
| EndIf |
| Next |
| EndSub |
| EndClass | 3) I've been trying to search since last evening but no luck so far, so if you don't mind me asking it in one place --> How do I bind the columns I created up there in the datatable to the columns I'm creating programatically in the datagridview? - Edited byreachrishikh Thursday, February 05, 2009 9:09 AMtypo
-
| | reachrishikh Thursday, February 05, 2009 8:25 AM | Going through the thread to which you posted a link to, I think I have the solution to my issue no 1 listed in the post above. Please correct me if I'm wrong.
| PrivateSubDataGridView1_CellEndEdit(ByValsenderAsSystem.Object,ByValeAsSystem.Windows.Forms.DataGridViewCellEventArgs)HandlesDataGridView1.CellLeave |
| DimcolAsInteger=DataGridView1.CurrentCell.ColumnIndex |
| Ifcol=0Then |
| Sub1() |
| EndIf |
| EndSub | | | reachrishikh Thursday, February 05, 2009 8:59 AM |
Hi reachrishikh,
1) Using the databindingcomplete or the cellendedit event handlers to run the code is inefficient, since I only want to check for changes in one column, not all the columns. How do I restrict that checking?
ANS: Put a If statement to check the column index before you run the check code, only do the check for the column you want.
2) The sorting code you gave me doesn't work anymore. I have made changes to the code, and I can no longer call the sort method from the initialize component call, because the entire datagridview itself is created a bit after the new() sub.
ANS: Look at my first post again. After you bind the DataTable to the DataGridView, you will call Sort method to set which column is sortable and how to sort it.
| DataGridView1.DataSource=dt |
| DataGridView1.Sort(DataGridView1.Columns("Column2"),System.ComponentModel.ListSortDirection.Ascending) |
These code should be in the "New" method.
3) I've been trying to search since last evening but no luck so far, so if you don't mind me asking it in one place --> How do I bind the columns I created up there in the datatable to the columns I'm creating programatically in the datagridview?
ANS: Set "DataPropertyName" property of that column to the column name in DataTable. Please see this. http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridviewcolumn.datapropertyname.aspx
Sincerely, Kira Qian
Please mark the replies as answers if they help and unmark if they don't. | | Kira Qian Friday, February 06, 2009 2:23 AM | Hey, Thanks for the reply.
If you see my post right above your last post, I have already tried out the solution you offered for problem number 1. But the thing is it doesn't work. If I put in that if statement to check the column index, the read-only method stops working. As I noted in this thread http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/54b1a182-f926-4c82-8817-2e9ba8f798b2/ the .currentcell property doesn't seem to be working for me. Ah! Okay, nowI get it. I was calling the two methods that set up my datatable and datagridview from the form load event. I shifted those to the new method under the initialize component call, and it's working fine now. Only problem is, after binding the dgv columns to the datatable columns, the datagridview is now repeating all 4 columns and appending them to the first 4 when run. - Edited byreachrishikh Friday, February 06, 2009 2:11 PMtypo
-
| | reachrishikh Friday, February 06, 2009 8:30 AM | You need to set the DataPropertyName of DataGridViewColumn to the column name in DataTable. E.g. You have create a DataGridViewComboBoxColumn named cmbCol, you want to bind this column to the column "Column1" in DataTable, so you need to write:cmbCol.DataPropertyName = "Column1" Sincerely, Kira Qian
Please mark the replies as answers if they help and unmark if they don't. | | Kira Qian Friday, February 06, 2009 8:43 AM | No, just found what the problem was. I was setting the datagridview1.autogeneratedcolumns = False after I was setting the property datagridview1.datasource = dt
I've corrected that issue now andeverything'sworking fine finally!
Thanks again for all the help! | | reachrishikh Friday, February 06, 2009 8:59 AM |
|