Как отобразить Spinner прогресса (или другой пользовательский интерфейс), пока WPF ListView привязан к данным? - PullRequest
3 голосов
/ 29 сентября 2010

У меня есть представление списка WPF, которое связано со списком объектов. Одним из отображаемых элементов является вычисляемое свойство (только для чтения, возвращает строку), для вычисления которого требуется небольшое количество времени. Когда окно первоначально загружается (или в любое время, когда пользовательский интерфейс обновляется событием Notify), пользовательский интерфейс будет зависать при возникновении этой привязки данных. Что мне было интересно, так это хороший механизм для решения этой проблемы (в идеале я хотел бы сделать что-то вроде выделения серого с помощью счетчика и текста «Обработка ...» или аналогичного).

Я думал, что смогу сделать это, захватив начало события, связанного с данными, и запустив историю (или аналогичную) и остановив историю, когда был запущен конец события, связанного с данными, но я не могу найти события такого рода.

Есть ли рекомендуемый механизм для работы с длинной привязкой данных или существуют события, которые я ищу, но я смотрю не в том месте? Любая помощь будет оценена.

РЕДАКТИРОВАТЬ: Я могу получить значок вращения (Cursor.Wait), пока данные получены и привязаны к данным (используя части решения ниже), но теперь нужно знать, когда привязка данных завершено. Кажется, что событие .Loaded срабатывает, когда элемент управления помещается на экран (что происходит сразу), но не происходит при обновлении данных. Похоже, что для ListView нет события типа OnDataBoundCompleted, есть идеи / мысли о том, как получить уведомление о завершении процесса привязки данных?

РЕДАКТИРОВАТЬ: Глядя на событие TargetUpdated сейчас, но получить некоторые странные результаты. Если я помещаю окно сообщения в обработчик событий для TargetUpdated, то пользовательский интерфейс обновляется (ListView отображает данные), а затем отображается окно сообщения. Если я вырезал окно сообщения и просто установил переменную (то есть IsBusyCursor = Cursors.Arrow), это делается до того, как ListView отобразит данные.

** РЕШЕНИЕ: ** Я закончил тем, что создал новый объект представления и установил Cursor = Wait, затем зацикливался на объектах, которые я ранее привязал к ListView, и создавал объекты представления из них (что вызвало выполнение вычисляемого свойства) затем, как только список объектов презентации был создан, свяжите его с ListView и выполните stet Cursor = Arrow. Разочарованный, похоже, не является событием типа DataBinding Completed (или каким-либо другим событием, инициируемым после завершения привязки данных, которое обновляет пользовательский интерфейс), но это решение работает.

Ответы [ 3 ]

5 голосов
/ 29 сентября 2010

У меня похожая ситуация ChrisHDog.Я использую MVVM, и это то, что я делаю:

Сначала, в моей ViewModel, я устанавливаю свойство с именем IsBusy:

public bool IsBusy
{
   get { return _isBusy; }
   set
   {
      _isBusy = value;
      NotifyPropertyChanged("IsBusy");
   }
}

Затем, когда дело доходит до загрузки фактических данных,Я запускаю асинхронное событие.Но прямо перед этим я установил для свойства IsBusy значение trueВ моем XAML я привязываю курсор к этому:

<UserControl x:Class="UserControls.Views.AgentListView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:Converters="clr-namespace:UserControls.Utility.Converters" 
             xmlns:Controls="clr-namespace:UserControls.Controls" 
             xmlns:DependencyProperties="clr-namespace:UserControls.DependencyProperties" 
             Cursor="{Binding IsBusy, Converter={Converters:CursorExtensionConverter}}" >

CursorExtensionConverter - это просто простой IValueConverter для преобразования логического значения в правильное значение Cursor, которое может быть понято XAML:

namespace UserControls.Utility.Converters
{
  public class CursorExtensionConverter : MarkupExtension, IValueConverter
  {
    private static CursorExtensionConverter instance = new CursorExtensionConverter();

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
      if (value != null && ((bool) value))
        return Cursors.Wait;
      else
        return Cursors.Arrow;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
      throw new NotImplementedException();
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
      return instance;
    }

  }
}

Когда данные завершаются асинхронной выборкой, я перенаправляю их обратно в поток пользовательского интерфейса, а затем устанавливаю для свойства IsBusy значение false.Затем курсор возвращается в нормальное состояние.

Что касается асинхронных вызовов и маршалинга обратно в пользовательский интерфейс, я оставлю это для вас, чтобы посмотреть вверх, так как это другая часть этого ответа.Я использую делегат Action и называю его асинхронным с BeginInvoke, а затем перенаправляю обратно в поток пользовательского интерфейса, используя метод, который я нашел здесь: http://www.wintellect.com/CS/blogs/jlikness/archive/2009/12/16/dispatching-in-silverlight.aspx.

Надеюсь, это поможет!

1 голос
/ 29 сентября 2010

Взгляните на текущий поток , где я объясняю базовый BackgroundWorker , и посмотрите, даст ли вам достаточно информации.

По сути, у вас будет функция, которая отображает ваш элемент управления «Please Wait», а затем использует BackgroundWorker для выполнения долгосрочных вычислений в другом потоке. Когда вычисление завершено, возникает другое событие, сообщающее, что BackgroundWorker завершен, и вы можете затем скрыть элемент управления «Please Wait» и связать данные. При желании вы можете сообщить о ходе расчета, если это возможно.

0 голосов
/ 04 октября 2010

Я закончил тем, что создал новый объект презентации и установил Cursor = Wait, затем перебрал объекты, которые я ранее привязал к ListView, и создал из них объекты презентации (что привело к выполнению вычисляемого свойства), а затем один раз в списке презентации. были созданы объекты, привязанные к ListView и stet Cursor = Arrow.

Разочаровано, что нет события типа DataBinding Completed (или любого другого события, которое запускается после завершения привязки данных, которое обновляет пользовательский интерфейс), но это решение работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...