Форум программистов, компьютерный форум, киберфорум
Наши страницы
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.88/8: Рейтинг темы: голосов - 8, средняя оценка - 4.88
AII
0 / 0 / 0
Регистрация: 19.09.2016
Сообщений: 36
1

Фильтрация DataGrid через ComboBox

10.07.2019, 07:56. Просмотров 1472. Ответов 28

Доброе время! Изучая WPF и MVVM я столкнулся с задачей, с решением которой не хватает знаний. Суть в следующем:
Приложение работает с некими товарами и определены они в Product для БД и затем в ProductVM для работы с View. Во вьюшке товары выгружаются в DataGrid. В ComboBox выводится наименование поставщиков. Задача состоит в том чтобы при выборе в ComboBox-е поставщика, в DataGrid выводились только товары у которых выбранный поставщик.
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    <ComboBox  Name="Supliers"  Width="200"
                                      
                   SelectedItem="{Binding SupplierVm, Mode=OneWayToSource}"
                   ItemsSource="{Binding supplierInfo}"
                   DisplayMemberPath="Supplier_Name"
                   SelectedIndex="0" 
                   SelectedValuePath="id" 
                   IsEditable="True"
                   IsReadOnly="True">
 
        </ComboBox>
 
 
        <GroupBox  Grid.Row="1" >
 
            <DataGrid AutoGenerateColumns="False" x:Name="productGrid" ItemsSource="{Binding ProductVM}" >
                <DataGrid.Columns>
 
                    <DataGridTextColumn Binding="{Binding Model}" Header="Модель" />
                    <DataGridTextColumn Binding="{Binding  Art}" Header="Артикул" Width="100"/>
                    <DataGridTextColumn Binding="{Binding Supplier}" Header="Поставщик" />
                    <DataGridTextColumn Binding="{Binding Category}" Header="Категория" />
                    <DataGridTextColumn Binding="{Binding Manufacturer}" Header="Производитель" />
                    <DataGridTextColumn Binding="{Binding Price}" Header="Цена" Width="70"/>
                    <DataGridTextColumn Binding="{Binding Currecurrency}" Header="Валюта" Width="70"/>
 
                </DataGrid.Columns>
            </DataGrid>
 
        </GroupBox>
Добавлено через 6 минут
Весь пример можно скачать тут https://yadi.sk/d/tkd2d6Yn54eLIQ
0
Лучшие ответы (1)
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.07.2019, 07:56
Ответы с готовыми решениями:

Фильтрация данных в WPF DataGrid
Помогите пожалуйста отфильтровать данные в DataGrid. &lt;Window.Resources&gt; &lt;my:SpringsDataSet...

Фильтрация в DataGrid по данным из TextBox или CheckBox
Подскажите как сделать фильтрацию с помощью чекбокса или текстбокса? данные в DataGrid идут с sql ...

Фильтрация ListView или DataGrid по нескольким критериям?
Допустим есть контрол таблицы неважно какой, нужно как по фото реализовать фильтр или группировку....

Combobox в DataGrid
Нужно, чтобы только одна ячейка из всего столбца содержала в себе ComboBox. Кто что может...

Combobox + datagrid + бд
Знаю тема избита, но у меня что-то не выходит есть датагрид &lt;DataGrid...

28
Почтальон
Модератор
992 / 782 / 163
Регистрация: 22.03.2015
Сообщений: 4,948
Записей в блоге: 1
Завершенные тесты: 2
10.07.2019, 07:58 2
AII, нужно фильтровать не DG, а источник данных, подцепленный к DG. В вашем случае - это ProductVM
0
AII
0 / 0 / 0
Регистрация: 19.09.2016
Сообщений: 36
10.07.2019, 08:33  [ТС] 3
Это я понимаю, но как сделать так чтобы это получалось как событие на изменение данных? То есть другими словами как организовать событие на выборку или в изменении свойства public SupplierVM SupplierVm.
0
Рядовой
738 / 477 / 206
Регистрация: 17.05.2015
Сообщений: 1,864
Завершенные тесты: 1
10.07.2019, 08:35 4
AII, повесить команду на событие. Если не знаете как - гуглите интерактивные триггеры
0
10.07.2019, 08:35
Почтальон
Модератор
992 / 782 / 163
Регистрация: 22.03.2015
Сообщений: 4,948
Записей в блоге: 1
Завершенные тесты: 2
10.07.2019, 09:06 5
В свойстве SupplierVm обрабатывайте установку значения и фильтруйте источник данных
0
AII
0 / 0 / 0
Регистрация: 19.09.2016
Сообщений: 36
10.07.2019, 09:29  [ТС] 6
Могли бы Вы накидать примерчик как это сделать?

