Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > [C#]BindingSource.Filter проблема с фильтрацией


Автор: thomas 13.3.2009, 12:47
Приветствую уважаемое сообщество.
В приложении использую классы для описания объектов (один объект = запись в таблице БД).
Для получения всех записей из таблицы использую методы, которые возвращают List<T> .
Это все реализовано в бизнес слое приложения.
В слое представления для отображения данных и реализации навигации по записям использую BindingSource, 
которые передаются DataGridView в качестве источника данных.
Все работает. 
Но вот возникла необходимость  при отображении данных в табличной форме фильтровать их по тому или иному параметру (столбцу).
К примеру - в DataGridView отображены все фактуры клиента, фактура может быть оплачена или не оплачена, пользователь жмет кнопочку и 
в DataGridView отображаются только не оплаченнные фактуры данного клиента.
Пытаюсь фильтровать BindingSource присваивая его свойству Filter необходимое значение. Но ничего не происходит.
Вот http://msdn.microsoft.com/ru-ru/library/system.windows.forms.bindingsource.filter.aspx смотрел в первую очередь.
Но это ничего не дало, так как там пример дан с DataView, а я присваиваю свойству DataSource моего BindingSource заполненный BindingList<T>, 
которому в качестве значения присваивается результат работы метода класса из бизнес слоя приложения в виде List<T>.

Прошу помощи у уважаемого сообщества. Подскажите в чем может быть проблема и как ее решить.
Потому как в приложении нужно будет реализовать еще много раз фильтрацию данных по заданным параметрам.

Да DataSet-ы  в приложении не используются вообще. Все реализовано через коллекции List<T>. А в слое представления через BindingList<T> и BindingSource.

Заранее благодарю.

Автор: thomas 13.3.2009, 13:05
Это код котрый сейчас в приложении.
Два метода срабатывают на ура, загрузка формы(конструктор) и SetupBinding()
А вот код в обработчике события "нажать кнопку" не срабатывает.
Код

public frmKlantEdit()
            {
                InitializeComponent();
                SetupBinding();
            }
private void SetupBinding()
            {
                ContactFilter _contactFilter = new ContactFilter("K");
                Predicate<Contact> filterByType = new Predicate<Contact>(_contactFilter.MatchesContactType);
                BindingList<Contact> klantList = new BindingList<Contact>(Contact.GetEntityList().FindAll(filterByType));
                this.contactBindingSource.DataSource = klantList;

                BindingList<Artikel> artikelList = new BindingList<Artikel>(Artikel.GetEntityList());
                this.artikelBindingSource.DataSource = artikelList;
            }
private void button1_Click(object sender, EventArgs e)
        {
            this.klantFactuurBindingSource.Clear();
            this.klantFactuurDataGridView.DataSource = null;

            //reloaden фактуры для данного клиента
            Contact klant = this.contactBindingSource.Current as Contact;
            BindingList<KlantFactuur> factuurList = new BindingList<KlantFactuur>(KlantFactuur.GetEntityList(klant.ContactId));
            this.klantFactuurBindingSource.DataSource = factuurList;
            this.klantFactuurDataGridView.DataSource = this.klantFactuurBindingSource;
            this.klantFactuurBindingSource.Filter = "Afbetaald = false";  
            this.klantFactuurDataGridView.Refresh();
        }


может я там много чего лишнего понаписал или надо как-то по другому?

Автор: Partizan 13.3.2009, 17:38
thomas, это решение проблемы? или это ваш код, который не работает?

Автор: thomas 13.3.2009, 17:41
Partizan, 
Это код который не работает. Имею ввиду код события (нажать кнопку Button1)
ЗЫ добавлял код с другого компа, поэтому в саму тему код не попал, а добавился отдельным постом. Упс, извиняюсь.

Автор: diadiavova 13.3.2009, 20:10
Для того, чтобы коллекция поддерживала фильтрацию, надо чтобы в ней был реализован интерфейс 
System.ComponentModel.IBindingListView.

Автор: thomas 14.3.2009, 00:10
diadiavova, 
приветствую.
в msdn вот по этому ms-help://MS.MSDNQTR.v90.ru/fxref_system.windows.forms/html/7a1ee03a-f316-f86f-a007-8891c1965901.htm адресу
НАПИСАНО

Цитата

C# 
[ComplexBindingPropertiesAttribute("DataSource", "DataMember")]
public class BindingSource : Component, IBindingListView, 
    IBindingList, IList, ICollection, IEnumerable, ITypedList, 
    ICancelAddNew, ISupportInitializeNotification, ISupportInitialize, ICurrencyManagerProvider
 


это означает что в классе BindingSource РЕАЛИЗОВАН интерфес, на который вы мне указываете.
Иначе, насколько я понимаю, у этого класса не было бы свойства Filter.

Так вот, вопрос остается открытым.
Что я делаю не так и что надо сделать, чтобы ПРОИЗВОДИЛАСЬ ФИЛЬТРАЦИЯ?

ЗЫ в статье про IBindingListView написано
Цитата

Заметки
Интерфейс IBindingListView позволяет реализовать расширенную сортировку как набор пар "дескриптор свойства-направление". Фильтрацию можно реализовать как строку, интерпретируемую реализацией источника данных. Интерфейс IBindingListView реализуется с помощью класса BindingSource.

Автор: diadiavova 14.3.2009, 00:18
Я написал о коллекции BindingList. у биндингсорса есть свойство  SupportsFiltering, о возвращаемом значении этого свойства написано
Цитата

Значение true, если список имеет тип System.ComponentModel.IBindingListView и поддерживает фильтрацию. В противном случае — значение false.


Автор: thomas 14.3.2009, 00:58
diadiavova, 
Я про Фому
Цитата

[C#]BindingSource.Filter проблема с фильтрацией

а ты про Ерёму
Цитата

Я написал о коллекции BindingList.

Ладно, это все лирика  smile 
Будем проверять свойство SupportsFiltering своего BindingSource.

Автор: diadiavova 14.3.2009, 01:02
На самом деле я про того же фому, ты просто меня не понял. Биндингсорс никаких чудес не творит, если в источнике реализован указанный интерфейс, то он будет фильтровать, а если нет -  то будет возникать как раз та проблема, из-за которой ты создал тему. Возьми вместо биндинглист таблицу и будет тебе счастье.

Добавлено через 9 минут и 54 секунды
Точнее не таблицу напрямую, DataView.

Автор: thomas 14.3.2009, 15:05
diadiavova, 
приветствую.
То что ты советуешь
Цитата

Возьми вместо биндинглист таблицу и будет тебе счастье.

Добавлено через 9 минут и 54 секунды
Точнее не таблицу напрямую, DataView. 

не покатит
Цитата

Да, DataSet-ы  в приложении не используются вообще. Все реализовано через коллекции List<T>. А в слое представления через BindingList<T> и BindingSource.


В приложении два слоя: слой данных и слой представления.
В слое данных на каждый объект написан класс, который представляет одну запись из той или иной таблицы, в нем есть статические методы, которые выдают коллекцию объектов, считав записи из БД посредством dataReader.
В слое представления  данные отображаются.
Никаких DataSet, DataTable, DataView в приложении нет и не будет.

Автор: diadiavova 14.3.2009, 15:14
Тогда для фильтрации можно выбирать из листа нужные записи методом FindAll, создавать на их основе биндинглист и передавать его дэйтасорсу грида. Как это выглядит с точки зрения кривизны реализации и производительности - не знаю, но на небольшом примере пробовал - работает
Код

datagridView1.DataSource = new BindingList<Contact>(List1.FindAll(cont=> ! cont.Afbetaald));

что-то в этом роде.

Автор: thomas 14.3.2009, 20:23
diadiavova, 
привет.
С точки зрения кривизны и производительности 
Цитата

Тогда для фильтрации можно выбирать из листа нужные записи методом FindAll
выглядит нормально и одобрено большим спецом по данным Джоном Папа.
Программа построена по его "схеме", которую он описывает в .NET Magazin за 2007 год (блин ссылки нет под рукой)
Если ты внимательно смотрел на код метода SetupBinding, то там видно что для получения клиентов используется как раз то о чем ты говоришь.
Код

            private void SetupBinding()
            {
                ContactFilter _contactFilter = new ContactFilter("K");
                Predicate<Contact> filterByType = new Predicate<Contact>(_contactFilter.MatchesContactType);
                BindingList<Contact> klantList = new BindingList<Contact>(Contact.GetEntityList().FindAll(filterByType));
                this.contactBindingSource.DataSource = klantList;
                BindingList<Artikel> artikelList = new BindingList<Artikel>(Artikel.GetEntityList());
                this.artikelBindingSource.DataSource = artikelList;
            }
 вот тут BindingList<Contact> klantList = new BindingList<Contact>(Contact.GetEntityList().FindAll(filterByType));

Для этого в классе формы написан вложенный приватный класс ContactFilter, для фильтрации контактов. Контакт может быть поставщиком или клиентом.
В данном случае нужны были клиенты.

Значит придется писать еще один класс - фильтр для фактур и по нажатию кнопочки перезаполнять   
BindingList<KlantFactuur> factuurList = new BindingList<KlantFactuur>(KlantFactuur.GetEntityList(klant.ContactId).FindAll(фильтр для фактур));
вот таким макаром.

Короче танцы с бубном.

А интересно какие коллекции реализуют этот хитрый интерфейс(IBindingListView)? 
Почему спрашиваю? Потому как, класс BindingSource является наследником этого интерфейса, но он получает коллекцию BindingList<T>, а тот в свою очередь получает List<T>. И получается что, свойство класса наследника интерфейса не работает. Так на фига нужно это свойство? smile  Или что этому классу надо скармливать что бы оно работало? Или мы должны переписывать этот класс из FW что бы реализовать в нем этот хитрый интерфейс?

Короче, дело ясное, что дело темное.  smile 
 
Пойду плясать с бубном. smile 

Автор: diadiavova 14.3.2009, 20:39
Цитата(thomas @  14.3.2009,  20:23 Найти цитируемый пост)
А интересно какие коллекции реализуют этот хитрый интерфейс(IBindingListView)?

К сожалению, порадовать особо нечем. Кроме BindingSource и DataView этот интерфейс нигде не реализован. При этом биндингсорс - просто посредник, а дэйтавью ориентирован на работу с таблицами.

Автор: thomas 14.3.2009, 23:07
В общем проблему фильтра решил таким образом.
Написал вложенный класс.
Потом подсовываю его Predicate-у и при помощи метода FindAll для List<Т> нахожу все неоплаченные фактуры для заданного клиента.

Код

            private class FactuurFilter
            {
                private bool afbetaald = false;

                public FactuurFilter(bool afbetaald)
                {
                    this.afbetaald = afbetaald;
                }

                public bool MatchesFactuurType(KlantFactuur factuur)
                {
                    return factuur.Afbetaald == afbetaald;
                }
            }

        private void btnFilterFactuur_Click(object sender, EventArgs e)
        {
            this.klantFactuurBindingSource.Clear();

            //reloaden facturen van deze klant
            Contact klant = this.contactBindingSource.Current as Contact;
            FactuurFilter _factuurFilter = new FactuurFilter(false);
            Predicate<KlantFactuur> filterByType = new Predicate<KlantFactuur>(_factuurFilter.MatchesFactuurType);
            BindingList<KlantFactuur> factuurList = new BindingList<KlantFactuur>(KlantFactuur.GetEntityList(klant.ContactId).FindAll(filterByType));
            this.klantFactuurBindingSource.DataSource = factuurList;
            this.klantFactuurDataGridView.DataSource = this.klantFactuurBindingSource;
        }


Будем считать что данная конкретная задача решена.

Но вопрос об использовании свойства Filter для BindingSource при использовании в качестве источника данных коллекции вместо DataView (как в примерах в msdn ) остался открытым.

diadiavova спасибо за участие .

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)