DataGridView shows columns that were set to non-visible - c#

I have 3 datagridviews, and each of them has a separate binding source. All three binding sources however get data from the same datatable.
bindingSource1.DataSource = mytable;
bindingSource2.DataSource = mytable;
bindingSource3.DataSource = mytable;
dataGridView1.DataSource = bindingSource1;
dataGridView2.DataSource = bindingSource2;
dataGridView3.DataSource = bindingSource3;
I control what the user sees with the following logic: Show 10 first columns on the first grid, the next 10 on the second, and the next 10 on the third.
for (int i = 0; i < mytable.Columns.Count; i++)
{
dataGridView1.Columns[i].Visible = i < 10;
dataGridView2.Columns[i].Visible = (i >= 10 && i < 20);
dataGridView3.Columns[i].Visible = (i >= 20 && i < 30);
}
This works fine when I have many columns in the datatable.
Problem If I have less than 10 columns in my datatable, normally they should only be shown in the first datagridview. This does happen, but also the first column of the datatable is always shown in datagrid 2 and 3. I have stepped through my loop to see whether a condition is wrong, and I found it to be correct. Therefore, I am pretty sure it must be one of the events that follow this. I have two events registed for my grids that could be the cuplrits: RowPostPaint and CellPainting. I commented out everything that I was doing in these events and still get this problem. I also have some others, like DataError, CellValueChanged(empty inside), Scroll etc, but I think they are irrelevant.
So I am wondering whether there is another event which I haven't registered, which could be doing this by itself.

You're seeing this behavior because of a default behavior that happens when binding the data source. To fix, handle each DataGridView.DataBindingComplete event. We will use the same event handler for each:
dataGridView1.DataBindingComplete += DataGridView_DataBindingComplete;
dataGridView2.DataBindingComplete += DataGridView_DataBindingComplete;
dataGridView3.DataBindingComplete += DataGridView_DataBindingComplete;
In that event handler, we will set the visible columns as before. But we will also set the row headers' visibility as well as scroll bars - in case no columns are visible.
private void DataGridView_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
DataGridView view = sender as DataGridView;
bool anyVisible = false;
int max = 0, min = 0;
if (view == this.dataGridView1)
{
min = 0;
max = 10;
}
else if (view == this.dataGridView2)
{
min = 10;
max = 20;
}
else if (view == this.dataGridView3)
{
min = 20;
max = 30;
}
for (int i = 0; i < this.table.Columns.Count; i++)
{
view.Columns[i].Visible = i >= min && i < max;
anyVisible = anyVisible || view.Columns[i].Visible;
}
view.RowHeadersVisible = anyVisible;
view.ScrollBars = anyVisible ? ScrollBars.Both : ScrollBars.None;
}

Related

WPF: How to detect rows rendering complete at DataGrid control?

I want to add a column to display sequence number without adding an extra property in the items source data and bind the sequence value in the binding property.
I added an event handler to the loading row event but I noticed that the last row's elements are not yet initialized during firing this event.
var dataGrid = new DataGrid();
dataGrid.LoadingRow += (s, e) =>
{
if (dataGrid.ItemsSource != null && e.Row.GetIndex() + 1 == ((IList)dataGrid.ItemsSource).Count)
{
int participantColumnsCount = ((DataGridControlEntity)item).DisplayMembersPathEn.Count + 2;
var elements = FindVisualChildren<TextBlock>(dataGrid);
int cellIdx = 0;
for (int idx = 1; idx <= ((IList)dataGrid.ItemsSource).Count; idx++)
{
cellIdx = 0 + (idx * participantColumnsCount);
if (cellIdx + 1 >= elements.Count())
break;
elements.ElementAt(cellIdx).Text = idx.ToString();
}
}
};
Any clue ?
I am able to find a fare workaround for this issue by subscribing to LayoutUpdated event rather than LoadingRow event.

Split cell in GridView C#