Добавлено через 4 минуты
Просто я это уже делал, значения фильтровал, но в гриде не меняется, поэтому не могу понять как это сделать.
0
Почтальон
Модератор
992 / 782 / 163
Регистрация: 22.03.2015
Сообщений: 4,948
Записей в блоге: 1
Завершенные тесты: 2
10.07.2019, 09:32 7
AII, в сеттере SupplierVm фильтруйте коллекцию. Коллекция должна быть типа ObservableCollection. Если используете List то нужно отключать-включать источник для DG
0
AII
0 / 0 / 0
Регистрация: 19.09.2016
Сообщений: 36
10.07.2019, 10:44  [ТС] 8
AII, в сеттере SupplierVm фильтруйте коллекцию. Коллекция должна быть типа ObservableCollection. Если используете List то нужно отключать-включать источник для DG
Тогда вопрос, каким образом сделать отключать-включать источник для DG???
0
Почтальон
Модератор
992 / 782 / 163
Регистрация: 22.03.2015
Сообщений: 4,948
Записей в блоге: 1
Завершенные тесты: 2
10.07.2019, 10:52 9
AII, так вы List используете ?

Добавлено через 28 секунд
ProductVM какой тип коллекции ?
0
AII
0 / 0 / 0
Регистрация: 19.09.2016
Сообщений: 36
10.07.2019, 11:02  [ТС] 10
ProductVM

Добавлено через 1 минуту
public IEnumerable<ProductVM> ProductVM тип коллекции соответственно <ProductVM>
0
Почтальон
Модератор
992 / 782 / 163
Регистрация: 22.03.2015
Сообщений: 4,948
Записей в блоге: 1
Завершенные тесты: 2
10.07.2019, 11:06 11
AII, курите https://metanit.com/sharp/wpf/14.2.php
0
Элд Хасп
Модератор
3569 / 2575 / 840
Регистрация: 21.04.2018
Сообщений: 8,181
Записей в блоге: 2
10.07.2019, 12:14 12
Цитата Сообщение от AII Посмотреть сообщение
Задача состоит в том чтобы при выборе в ComboBox-е поставщика, в DataGrid выводились только товары у которых выбранный поставщик.
Это задача имеет два концептуально разных решения:
  • Если это касается фильтрации данных для дальнейшей обработки отфильтрованных данных, то это задача Model. И при изменении выбранного значения в ComboBox оно должно передаваться в Model, Model меняет список данных и сообщает об этом. Событие по цепочки доходит до View и View отображает изменённый список.
  • Но чаще это задача только View. То есть исходные данные менять не надо, но для пользователя нужно сделать фильтрацию. В таком случае типовым подходом является использование CollectionViewSource https://docs.microsoft.com/ru-ru/dot...tframework-4.8. Экземпляр CollectionViewSource можно объявить как в ViewModel, так и в XAML View. CollectionViewSource поддерживает динамическую сортировку. В разделе есть несколько тем с примерами применения.
0
AII
0 / 0 / 0
Регистрация: 19.09.2016
Сообщений: 36
23.07.2019, 11:53  [ТС] 13
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Это задача имеет два концептуально разных решения:
  • Если это касается фильтрации данных для дальнейшей обработки отфильтрованных данных, то это задача Model. И при изменении выбранного значения в ComboBox оно должно передаваться в Model, Model меняет список данных и сообщает об этом. Событие по цепочки доходит до View и View отображает изменённый список.
  • Но чаще это задача только View. То есть исходные данные менять не надо, но для пользователя нужно сделать фильтрацию. В таком случае типовым подходом является использование CollectionViewSource https://docs.microsoft.com/ru-ru/dot...tframework-4.8. Экземпляр CollectionViewSource можно объявить как в ViewModel, так и в XAML View. CollectionViewSource поддерживает динамическую сортировку. В разделе есть несколько тем с примерами применения.
