filter the child entityCollection that is bound to datagridView as "dataMember"

Posts   
 
    
yogiberr
User
Posts: 432
Joined: 29-Jun-2005
# Posted on: 19-May-2006 13:14:46   

hiya,

I have a datagridView.

There is a top level bindingSource, let's just call it "tblReturnsBindingSource"

tblReturnsBindingSource.datasource = tblReturnCollection1

Then, we have the "child" binding source...which is actually bound to the datagridview.

"tblReturnsProductsBindingSource"

tblReturnsProductsBindingSource.datamember = tblReturnProducts //THIS IS WHAT i NEED TO FILTER

tblReturnsProductsBindingSource.dataSource = tblReturnsBindingSource

At the moment, I simply populate the parentEntityCollection..And the IDE knows to bind the child entityCollection to the datagridView..

So far so good. I now need to filter the "child" entity collection, namely the "tblReturnProducts".

I have some code that will tell me WHICH entities in the child entityCollection satisfy the filter conditions:


foreach (TblReturnEntity currReturnsEntity in tblReturnCollection1)
            {
                foreach (TblReturnProductsEntity currReturnsProduct in currReturnsEntity.TblReturnProducts)
                {
                    if (currReturnsProduct.ReturnId == _selectedReturnId && currReturnsProduct.ReturnProductCondtionId == (int)cboReturnProductCondition.SelectedValue)
                    {
                                             // What do I DO with these entities, so that the entiyCollection is successfully filtered?                 }
                    }
            }

So, how do I successfully apply this filter? PS, the reason that I can't simply filter the parent entityCollection is that the child entityColletion contains fields which are NOT part of the parent entityCollection.

I hope the above made sense.

many thanks,

yogi

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 19-May-2006 20:56:25   

I don't think it's wise to chain bindingsources, just bind collections to bindingsources and bindingsources to controls, not bindingsources to bindingsources.

Secondly, I think it's best if you filter the child collection's entities and the entities matching the filter are added to a new collection which is bound to the bindingsource. There's otherwise no way to do it at this point. In v2 you can create a view and filter that view and bind that view to the bindingsource, but that's not possible with v1.0.2005.1

Frans Bouma | Lead developer LLBLGen Pro
yogiberr
User
Posts: 432
Joined: 29-Jun-2005
# Posted on: 20-May-2006 12:14:58   

thanks Frans.

yogi

Posts: 10
Joined: 28-May-2009
# Posted on: 02-Jun-2009 13:26:38   

Sorry for disturbing the dead,

but I'd like to know just how to bind an EntityView from a EntityCollection to a BindingSource at design time.

it should result in something like:

            this.colCustomer = new CustomerCollection();
            this.bscCustomers = new BindingSource(this.components);
            this.bscCustomers.DataSource = this.colCustomer.DefaultView;
            this.dgvCustomerList = new DataGridView();
            this.dgvCustomerList.DataSource = this.bscCustomers;

Why do I want to explicitly bind the View? Because I want to filter the dgvCustomerList with an IPredicateExpression filter like

cCustomer.DefaultView.Filter = filter;

Or it possible to apply the filter to the colCustomers without removing the CustomerEntites not shown?

Thanks, Gerard

LLBLGen Pro 2.6 Final (2.6.08.1013)

Posts: 10
Joined: 28-May-2009
# Posted on: 02-Jun-2009 14:47:21   

Also: The filter is determined by a set of TextBox controls above the DataGridView. The DataGridView is not supposed to page. The whole form is supposed to be something like a fancy search function. All TextBoxes have their TextChanged events sent to

        private void tbxFilter_TextChanged(object sender, EventArgs e)
        {
            IPredicateExpression filter = getFilter();
            colCustomer.DefaultView.Filter = filter;

            if ((dgvCustomerList.Rows.Count < MIN_RESULTS && collectionContainsIsMaxRows > MIN_RESULTS)
                // database may contain more elements
                || (dgvCustomerList.Rows.Count == collectionContainsIsMaxRows && collectionContainsIsMaxRows < MAX_RESULTS))
                // filter weakened, fetch more
            {
                colCustomer.GetMulti(filter, MAX_RESULTS, customerSorter);
                collectionContainsIsMaxRows = colCustomer.Count; // *)
            }
        }

min_results and max_results are Properties.Settings.Default.* to be set at deployment per-machine. min_results basicly controls how often GetMulti is called. (My values in testing are 10 and 200).

*) striktly everywhere in the form after a GetMulti.

Is that the optimal way to do it (the event handler) or is there a better way?

getFilter() is (just to complete the above excerpt):

        private IPredicateExpression getFilter()
        {
            PredicateExpression predExp = new PredicateExpression();

            if (!"".Equals(tbxFilterFirstname.Text)) predExp.Add(new FieldLikePredicate(CustomerFields.Firstname, "%" + tbxFilterFirstname.Text + "%"));
            if (!"".Equals(tbxFilterLastname.Text)) predExp.AddWithAnd(new FieldLikePredicate(CustomerFields.Lastname, "%" + tbxFilterLastname.Text + "%"));
            if (!"".Equals(tbxFilterMiddlename.Text)) predExp.AddWithAnd(new FieldLikePredicate(CustomerFields.Middlename, "%" + tbxFilterMiddlename.Text + "%"));
            if (!"".Equals(tbxFilterTitle.Text)) predExp.AddWithAnd(new FieldLikePredicate(CustomerFields.Title, "%" + tbxFilterTitle.Text + "%"));
            // ... and so on... filtering is possible on all fields of Customer

            return predExp;
        }

Take my handle literally, this is really my first WinForms application, also my first llblgen project. (I'm from java-land).

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 02-Jun-2009 21:13:17   

DataSources bind to the default view automatically, so filtering the base collection should result in the filter results being reflected in the bound control. Take a look at the documentation about this.

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 02-Jun-2009 21:16:41   

Your filtering method is reasonable enough - the only thing to watch out for is that (I think) .TextChange fires on every keypress (the text HAS changed, after all) which will result in many DB queries as the user types into a box.

There are two alternative approaches. 1) Grab the entire contents of the table into a collection (obviously only sensible on smallish tables), and use in-memory filtering on the TextChanged event.

2) Run the filter on .LostFocus, or a "Search" button so that the db is only queried when the user is ready.

Obvioulsy the approach you take will be directed by the amount of the data and the needs of the users.

Matt

Posts: 10
Joined: 28-May-2009
# Posted on: 03-Jun-2009 10:50:36   

Thanks Matt,

the filtering now works and I even added a layer of abstraction (I need that search for a few things).

I can't read all the customers, the customertable has +3000 entries from the start.

To avoid triggering all these DB queries is the whole point of MIN_RESULTS. As long as there are still more entries shown, no DB query will take place (except forced, by clicking the button).

I wrote a note to the deployers to play around with those values to find a balance. I also think that the experience the users get teaches them. If they use "bad" filters the form will react lazyly...

Gerard