WPF лезет в базу - как задержать?
От: Kolesiki  
Дата: 01.10.21 13:24
Оценка:
Ребят, хитрый вопрос по поведению приложения: есть "морда к базе". Перед работой, разумеется, делается логин в базу (юзер вводит пароль). Только после этого становятся доступными данные таблиц.
НО(!) на главной форме есть комбобокс, куда засасываются справочные данные, используя сам же XAML:

<ComboBox ItemsSource="{Binding PersonStatus, Source={x:Static local:App.Current}}" />


Проблема в том, что как только главная форма инициализирована (но до логина), она пытается заполнить комбобокс и лезет в App.PersonStatus , который разумеется требует уже авторизованное соединение с базой, а оно у меня ещё null.

Решение №1 — тупо загружать комбобокс из кода. Что совсем не интересно и не эстетично.

Решение №2 МОГЛО БЫ сработать, если бы у комбобокса была отложенная загрузка. Что обидно: где НЕ надо, отважные индусы вкорячили в WPF "отложенную загрузку" всего и вся, но вот для ItemsSource её почему-то нет! (ведь я ещё не раскрывал ComboBox, зачем УЖЕ сосать туда данные?)

Решение №3 — открывать отдельное read-only соединение к базе (ещё перед инитом формы) и сосать справочные данные оттуда. Но это костыль и самое последнее, что хочется делать.

Есть какие-то ещё варианты, как задержать загрузку ItemsSource?
Re: WPF лезет в базу - как задержать?
От: Sharov Россия  
Дата: 01.10.21 14:55
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>Решение №3 — открывать отдельное read-only соединение к базе (ещё перед инитом формы) и сосать справочные данные оттуда. Но это костыль и самое последнее, что хочется делать.

K>Есть какие-то ещё варианты, как задержать загрузку ItemsSource?

Нормальный вариант, в чем проблема прочитать данные из таблицы? Ну придется заморочится с правами
доступа для этой и других таблиц разве что.
Кодом людям нужно помогать!
Re: WPF лезет в базу - как задержать?
От: alexsmirnoff  
Дата: 01.10.21 15:03
Оценка:
Здравствуйте, Kolesiki, Вы писали:


K>Решение №1 — тупо загружать комбобокс из кода. Что совсем не интересно и не эстетично.


Почему?

K>Есть какие-то ещё варианты, как задержать загрузку ItemsSource?


Дак тут получается не "задержать", а "держать, пока не выполнено условие".
Разве нельзя его создать задизабленным, а после логина раздизаблить?
Re: WPF лезет в базу - как задержать?
От: Osaka  
Дата: 02.10.21 01:17
Оценка: +2
K><ComboBox ItemsSource="{Binding PersonStatus, Source={x:Static local:App.Current}}" />
K>Есть какие-то ещё варианты, как задержать загрузку ItemsSource?
Оставить при старте этот PersonStatus пустым, затем когда появится соединение с базой — загрузить в него данные и вызвать ему PropertyChanged.
Re: WPF лезет в базу - как задержать?
От: karbofos42 Россия  
Дата: 02.10.21 07:21
Оценка: 2 (2) +4
Здравствуйте, Kolesiki, Вы писали:

K>Есть какие-то ещё варианты, как задержать загрузку ItemsSource?


Решение № 4: Сделать нормальную ViewModel для окна, а не биндить к классу приложения.
В этой ViewModel уже изначально оставить коллекцию пустой, а после аутентификации подгрузить данные в неё. Коллекцию сделать ObservableCollection, чтобы WPF подхватывал её изменения автоматом.
Re[2]: WPF лезет в базу - как задержать?
От: Kolesiki  
Дата: 03.10.21 11:32
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Нормальный вариант, в чем проблема прочитать данные из таблицы? Ну придется заморочится с правами доступа для этой и других таблиц разве что.


Вот это. Потому что:
1. Никто не Ванга и я не знаю, что мы будем использовать завтра. Может, это будут REST-сервисы, может Postgres, может ещё какая хрень. Завязываться на возможность "readonly соединения" не хочется.
2. Это лишний коннекшн, за которым тоже придётся следить, вовремя менять conn.string и т.п.
3. Лишний гемор при сетапе. Особенно для "людей в поле" (слабоквалифицированные технари, которые максимум могут запустить setup.exe).

Ну то есть я не отвергаю его категорически, но показал как не самый лучший вариант.
Re[2]: WPF лезет в базу - как задержать?
От: Kolesiki  
Дата: 03.10.21 11:35
Оценка:
Здравствуйте, alexsmirnoff, Вы писали:

K>>Решение №1 — тупо загружать комбобокс из кода. Что совсем не интересно и не эстетично.


A>Почему?


Потому что декларативно это удобнее: объявлен контрол и ВСЕ сопутствующие ему настройки, т.е. сам C# код — чистый.

K>>Есть какие-то ещё варианты, как задержать загрузку ItemsSource?


A>Дак тут получается не "задержать", а "держать, пока не выполнено условие".

A>Разве нельзя его создать задизабленным, а после логина раздизаблить?

Пробовал — НЕ ПОМОГАЕТ! Я даже больше скажу — этот комбобокс лежит на задизэйбленом табе, который даже не выбран!! Т.е. у мелкомягких макак было как минимум ТРИ препятствия-условия, при которых ну совсем не надо лезть за данными! ППЦ....
Re[2]: WPF лезет в базу - как задержать?
От: Kolesiki  
Дата: 03.10.21 11:36
Оценка:
Здравствуйте, Osaka, Вы писали:

O>Оставить при старте этот PersonStatus пустым, затем когда появится соединение с базой — загрузить в него данные и вызвать ему PropertyChanged.


Это равносильно тупо загрузить его в коде после логина. Не очень хочется загружать код.
Re[2]: WPF лезет в базу - как задержать?
От: Kolesiki  
Дата: 03.10.21 11:42
Оценка: :))
Здравствуйте, karbofos42, Вы писали:

K>Решение № 4: Сделать нормальную ViewModel для окна, а не биндить к классу приложения.


Для сферического мира хелловорлдов — да, это "нормальную ViewModel". Но не везде и не всегда удобно городить отдельный почти дублирующий слой VM-классов. Вообще, на будущее: MVVM — далеко не идеальная модель, лучше не бросаться замусоривать проект "идеологиями".

K>В этой ViewModel уже изначально оставить коллекцию пустой, а после аутентификации подгрузить данные в неё. Коллекцию сделать ObservableCollection, чтобы WPF подхватывал её изменения автоматом.


Это практически ничем не отличается от того, чтобы тупо загрузить данные после логина. Было. Не хочу.

В целом, это как бы и не страшная проблема — так или иначе я догружу. Но имея декларативный XAML, хочется побольше взвалить на него. Просто бывает, что не знаешь каких-то тонкостей, где одним атрибутом можно решить все проблемы.
Re[3]: WPF лезет в базу - как задержать?
От: Sharov Россия  
Дата: 03.10.21 12:39
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>Вот это. Потому что:

K>1. Никто не Ванга и я не знаю, что мы будем использовать завтра. Может, это будут REST-сервисы, может Postgres, может ещё какая хрень. Завязываться на возможность "readonly соединения" не хочется.

Так это все на стороне бд, настройки и т.д. Разве что бд поменяется, но это довольно редкое явление.

K>2. Это лишний коннекшн, за которым тоже придётся следить, вовремя менять conn.string и т.п.


Вот тут не уверен(не знаю). Скорее всего понадобиться отдельный логин и пароль для такого пользователя.
А cs будет таже.

K>3. Лишний гемор при сетапе. Особенно для "людей в поле" (слабоквалифицированные технари, которые максимум могут запустить setup.exe).


Да, возможно. Ну будет же скрипт, который будет создавать бд. Вот туда и добавить эту логика со спец. пользователем
с правами только на чтение таблицы.
Кодом людям нужно помогать!
Re[3]: WPF лезет в базу - как задержать?
От: karbofos42 Россия  
Дата: 03.10.21 18:54
Оценка: +4
Здравствуйте, Kolesiki, Вы писали:

K>Здравствуйте, karbofos42, Вы писали:


K>>Решение № 4: Сделать нормальную ViewModel для окна, а не биндить к классу приложения.


K>Для сферического мира хелловорлдов — да, это "нормальную ViewModel". Но не везде и не всегда удобно городить отдельный почти дублирующий слой VM-классов. Вообще, на будущее: MVVM — далеко не идеальная модель, лучше не бросаться замусоривать проект "идеологиями".


Как раз для хелловорлда можно забить и не дублировать.
"Дублирующий" слой больше контроля в итоге даст и поддержка проще будет.
А биндинг — это не замусоривание?
А в класс Application коллекции из БД грузить — это нормально?

K>>В этой ViewModel уже изначально оставить коллекцию пустой, а после аутентификации подгрузить данные в неё. Коллекцию сделать ObservableCollection, чтобы WPF подхватывал её изменения автоматом.