Хороший ответ. Хотелось бы разобраться все таки с первым вариантом, когда нужно выполнить выборку из БД. Как сделать команду применительно к моему примеру?
0
Элд Хасп
Модератор
3569 / 2575 / 840
Регистрация: 21.04.2018
Сообщений: 8,181
Записей в блоге: 2
23.07.2019, 12:21 14
Цитата Сообщение от AII Посмотреть сообщение
Хотелось бы разобраться все таки с первым вариантом, когда нужно выполнить выборку из БД. Как сделать команду применительно к моему примеру?
Для конктретики нужен код вашей модели.

В общем на это примерно так. В Model по запросу в БД вы получаете DataTable из которой формируете список для отображения в View. Формировать список может как Model, так и ViewModel.

Фильтрацию можно сделать сразу при запросе в БД изменив запрос соответствующим образом. И после получения обновлённых данных сообщить в ViewModel, что данные изменились.

Так же можно сделать это изменив формируемый из DataTable список для View включив в него только элементы прошедшие фильтрацию.

Но, по-моему, для вашей задачи оптимальнее будет использовать CollectionViewSource в View.

Добавлено через 2 минуты
Цитата Сообщение от AII Посмотреть сообщение
Во вьюшке товары выгружаются в DataGrid. В ComboBox выводится наименование поставщиков. Задача состоит в том чтобы при выборе в ComboBox-е поставщика, в DataGrid выводились только товары у которых выбранный поставщик.
Если вам не нужно табличное редактирование записей (а как я понял - не нужно), то DataGrid избыточен и только будет мешать.
0
AII
0 / 0 / 0
Регистрация: 19.09.2016
Сообщений: 36
23.07.2019, 12:44  [ТС] 15
К сожалению я не могу сообразить, как мне в моем примере, оформить именно "событийность" выборки в ComboBox_е нужного нам поставщика. Я понимаю как сделать это путем события, например можно было бы наверное так:
Код
<ComboBox  Name="Supliers"  
                                      
                                       SelectedItem="{Binding SupplierVm, Mode=OneWayToSource}"
                                       ItemsSource="{Binding supplierInfo}"
                                       DisplayMemberPath="Supplier_Name"
                                       SelectedIndex="0" 
                                       SelectedValuePath="id" 
                                       IsEditable="True"
                                       IsReadOnly="True"
                                       SelectionChanged="Supliers_OnSelectionChanged"
                                       >
И затем можно было бы обработать во ViewModel выборку из БД нужных нам товаров, и записать это все в свойство ProductVM, выводя их в грид. Но так как я пытаюсь выполнить это путем MVVM, то нужно вот это написать относительно шаблона MVVM. Можно конечно на форму поставить тупо кнопку обновить и к ней привязав команду в ViewModel выполнить запрос к БД и затем обновить значения в гриде.
А как сделать применительно к моей задачи, прока не могу найти ответа.
0
Элд Хасп
Модератор
3569 / 2575 / 840
Регистрация: 21.04.2018
Сообщений: 8,181
Записей в блоге: 2
23.07.2019, 14:23 16
AII, мои комментарии и рекомендации (буду отправлять по мере написания):
  1. Если подключение ViewModel к контексту данных не требует "танцев с бубном", то VM надо подключать в XAML. Это значительно облегчает использование конструктора XAML и отладку.
    XML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    <Window x:Class="WPF_Product_SQLite.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WPF_Product_SQLite"
            xmlns:viewmodel="clr-namespace:WPF_Product_SQLite.ViewModel"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="600">
        <Window.DataContext>
            <viewmodel:ApplicationViewModel/>
        </Window.DataContext>
        <Grid>
    Старайтесь чтобы CB окна был пустой. Там нужна только одна строчка
    C#
    1
    
        public partial class MainWindow : Window { public MainWindow() => InitializeComponent(); }
