|
@@ -26,15 +26,13 @@
|
|
|
>То есть создаётся приватная переменная для хранения реального значения свойства и методы **get** и **set** для, соответственно, получения и сохранения значения свойства. "value" это новое значение свойства, устанавливаемое при присваивании.
|
|
>То есть создаётся приватная переменная для хранения реального значения свойства и методы **get** и **set** для, соответственно, получения и сохранения значения свойства. "value" это новое значение свойства, устанавливаемое при присваивании.
|
|
|
|
|
|
|
|
```cs
|
|
```cs
|
|
|
-public string selectedBreed = "";
|
|
|
|
|
-
|
|
|
|
|
private IEnumerable<Cat> _catList = null;
|
|
private IEnumerable<Cat> _catList = null;
|
|
|
public IEnumerable<Cat> catList {
|
|
public IEnumerable<Cat> catList {
|
|
|
get
|
|
get
|
|
|
{
|
|
{
|
|
|
// возвращаем не весь список, а фильтрованный по выбранной породе
|
|
// возвращаем не весь список, а фильтрованный по выбранной породе
|
|
|
return _catList
|
|
return _catList
|
|
|
- .Where(c=>(selectedBreed=="Все породы" || c.breed==selectedBreed));
|
|
|
|
|
|
|
+ .Where(c => selectedBreed == "Все породы" || c.breed.title==selectedBreed);
|
|
|
}
|
|
}
|
|
|
set {
|
|
set {
|
|
|
_catList = value;
|
|
_catList = value;
|
|
@@ -89,72 +87,88 @@ public IEnumerable<Cat> catList {
|
|
|
|
|
|
|
|
* можно выбрать существующие породы из исходных данных (этот вариант предпочтительнее)
|
|
* можно выбрать существующие породы из исходных данных (этот вариант предпочтительнее)
|
|
|
|
|
|
|
|
- >Первоначальный вариант, как оказалось, не работает в **WPF** (видимо метод *DiastinctBy*) появился в C# более старших версий
|
|
|
|
|
- >
|
|
|
|
|
- >```cs
|
|
|
|
|
- >public IEnumerable<CatBreed> getCatBreeds()
|
|
|
|
|
- >{
|
|
|
|
|
- > return _catList.DistinctBy(cat => cat.breed)
|
|
|
|
|
- > .Select(cat => new CatBreed { title = cat.breed });
|
|
|
|
|
- >}
|
|
|
|
|
- >```
|
|
|
|
|
- >
|
|
|
|
|
- >Что тут происходит?
|
|
|
|
|
- >
|
|
|
|
|
- >* метод *DistinctBy* выбирает записи с уникальным значением породы
|
|
|
|
|
- >* метод *Select* преобразует исходный список - вместо списка кошек получаем список пород
|
|
|
|
|
|
|
+ Во-первых, немного поменяем класс **LocalDataProvider**, добавив кеширование списка кошек:
|
|
|
|
|
+
|
|
|
|
|
+ ```cs
|
|
|
|
|
+ public class LocalDataProvider : IDataProvider
|
|
|
|
|
+ {
|
|
|
|
|
+ // добавляем приватное поле для хранения списка кошек
|
|
|
|
|
+ private IEnumerable<Cat> _cats = null;
|
|
|
|
|
+
|
|
|
|
|
+ // в методе выбора кошек добавим проверку списка
|
|
|
|
|
+ public IEnumerable<Cat> getCats()
|
|
|
|
|
+ {
|
|
|
|
|
+ if (_cats == null)
|
|
|
|
|
+ {
|
|
|
|
|
+ _cats = new Cat[]{
|
|
|
|
|
+ // тут старый код, формирующий список кошек
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return _cats;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ```
|
|
|
|
|
+
|
|
|
|
|
+ И реализуем метод, формирующий список пород:
|
|
|
|
|
|
|
|
```cs
|
|
```cs
|
|
|
public IEnumerable<CatBreed> getCatBreeds()
|
|
public IEnumerable<CatBreed> getCatBreeds()
|
|
|
{
|
|
{
|
|
|
- return _catList
|
|
|
|
|
- .Select(cat => cat.breed)
|
|
|
|
|
- .Distinct()
|
|
|
|
|
- .Select(breed => new CatBreed { title = breed });
|
|
|
|
|
|
|
+ getCats();
|
|
|
|
|
+ return _cats
|
|
|
|
|
+ .Select(c => c.breed)
|
|
|
|
|
+ .DistinctBy(b => b.title);
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
Что тут происходит?
|
|
Что тут происходит?
|
|
|
|
|
|
|
|
- Допустим исходный массив выглядит так (массив объектов):
|
|
|
|
|
-
|
|
|
|
|
- ```
|
|
|
|
|
- [
|
|
|
|
|
- {breed: "Порода №1", name: "Имя1"},
|
|
|
|
|
- {breed: "Порода №2", name: "Имя2"},
|
|
|
|
|
- {breed: "Порода №1", name: "Имя3"}
|
|
|
|
|
- ]
|
|
|
|
|
- ```
|
|
|
|
|
|
|
+ * метод _getCats_ заполняет локальный список кошек
|
|
|
|
|
|
|
|
- * метод *Select* преобразует элемент массива в новый объект, и т.к. мы из всего объекта вернули только одно поле, то на выходе у нас будет массив пород:
|
|
|
|
|
|
|
+ Допустим исходный массив выглядит так (массив объектов):
|
|
|
|
|
|
|
|
- ```
|
|
|
|
|
|
|
+ ```json
|
|
|
[
|
|
[
|
|
|
- "Порода №1",
|
|
|
|
|
- "Порода №2",
|
|
|
|
|
- "Порода №1"
|
|
|
|
|
|
|
+ {"breed": {"title": "Порода №1"}, "name": "Имя1"},
|
|
|
|
|
+ {"breed": {"title": "Порода №2"}, "name": "Имя2"},
|
|
|
|
|
+ {"breed": {"title": "Порода №1"}, "name": "Имя3"}
|
|
|
]
|
|
]
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
- * метод *Distinct* вернёт массив уникальных занчений:
|
|
|
|
|
|
|
+ * метод _Select_ преобразует элемент массива в новый объект, и т.к. мы из всего объекта вернули только одно поле, то на выходе у нас будет список пород `IEnumerable<CatBreed>`, содержащий все породы из спика кошек:
|
|
|
|
|
|
|
|
- ```
|
|
|
|
|
|
|
+ ```json
|
|
|
[
|
|
[
|
|
|
- "Порода №1",
|
|
|
|
|
- "Порода №2"
|
|
|
|
|
|
|
+ {"title": "Порода №1"},
|
|
|
|
|
+ {"title": "Порода №2"},
|
|
|
|
|
+ {"title": "Порода №1"}
|
|
|
]
|
|
]
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
- * второй вызов *Select* преобразует массив строк в массив объектов типа **CatBreed**
|
|
|
|
|
|
|
+ * метод *DistinctBy* выбирает записи с уникальным значением породы
|
|
|
|
|
+
|
|
|
|
|
+ ```json
|
|
|
|
|
+ [
|
|
|
|
|
+ {"title": "Порода №1"},
|
|
|
|
|
+ {"title": "Порода №2"}
|
|
|
|
|
+ ]
|
|
|
|
|
+ ```
|
|
|
|
|
|
|
|
1. Получаем список пород и добавляем в начало "Все породы", чтобы можно было отменить фильтрацию и отображать полный список
|
|
1. Получаем список пород и добавляем в начало "Все породы", чтобы можно было отменить фильтрацию и отображать полный список
|
|
|
|
|
|
|
|
```cs
|
|
```cs
|
|
|
|
|
+ // добавляем в класс переменую для хранения текущё выбранной породы
|
|
|
|
|
+ private string selectedBreed = "Все породы";
|
|
|
|
|
+ ```
|
|
|
|
|
+
|
|
|
|
|
+ ```cs
|
|
|
|
|
+ // в конструкторе получаем список пород
|
|
|
catBreedList = Globals.dataProvider.getCatBreeds().ToList();
|
|
catBreedList = Globals.dataProvider.getCatBreeds().ToList();
|
|
|
- catBreedList.Insert(0, new CatBreed { title = "Все породы" });
|
|
|
|
|
|
|
+ // и добавляем в начало "все породы"
|
|
|
|
|
+ catBreedList.Insert(0, new CatBreed { title = selectedBreed });
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-1. Теперь, имея список пород, добавляем в разметку (файл .xaml) выпадающий список для выбор породы (во WrapPanel):
|
|
|
|
|
|
|
+1. Теперь, имея список пород, добавляем в разметку (файл `.xaml`) выпадающий список для выбор породы (во **WrapPanel**):
|
|
|
|
|
|
|
|
```xml
|
|
```xml
|
|
|
<Label
|
|
<Label
|
|
@@ -163,24 +177,60 @@ public IEnumerable<Cat> catList {
|
|
|
|
|
|
|
|
<ComboBox
|
|
<ComboBox
|
|
|
Name="BreedFilterComboBox"
|
|
Name="BreedFilterComboBox"
|
|
|
- SelectionChanged="BreedFilterComboBox_SelectionChanged"
|
|
|
|
|
VerticalAlignment="Center"
|
|
VerticalAlignment="Center"
|
|
|
- MinWidth="100"
|
|
|
|
|
|
|
+ MinWidth="150"
|
|
|
SelectedIndex="0"
|
|
SelectedIndex="0"
|
|
|
- ItemsSource="{Binding catBreedList}">
|
|
|
|
|
-
|
|
|
|
|
- <ComboBox.ItemTemplate>
|
|
|
|
|
- <DataTemplate>
|
|
|
|
|
- <Label
|
|
|
|
|
- Content="{Binding title}"/>
|
|
|
|
|
- </DataTemplate>
|
|
|
|
|
- </ComboBox.ItemTemplate>
|
|
|
|
|
- </ComboBox>
|
|
|
|
|
|
|
+ ItemsSource="{Binding catBreedList}"
|
|
|
|
|
+ />
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
- Элемент **ComboBox** предназначен для отображения списка *строк*. Для того, чтобы отобразить элементы произвольного списка используется шаблон **ComboBox.ItemTemplate**, в котором можно реализовать произвольный вид элемента списка (вставить картинки, раскрасить и т.п.) и, в нашем случае, в качестве содержимого выбрать свойство объекта для отображения.
|
|
|
|
|
|
|
+ Если запустить программу в таком виде, то увидим примерно такое:
|
|
|
|
|
|
|
|
- >Можно сделать проще, используя переопределение метода *getString*, но пока оставим так.
|
|
|
|
|
|
|
+ 
|
|
|
|
|
+
|
|
|
|
|
+ Вместо названий пород у нас имя класса, почему так происходит?
|
|
|
|
|
+
|
|
|
|
|
+ Элемент **ComboBox** предназначен для отображения списка **строк**, т.е. где-то под капотом он для элемента списка вызывает метод _ToString_, а этот матод как раз и возвращает название класса.
|
|
|
|
|
+
|
|
|
|
|
+ Для того, чтобы отобразить элементы другого типа данных можно использовать два варината:
|
|
|
|
|
+
|
|
|
|
|
+ * Использовать шаблон **ComboBox.ItemTemplate**, в котором можно реализовать произвольный вид элемента списка (вставить картинки, раскрасить и т.п.) и, в нашем случае, в качестве содержимого выбрать строковое свойство объекта для отображения.
|
|
|
|
|
+
|
|
|
|
|
+ ```cs
|
|
|
|
|
+ <ComboBox
|
|
|
|
|
+ Name="BreedFilterComboBox"
|
|
|
|
|
+ VerticalAlignment="Center"
|
|
|
|
|
+ MinWidth="150"
|
|
|
|
|
+ SelectedIndex="0"
|
|
|
|
|
+ ItemsSource="{Binding catBreedList}"
|
|
|
|
|
+ >
|
|
|
|
|
+ <ComboBox.ItemTemplate>
|
|
|
|
|
+ <DataTemplate>
|
|
|
|
|
+ <Label
|
|
|
|
|
+ Content="{Binding title}"/>
|
|
|
|
|
+ </DataTemplate>
|
|
|
|
|
+ </ComboBox.ItemTemplate>
|
|
|
|
|
+ </ComboBox>
|
|
|
|
|
+ ```
|
|
|
|
|
+
|
|
|
|
|
+ * Первый вариант, на мой взгляд, слишком сложен, если нам нужно вывести только одно строковое поле. В таком случае проще переопределить метод _ToString_ в классе **CatBreed**:
|
|
|
|
|
+
|
|
|
|
|
+ ```cs
|
|
|
|
|
+ public class CatBreed
|
|
|
|
|
+ {
|
|
|
|
|
+ public string title { get; set; }
|
|
|
|
|
+ public override string ToString() => title;
|
|
|
|
|
+ }
|
|
|
|
|
+ ```
|
|
|
|
|
+
|
|
|
|
|
+1. Добавим в **ComboBox** обработчик события выбора: **SelectionChanged**
|
|
|
|
|
+
|
|
|
|
|
+ ```xml
|
|
|
|
|
+ <ComboBox
|
|
|
|
|
+ Name="BreedFilterComboBox"
|
|
|
|
|
+ SelectionChanged="BreedFilterComboBox_SelectionChanged"
|
|
|
|
|
+ ...
|
|
|
|
|
+ ````
|
|
|
|
|
|
|
|
1. В классе главного окна в обработчике события выбора породы (*BreedFilterComboBox_SelectionChanged*) запоминаем выбранную породу
|
|
1. В классе главного окна в обработчике события выбора породы (*BreedFilterComboBox_SelectionChanged*) запоминаем выбранную породу
|
|
|
|
|
|
|
@@ -253,7 +303,7 @@ public IEnumerable<Cat> catList {
|
|
|
};
|
|
};
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-1. В разметке меняем привязку
|
|
|
|
|
|
|
+1. В разметке меняем привязку (аттрибут _ItemsSource_)
|
|
|
|
|
|
|
|
```xml
|
|
```xml
|
|
|
<ComboBox
|
|
<ComboBox
|
|
@@ -289,7 +339,7 @@ public IEnumerable<Cat> catList {
|
|
|
get
|
|
get
|
|
|
{
|
|
{
|
|
|
return _catList
|
|
return _catList
|
|
|
- .Where(c=>(c.age>=selectedAge.ageFrom && c.age<selectedAge.ageTo));
|
|
|
|
|
|
|
+ .Where(c=>(c.age >= selectedAge.ageFrom && c.age<selectedAge.ageTo));
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|