I am pulling data from database and showing it in GridView ,
C# code
GridView1.DataSource = ds;
GridView.DataBind();
data coming from database has same name for tow rows in Column1 but column2 and column3 have unique values, it appears in grid view as :
However i want to display it as :
You have to use row span to achieve it. It's a merging of row. Not a splitting of row.
Refer following code for it:
protected void GridView1_DataBound1(object sender, EventArgs e)
{
for (int rowIndex = GridView1.Rows.Count - 2; rowIndex >= 0; rowIndex--)
{
GridViewRow gvRow = GridView1.Rows[rowIndex];
GridViewRow gvPreviousRow = GridView1.Rows[rowIndex + 1];
for (int cellCount = 0; cellCount < gvRow.Cells.Count; cellCount++)
{
if (gvRow.Cells[cellCount].Text == gvPreviousRow.Cells[cellCount].Text)
{
if (gvPreviousRow.Cells[cellCount].RowSpan < 2)
{
gvRow.Cells[cellCount].RowSpan = 2;
}
else
{
gvRow.Cells[cellCount].RowSpan = gvPreviousRow.Cells[cellCount].RowSpan + 1;
}
gvPreviousRow.Cells[cellCount].Visible = false;
}
}
}
There are several ways to do that but none of them are easy.
What might be the easiest of all:
Turn off top and bottom grid lines in the first column.
Declare a variable at the page level the same type as column1.
Inside gridviewrowdataboundevent compare the value from column1 to the value in the variable. If they not the same, turn on the appropriate grid lines, else leave them off.
This is all pseudo code. You will need to provide the specific details, etc.

get value from datagrid cell in C#

How do I get the info from a certain cell in a data grid? I want an event to happen when a person clicks the button in the 7th column, but the event depends on the value in the first column. here's what i have, but nothing is happening.
if (InventoryDataGridView.CurrentCell.ColumnIndex == 7)
{
if(InventoryDataGridView[0,0].Equals("Books"))
{
Books open = new Books();
open.Show();
}
}
Nothing happens though
InventoryDataGridView[0,0]
only refers to the DataGridViewCell. That class has a Value property which contains the value of the cell.
so that line should look like this:
if(InventoryDataGridView[0,0].Value.Equals("Books"))
{
//
}
If you using WPF then you must try this:
for (int j = 0; j < dataGrid1.Columns.Count; j++)
{
for (int i = 0; i < dataGrid1.Items.Count - 1; i++)
{
string s=(dataGrid1.Items[i] as DataRowView).Row.ItemArray[j].ToString();
}
}
i,j are the co-ordinates. So you can play around it.
reference: http://subrat308.blogspot.in/2012/02/wpf-get-cell-value-from-datagrid-cellij.html

mulit select listbox in wpf

how i can select five items in the single click on the list box??
if i click any item, i just want to +2 and -2 from the selected index. so my single click need to select five items in the listview.
Am using C#(WPF).
I am not sure what you want to do exactly, but trying. =)
Have a look at the Click event of the ListBox. You can do anything in there, including selecting five items of your choice. You can do it like this (untested, but gives you an idea):
int sindex = listBox1.SelectedIndex;
listBox1.SelectedItems.Clear();
for(int i = Math.Max(sindex - 2, 0); i < Math.Min(sindex + 2, listBox1.Items.Count()), i++)
{
listBox1.SelectedItems.Add(listBox1.Items[i]);
}
Another thing would be setting the SelectionMode to Multiple or Extended. Does this result in the behaviour you are looking for?
have a look at selectionchanged event, and get the index of the selected item and make it +2 and -2
i tried it like this and it works:
void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int idx = list.SelectedIndex;
int startIdx = idx - 2;
int endIdx = idx + 2;
if (startIdx < 0)
{
startIdx = 0;
}
if (endIdx >= list.Items.Count)
{
endIdx = list.Items.Count-1;
}
for (int i = startIdx; i <= endIdx; i++)
{
if (i != idx)
{
list.SelectedItems.Add(list.Items[i]);
}
}
}
one problem with this code is you can still use ctrl to select another item so it makes the selecteditems count increased

How to find a particular position of a selected item in Listbox making the Buttons Enabled in C#?

I have a list box with items like A B C D E.
I also have two buttons Move UP and Move Down with it.
I have already made their properties false in the property window (F4).
When a user selects B or all the items below then my Move Up button should get enabled. It should be disabled for A item
In the same way my Move Down button should be enabled when the user selects D or all the items above it. It should be disabled for E.
Can you please provide me the right part of code to be written here.
Thanks....
I am doing a similar thing in my app. It also handles selection of multiple items and also checks if the multiple items that are selected are continuous or not.
Here's the code:
private bool SelectionIsContiguous(ListBox lb)
{
for (int i = 0; i < lb.SelectedIndices.Count - 1; i++)
if (lb.SelectedIndices[i] < lb.SelectedIndices[i + 1] - 1)
return false;
return true;
}
private void SetMoveButtonStates()
{
if (this.listBox.SelectedIndices.Count > 0)
{
if (this.listBox.SelectedIndices.Count > 1 && !SelectionIsContiguous(this.listBox))
{
this.btnMoveUp.Enabled = false;
this.btnMoveDown.Enabled = false;
return;
}
int firstSelectedIndex = this.listBox.SelectedIndices[0];
this.btnMoveUp.Enabled = firstSelectedIndex == 0 ? false : true;
int lastIndex = this.listBox.Items.Count - 1;
int lastSelectedIndex = this.listBox.SelectedIndices[this.listBox.SelectedIndices.Count - 1];
this.btnMoveDown.Enabled = lastSelectedIndex == lastIndex ? false : true;
}
}
Handle the SelectedIndexChanged event of the ListBox. If the SelectedIndex is greater than 0, enable "move up". If it is lesser than count - 1, enable "move down"
Here's the code I use in listBox_SelectedIndexChanged:
this.moveUp.Enabled = this.listBox.SelectedIndex > 0;
this.moveDown.Enabled = this.listBox.SelectedIndex > -1 && listBox.SelectedIndex < listBox.Items.Count - 1;
Actually it's in a method called from there as the code's called when the dialog's initialised too.

Categories