#wpf #data-binding
#wpf #привязка к данным
Вопрос:
У меня есть приложение WPF, и дизайн соответствует стандартной модели MVVM.
Когда базовые данные изменяются, моя модель представления запускает событие PropertyChanged, чтобы элементы управления могли обновляться.
Мой основной вид — это элемент управления tab, поэтому большинство элементов управления невидимы в любой момент времени. Существуют проблемы с производительностью, и я понял, что большая часть процессорного времени отводится на выборку данных для обновления невидимых элементов управления. (Моя модель представления использует отложенную оценку, поэтому она запускает события PropertyChanged, но фактически не вычисляет конечные отображаемые свойства, пока их не спросят).
Есть ли у WPF стандартный способ решения этой проблемы?
В идеале, если невидимый элемент управления получает соответствующее событие PropertyChanged, он должен просто подумать «Я должен запросить это свойство, как только я снова стану видимым«.
Комментарии:
1. Я не думаю, что есть, хотя было бы весьма полезно.
Ответ №1:
Я не думаю, что существует какая-либо инфраструктура для деактивации привязок, связанных с невидимыми элементами управления. К сожалению, есть много ситуаций, в которых вы хотели бы, чтобы элемент управления, который не виден, участвовал в привязке данных. Самое главное, у вас часто есть элемент управления, видимость которого сама по себе зависит от привязки. Кроме того, у вас может быть привязка между свойствами видимого элемента управления и невидимого элемента управления. Или кто-то может захотеть прямо противоположное тому, что вы хотите: элемент управления должен заполняться, пока он невидим, а затем выскакивать полностью заполненным, как только он станет видимым.
Я думаю, что единственное хорошее решение для вашей ситуации — избегать использования тяжелых невидимых элементов управления, если это возможно. В частности, для вашего элемента управления tab я бы подумал, что это будет поведение по умолчанию, но, возможно, это зависит от вашей ситуации. По иронии судьбы некоторые люди жалуются, что TabControl
уничтожает своих дочерних элементов при переключении между вкладками, и хотели бы знать, как это предотвратить, потому что сохранение всех фоновых вкладок в памяти требует некоторой работы. Но у вас, похоже, противоположная проблема.
Для справки, вот источник, который я упомянул для TabControl
дочерних элементов:
Возможно, вы сможете провести несколько экспериментов в небольшом проекте, чтобы «включить» поведение рециркуляции, которое они пытаются отключить. Если бы ваш элемент управления загружался по требованию, переключение вкладок могло бы быть немного медленнее, но производительность на вкладке улучшилась бы.
Комментарии:
1. По устаревшим причинам это фактически элемент управления вкладкой WinForms с несколькими вкладками, содержащими элементы управления WPF через ElementHost. Возможно, моя проблема не соответствует обычному поведению элемента управления tab.
2. Кроме того, спасибо за предоставление отличного контраргумента предпосылке заголовка. (Я экспериментирую со спорными заголовками, чтобы посмотреть, получают ли они больше чтения :-).
3. Интересный вопрос. Я надеюсь, вы найдете решение. В моем случае ваша стратегия сработала. 🙂
4. @Andrew Shepard: На самом деле вы можете реализовать желаемое поведение, извлекая из
ElementHost
и создавая экземпляры своих субконтролей по требованию на основе видимости. Тогда используйте свойLazyElementHost
систематически, а неElementHost
в элементе управления tab.
Ответ №2:
Мы сделали что-то в этом роде в нашей базовой ViewModel..
Обратите внимание, вы должны заморозить / разморозить в соответствии с видимостью представления.
По сути, он захватывает все события PropertyChanged во время замораживания и выталкивает их при размораживании. При этом также не сохраняются дубликаты, поскольку в нашем случае они не имеют значения.
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private readonly HashSet<string> hashSet = new HashSet<string>();
private bool isFrozen;
protected void RaisePropertyChanged(string propertyName)
{
if (isFrozen)
{
lock (hashSet)
{
hashSet.Add(propertyName);
return;
}
}
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
protected void Freeze()
{
isFrozen = true;
}
/// <summary>
/// Enable PropertyChanged Events to fire again
/// </summary>
protected void Thaw(bool fireQueued)
{
isFrozen = false;
if (fireQueued)
{
lock (hashSet)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
foreach (string propertyName in hashSet)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
hashSet.Clear();
}
}
else
{
hashSet.Clear();
}
}
}
Ответ №3:
Моя базовая модель представления имеет свойство isVisible. Когда модель представления невидима, просто подавляйте уведомления об изменении свойств. Когда они становятся видимыми, запускайте событие изменения свойства для каждого свойства (pr передает значение null к имени свойства)