K>Это практически ничем не отличается от того, чтобы тупо загрузить данные после логина. Было. Не хочу.


Суть была в VM и намёк на то, что биндить к свойству Application — сомнительная практика.
Так-то можно завести две разные VM — для неавторизованного состояния и для авторизованного.
Либо селектором выбирать разные шаблоны в зависимости от состояния.
Запустилась программа — в окне показывается, что данных нет, нужно пройти аутентификацию.
Залогинились — теперь уже в окне все данные, которые подгрузились из БД.
VM будет создаваться после аутентификации, так что доступ к БД уже будет и только в этот момент начнут запрашиваться данные и т.п.

K>В целом, это как бы и не страшная проблема — так или иначе я догружу. Но имея декларативный XAML, хочется побольше взвалить на него. Просто бывает, что не знаешь каких-то тонкостей, где одним атрибутом можно решить все проблемы.


Этот самый XAML завязан на MVVM и биндинги все эти нормально работать будут только при условии реализации конкретных интерфейсов и т.п.
Как раз, либо это остаётся на "дублирующем слое" VM и не перемешивается с моделью и "идеология" не замусоривает проект. Либо модель будет допиливаться под View и тогда всё будет прибито гвоздями к WPF и т.п.
Re: Иерархично
От: Quebecois Канада https://www.canada.ca/
Дата: 04.10.21 02:06
Оценка: +1
Здравствуйте, Kolesiki, Вы писали:

Вместо:
<ComboBox ItemsSource="{Binding PersonStatus, Source={x:Static local:App.Current}}" />


делаем:

<ComboBox ItemsSource="{Binding Path=DBConnection.PersonStatus, Source={x:Static local:App.Current}}" />


DBConnection обновляем с PropertyChanged после загрузки. Все элементы, от него зависящие, обновляются.

Если полей много, то это упрощается через наследование DataContext:

<Grid DataContext="{Binding DBConnection, Source={x:Static local:App.Current}}">
<ComboBox ItemsSource="{Binding PersonStatus}" />
</Grid>
Re[4]: WPF лезет в базу - как задержать?
От: Mr.Delphist  
Дата: 04.10.21 08:23
Оценка: -1
Здравствуйте, karbofos42, Вы писали:

K>Здравствуйте, Kolesiki, Вы писали:


K>>Здравствуйте, karbofos42, Вы писали:


Коллега, не тратьте сил.
INotifyPropertyChanged и INotifyCollectionChanged
От: igor-booch Россия  
Дата: 05.10.21 15:11
Оценка:
K>
K><ComboBox ItemsSource="{Binding PersonStatus, Source={x:Static local:App.Current}}" />
K>


K>Есть какие-то ещё варианты, как задержать загрузку ItemsSource?


2 варианта:
    1. App должен реализоовать INotifyPropertyChanged, когда залогинились делаем так, чтобы PersonStatus возвращал заполненную коллекцию и шлём PropertyChanged на свойство PersonStatus
    2. PersonStatus должен возвращать ObservableCollection (INotifyCollectionChanged), когда залогинились заполняем эту коллекцию
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Отредактировано 05.10.2021 15:15 igor-booch . Предыдущая версия . Еще …
Отредактировано 05.10.2021 15:13 igor-booch . Предыдущая версия .
Отредактировано 05.10.2021 15:12 igor-booch . Предыдущая версия .
Re: WPF лезет в базу - как задержать?
От: Vladek Россия Github
Дата: 06.10.21 05:52
Оценка:
Здравствуйте, Kolesiki, Вы писали:

K>Ребят, хитрый вопрос по поведению приложения: есть "морда к базе". Перед работой, разумеется, делается логин в базу (юзер вводит пароль). Только после этого становятся доступными данные таблиц.

K>НО(!) на главной форме есть комбобокс, куда засасываются справочные данные, используя сам же XAML:

K>
K><ComboBox ItemsSource="{Binding PersonStatus, Source={x:Static local:App.Current}}" />
K>


Это всё решения из разряда https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D0%B0_XY

K>Есть какие-то ещё варианты, как задержать загрузку ItemsSource?


Биндинг должен работать сразу, просто источник данных сначала будет выдавать пустой список, а когда он станет готов — выдаст полный список. В WPF для этого всё есть: ListCollectionView в связке с ObservableCollection.

Лучше всего завести модель вида для главной формы, ей добавить свойство с этим списком — заполнить список данными, когда он будет готов. WPF подхватит всё это автоматом.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.