0
AII
0 / 0 / 0
Регистрация: 19.09.2016
Сообщений: 36
23.07.2019, 14:45  [ТС] 17
Принял, принимается.
0
Элд Хасп
Модератор
3569 / 2575 / 840
Регистрация: 21.04.2018
Сообщений: 8,181
Записей в блоге: 2
23.07.2019, 14:53 18
2) Фильтрация выводимого списка никак не связана с фильтрацией самих данных из БД. Это нужно только для View. Поэтому лучше всего её настроить через CollectionViewSource.
Можно это сделать в XAML и CB окна.
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<Window x:Class="WPF_Product_SQLite.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF_Product_SQLite"
        xmlns:viewmodel="clr-namespace:WPF_Product_SQLite.ViewModel"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="600">
    <Window.DataContext>
        <viewmodel:ApplicationViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <CollectionViewSource x:Key="ProductVM.Filter" 
                              Filter="CollectionViewSource_Filter"
                              Source="{Binding ProductVM}" IsLiveFilteringRequested="True">
            <CollectionViewSource.LiveFilteringProperties>
                <sys:String>Supplier</sys:String>
            </CollectionViewSource.LiveFilteringProperties>
        </CollectionViewSource>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition />
        </Grid.RowDefinitions>
 
        <ComboBox  x:Name="Supliers"  Width="200"
                   SelectionChanged="Supliers_SelectionChanged"
                   SelectedItem="{Binding SupplierVm, Mode=OneWayToSource}"
                   ItemsSource="{Binding supplierInfo}"
                   DisplayMemberPath="Supplier_Name"
                   SelectedIndex="0" 
                   SelectedValuePath="id" 
                   IsEditable="True"
                   IsReadOnly="True">
 
        </ComboBox>
 
 
        <GroupBox  Grid.Row="1" >
            <DataGrid AutoGenerateColumns="False" x:Name="productGrid" ItemsSource="{Binding Mode=OneWay, Source={StaticResource ProductVM.Filter}}" >
                <DataGrid.Columns>
 
                    <DataGridTextColumn Binding="{Binding Model}" Header="Модель" />
                    <DataGridTextColumn Binding="{Binding  Art}" Header="Артикул" Width="100"/>
                    <DataGridTextColumn Binding="{Binding Supplier}" Header="Поставщик" />
                    <DataGridTextColumn Binding="{Binding Category}" Header="Категория" />
                    <DataGridTextColumn Binding="{Binding Manufacturer}" Header="Производитель" />
                    <DataGridTextColumn Binding="{Binding Price}" Header="Цена" Width="70"/>
                    <DataGridTextColumn Binding="{Binding Currecurrency}" Header="Валюта" Width="70"/>
 
                </DataGrid.Columns>
            </DataGrid>
 
        </GroupBox>
 
       
       
    </Grid>
</Window>
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    public partial class MainWindow : Window
    {
        public MainWindow() => InitializeComponent();
 
        private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
        {
            if (Supliers.SelectedItem is SupplierVM supplierVM && supplierVM.Supplier_Name != "Все" && e.Item is ProductVM productVM)
                e.Accepted = productVM.Supplier == supplierVM.Supplier_Name;
            else
                e.Accepted = true;
        }
 
        private void Supliers_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            CollectionViewSource cvs = (CollectionViewSource)Resources["ProductVM.Filter"];
            cvs.IsLiveFilteringRequested = false;
            cvs.IsLiveFilteringRequested = true;
        }
    }
Но если для какой-то обработки в VM понадобится эта фильтрация, то CollectionViewSource надо объявить в VM.
0
Элд Хасп
Модератор
3569 / 2575 / 840
Регистрация: 21.04.2018
Сообщений: 8,181
Записей в блоге: 2
23.07.2019, 14:58 19
3) Я так и не понял каким образом вы сохраняете (или собираетесь сохранять) изменённые в View данные? Если для этого у вас будет отдельная кнопка, то DataGrid подходит.
Если же данные сразу должны сохранять по окончании редактирования элемента, то с DataGrid будут сложности. Проще будет сделать ListBox или ListView и кнопки для явного добавление/удаления/редактирования записей.
0
AII
0 / 0 / 0
Регистрация: 19.09.2016
Сообщений: 36
23.07.2019, 15:02  [ТС] 20
Да, планирую редактирование, сохранение и удаление производить другими кнопками.
0
23.07.2019, 15:02
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.07.2019, 15:02

WPF. DataGrid в ComboBox
Доброго времени суток. В combobox'e должен лежать datagrid, это у меня есть (см. скрин), но...

Заполнение ComboBox в DataGrid
Приветствую, ребята, помогите разобраться с такой проблемкой. Есть DataGrid, в нем есть колонки. В...

ComboBox <=> ObservableCollection <=> DataGrid.CanUserAddRows
Подскажите как решить проблему: есть DataGrid, к которой прибиндина коллекция...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.