Многозадачность интерфейса WPF UI

Я создаю некоторый пользовательский интерфейс программно, что связано с некоторой тяжелой обработкой. В основном я хочу запустить анимацию загрузчика, пока мой пользовательский интерфейс создается и добавляется в окно. Добавляемый пользовательский интерфейс представляет собой некоторые Сетки и некоторые изображения загружаются в них.

До сих пор я пробовал BackgroundWorker, но так как мне нужно использовать stream пользовательского интерфейса для добавления пользовательского интерфейса, который я создаю, загрузчик не запускается / не обновляется до тех пор, пока пользовательский интерфейс не будет добавлен.

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

private async void begin() { await this.LongRunOpAsync(); } public Task LongRunOpAsync() { return Task.Run(() => { InitGrid(); stopLoadingScreen(); }); } 

Я мог бы что-то упустить, но я не знаю, что и у меня тоже нет идей для этого. Любая помощь будет оценена по достоинству.

EDIT: метод, который имеет тяжелую работу

 private void makeIgrid() { Grid hostgrid = new Grid(); hostgrid.Name = "imagesHostGrid"; hostgrid.Width = 700; hostgrid.VerticalAlignment = VerticalAlignment.Top; hostgrid.HorizontalAlignment = HorizontalAlignment.Center; hostgrid.SetValue(Canvas.ZIndexProperty, 0); this.RegisterName(hostgrid.Name, hostgrid); Grid imagegrid = new Grid(); imagegrid.Name = "imagegrid"; imagegrid.Height = height2; //imagegrid.Width = 700; imagegrid.SetValue(Canvas.ZIndexProperty, 0); imagegrid.VerticalAlignment = VerticalAlignment.Top; imagegrid.HorizontalAlignment = HorizontalAlignment.Center; imagegrid.Margin = new Thickness(0, height1, 0, 0);//(left,top,right,bottom) RowDefinition iRow1 = new RowDefinition(); iRow1.Height = new GridLength(2, GridUnitType.Star); imagegrid.RowDefinitions.Add(iRow1); RowDefinition iRow2 = new RowDefinition(); iRow2.Height = new GridLength(70, GridUnitType.Star); imagegrid.RowDefinitions.Add(iRow2); ScrollViewer sv = new ScrollViewer { CanContentScroll = true, HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden, VerticalScrollBarVisibility = ScrollBarVisibility.Disabled }; for (int i = 0; i < images.Length; i++) { ColumnDefinition columns = new ColumnDefinition(); columns.MinWidth = 100; columns.Width = new GridLength(100, GridUnitType.Star); imagegrid.ColumnDefinitions.Add(columns); BitmapImage bmp = new BitmapImage(); bmp.BeginInit(); bmp.UriSource = new Uri(currentDirectory + "//Media//Images//" + selectedFolder + "//" + System.IO.Path.GetFileName(images[i].ToString()), UriKind.Relative); bmp.CacheOption = BitmapCacheOption.OnLoad; Debug.WriteLine("Loading: " + currentDirectory + "//Media//Images//" + selectedFolder + "//" + System.IO.Path.GetFileName(images[i].ToString())); bmp.EndInit(); Image img = new Image(); img.Name = System.IO.Path.GetFileNameWithoutExtension(images[i].ToString()); img.Source = bmp; img.VerticalAlignment = VerticalAlignment.Center; img.HorizontalAlignment = HorizontalAlignment.Center; img.TouchDown += addImagetoScreen; img.Width = 94; img.Stretch = Stretch.Uniform; img.SetValue(Canvas.ZIndexProperty, 0); this.RegisterName(img.Name, img); Border border = new Border(); border.SetResourceReference(Control.BackgroundProperty, "MenuSelected"); border.SetValue(Canvas.ZIndexProperty, 0); Grid.SetRow(border, 0); Grid.SetColumn(border, i); Grid.SetRow(img, 1); Grid.SetColumn(img, i); imagegrid.Children.Add(border); imagegrid.Children.Add(img); } sv.Content = imagegrid; sv.SetValue(Canvas.ZIndexProperty, 0); hostgrid.Children.Add(sv); mainGrid.Children.Add(hostgrid); } 

ОК. Удалите весь свой код и начните все заново.

Так вы делаете это в WPF:

                            

Код:

 public partial class ItemsControlSample2 : Window { public ItemsControlSample2() { InitializeComponent(); //Make sure you change this path to a valid path in your PC where you have JPG files var path = @"F:\Media\Images\My Drums"; var images = Directory.GetFiles(path,"*.jpg") .Select(x => new ImageViewModel() { Path = x, }); DataContext = images.ToList(); } } 

Элемент данных:

 public class ImageViewModel : INotifyPropertyChanged { private bool _isLoading; public bool IsLoading { get { return _isLoading; } set { _isLoading = value; OnPropertyChanged("IsLoading"); } } private ImageSource _imageSource; public ImageSource ImageSource { get { return _imageSource; } set { _imageSource = value; OnPropertyChanged("ImageSource"); } } private string _path; public string Path { get { return _path; } set { _path = value; OnPropertyChanged("Path"); LoadImageAsync(); } } private void LoadImageAsync() { IsLoading = true; var UIScheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task.Factory.StartNew(() => { var bmp = new BitmapImage(); bmp.BeginInit(); bmp.UriSource = new Uri(Path, UriKind.Relative); bmp.CacheOption = BitmapCacheOption.OnLoad; bmp.EndInit(); bmp.Freeze(); return bmp; }).ContinueWith(x => { ImageSource = x.Result; IsLoading = false; },UIScheduler); } #region INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } #endregion } 

Результат:

введите описание изображения здесь

  • Обратите внимание, как я декларативно определяю пользовательский интерфейс в XAML, а не процедурно создавая его в коде C #. Это гораздо более чистый подход, поскольку он позволяет WPF выполнять свою работу

  • Я использую ItemsControl который является подходящим подходом для всех пользовательских интерфейсов, основанных на «элементах», в WPF. Независимо от их внешнего вида.

  • Также обратите внимание на то, как я использую DataBinding , чтобы заполнить пользовательский интерфейс фактическими данными, а также DataTriggers , чтобы создать базовое поведение с DataTriggers состояния.

    • Пока изображение загружается ( IsLoading == true ), Image.Source имеет значение NULL и отображается TextBlock .
    • Когда изображение закончит загрузку ( IsLoading == false ), Image.Source привязан к данным ViewModel, а TextBlock скрыт.
  • Посмотрите, как я использую WrapPanel для компоновки вместо того, чтобы вручную размещать элементы. Это дает вам поведение «Explorer-like». Попробуйте resize windows, чтобы увидеть результаты.

  • Я настоятельно рекомендую вам прочитать вышеупомянутую связанную документацию, в основном материал ItemsControl, а также пост Rachel’s WPF Mentality .

  • Скалы WPF. Просто скопируйте и вставьте мой код в File -> New Project -> WPF Application и посмотрите результаты для себя.

  • Я использую C # 4.0 и .Net 4.0, поэтому у меня нет async/await . Вы должны уметь удалить весь код на основе Task и заменить его новым, более чистым асинхронным подходом.

  • Дайте мне знать, если вам нужна дополнительная помощь.

Я не вижу там никакой тяжелой работы, кроме, может быть, загрузки изображений.

В идеале вы должны создать все элементы пользовательского интерфейса (граница / grid / и т. Д.) В streamе ui и загружать изображения только в другом streamе.

Или еще лучше, вместо того, чтобы создавать все эти UI программно, вы должны использовать какую-то форму ItemsControl и DataTemplate для генерации всех ui и загружать все ваши изображения async в какую-то модель вида, например, вещь.

  • Как выполнить выбор флажка «Однократный щелчок» в WPF DataGrid?
  • WPF ListView: привязка события двойного щелчка (по элементу)
  • Модель Mvvm ViewModel
  • Связывание в WPF с элементом массива, заданным свойством
  • Таймер WPF Как таймер C #
  • Как получить доступ к элементу управления WPF c # в streamовом безопасном режиме?
  • MVVM: привязка переключателей к модели просмотра?
  • Связанное с WPF привязка данных свойств
  • Приложение WPF, в котором есть только значок в трее
  • WPF C #: переупорядочить элементы в списке с помощью перетаскивания
  • наследовать стиль от стиля по умолчанию
  • Давайте будем гением компьютера.