0
votes

My current situation is as follows: I have 3 datagridviews, I can filter them (through bindingsource.filter) and also move columns from one datagridview from another. Code that does this:

//Move from third datagrid to first
private void moveToFirstGridToolStripMenuItem1_Click(object sender, EventArgs e)
    {
        dataGridView3.Columns[currentColumnIndex].Visible = false;
        dataGridView1.Columns[currentColumnIndex].Visible = true;
        currentColumnIndex = -5;
    }

This works because all three datagrids have the same datatable as a datasource, have all the columns of this table, and I just control what is shown at any time. These 3 datagridviews, each of them has a separate binding source. All three binding sources however get data from the same datatable. I also 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.

I had a small problem, that whenever there were columns only in the first datagrid, the first column of the datatable would also be shown on the second and third datagrids, which I didn't want. Through this question: DataGridView shows columns that were set to non-visible I was able to handle the databindingcomplete event, through that answer. This is my current handler, for all 3 datagrids:

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;
        }
        if (view == this.dataGridView2)
        {
            min = 10;
            max = 20;
        }
        if (view == this.dataGridView3)
        {
            min = 20;
            max = 30;
        }

        for (int i = 0; i < this.m_CurrentTable.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;
}

Coming to the problem: If I move for example a column from datagrid 3 to datagrid 1, and then try to filter, I would like that to work as one would expect. This code will not allow you to do that, because if for example I moved column#21 (3rd datagrid) to the first, and then filtered, when the databindingcomplete event is fired once for each datagrid, column #21 will move back to the third datagrid. The filtering works correctly but the position of the column is reset, which I don't want.

Basically my filter specifies what rows are to be shown, and the databindingcomplete event what columns. I could just implement a boolean to check if there has been a filter, and then avoid this event, but this is not a very good solution, and also leads to other problems.

A way I am thinking of is perhaps I could try to reset my binding source datasource to the current datagrid datasource (which has been changed when you moved a column to it), in the databindingcomplete event. I'm still trying to see whether that makes sense though. Another thing perhaps that could be used also is the e.listchangedtype of the datagridviewbindingcomplete event args, but I have no experience with it.

This obviously is a specialised question, but the parts of it (datagridview, event handling) are more fundamental. Any attempt of answering is welcome.

1
Show the code that "moves a column from one grid to another". - Ivan Stoev
@IvanStoev Move from third grid to first: private void moveToFirstGridToolStripMenuItem1_Click(object sender, EventArgs e) { dataGridView3.Columns[currentColumnIndex].Visible = false; dataGridView1.Columns[currentColumnIndex].Visible = true; currentColumnIndex = -5; } Basically making columns visible and invisible, because all three datagridviews have the same datatable as datasource. - Iason
@IvanStoev Added it to question. - Iason

1 Answers

1
votes

Instead of blocking the event, you need to maintain some logical map of which column belongs to which data grid view, and update it accordingly when you move the columns between the grids.

For instance, something like this

private int[] columnViewIndex = Enumerable.Repeat(0, 10)
    .Concat(Enumerable.Repeat(1, 10))
    .Concat(Enumerable.Repeat(2, 10))
    .ToArray();

private void moveToFirstGridToolStripMenuItem1_Click(object sender, EventArgs e)
{
    dataGridView3.Columns[currentColumnIndex].Visible = false;
    dataGridView1.Columns[currentColumnIndex].Visible = true;
    columnViewIndex[currentColumnIndex] = 0; // 1, 2 in other move methods
    currentColumnIndex = -5;
}

private void DataGridView_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
    var view = sender as DataGridView;
    int viewIndex = view == this.dataGridView1 ? 0 : view == this.dataGridView2 ? 1 : 2;
    bool anyVisible = false;
    for (int i = 0; i < this.m_CurrentTable.Columns.Count; i++)
    {
        bool visible = i < columnViewIndex.Length && columnViewIndex[i] == viewIndex;
        view.Columns[i].Visible = visible;
        anyVisible = anyVisible || visible;
    }

    view.RowHeadersVisible = anyVisible;
    view.ScrollBars = anyVisible ? ScrollBars.Both : ScrollBars.None;
}