Nano Hash - криптовалюты, майнинг, программирование

WPF Как обновить графический интерфейс, когда фоновый поток завершает создание коллекций?

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

Это возможно? Я создаю новую структуру данных, и она выводится как pd.result в фоновом потоке. Когда поток пользовательского интерфейса проверяет, закрыто ли диалоговое окно, он должен затем установить

ModuleHierarchyVM.TopLevelModules = pd.Result as ObservableCollection<ModuleViewModel>;

после этого вызывается событие OnLoadVCD. У меня есть обработчик событий, который затем пытается установить источник элементов древовидного представления для новой коллекции.

this.AvailableModulesTreeView.ItemsSource = gvvm.ModuleHierarchyVM.TopLevelModules;

Это приводит к сбою с ошибкой: «Вызывающий поток не может получить доступ к этому объекту, потому что им владеет другой поток».

Даже не зная, как его отлаживать, стек вызовов не дает никаких реальных подробностей.

Однако, если я просто установлю для Itemsource пустую новую пустую коллекцию, например:

this.AvailableModulesTreeView.ItemsSource = (IEnumerable<object>)new List<object>();

он не вылетает (но и мои данные тоже не отображаются). Есть идеи, что могло вызвать сбой?

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

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

Полный код:

метод, вызываемый потоком пользовательского интерфейса

public bool LoadPortInterface(string VCDFileName)
{
    ProgressDialog pd = new ProgressDialog("Loading File: ", VCDFileName);
    pd.Owner = Application.Current.MainWindow;
    pd.WindowStartupLocation = WindowStartupLocation.CenterOwner;
    ModuleHierarchyVM.TopLevelModules.Clear();


    VCDData TempVCDOutput = null;
    Func<object> handler = delegate
    {
        return VCDParser.ParseVCDFileForAllPorts(VCDFileName, this, pd.Worker, out TempVCDOutput);
    };
    pd.RunWorkerThread(handler);
    pd.ShowDialog();
    if (pd.DialogResult == true)
    {
        ModuleHierarchyVM.TopLevelModules = pd.Result as ObservableCollection<ModuleViewModel>;
        VCDOutput = TempVCDOutput;
    }
    OnLoadVcd();
}

Ответ на обработчик события OnLoadVCD в графическом средстве просмотра:

void gvvm_LoadVCDEvent(object sender, EventArgs e)
{
    this.AvailableModulesTreeView.ItemsSource = gvvm.ModuleHierarchyVM.TopLevelModules;
}
11.03.2014

  • Вы передаете this в синтаксический анализатор. Я думаю, нам нужно посмотреть, что происходит в этом коде. Вы можете опубликовать это? 11.03.2014
  • Я почти уверен, что нашел свою настоящую проблему. Я попытался вызвать OnPropertyChanged для наблюдаемой коллекции. Я предполагаю, что пытался справиться с тем, что мой источник представления коллекции не обновлялся, заставляя его. Но я не понимаю, почему в одном случае это сработало без сбоев. В любом случае, теперь мне просто нужно понять, что я должен делать на самом деле. Один из вариантов - просто повторно привязать вновь созданную коллекцию Observable к источнику collectionviewsource, который я определил в xaml. Или я мог бы передать коллекцию фоновому потоку, но диспетчер WPF отправил бы любые обновления модели представления. Быть проще, держу пари 11.03.2014
  • Почему бы парсеру не вернуть List ‹ModuleViewModel›, а затем добавить его в новую коллекцию ObservableCollection в потоке пользовательского интерфейса, когда он вернется? Должен ли быть ObservableCollection в фоновом потоке? 11.03.2014
  • Нет, я попробую и посмотрю, поможет ли. Я думаю, что проблема может заключаться в моем collectionviewsource. Невозможно обновить источник коллекцииviewsource, который используется пользовательским интерфейсом? 11.03.2014
  • Нет причин, по которым вы не должны вызывать NotifyPropertyChanged для самого объекта TopLevelModules - это должно вызвать срабатывание пользовательского интерфейса для перезагрузки всей коллекции без проблем. 11.03.2014
  • добавлено много кода; надеюсь, это поможет людям разобраться в моей проблеме. так неловко 12.03.2014

Ответы:


1

Скорее всего, вы создаете, читаете или изменяете ObservableCollection в потоке, отличном от потока пользовательского интерфейса. Также убедитесь, что вы не добавляете и не удаляете из ObservableCollection что-либо, кроме потока пользовательского интерфейса.

Чтобы отладить это, установите точку останова везде, где вы получаете доступ / изменяете наблюдаемую коллекцию, и обратите внимание на номер потока (окно потока в VS), который попадает в эту точку останова. Всегда должно быть одно и то же.

Вы можете использовать другую структуру (список / массив) для хранения результатов, а затем обратный вызов в поток пользовательского интерфейса для обновления / создания ObservableCollection. Обновление ObservableCollection стоит недорого, даже для сотен элементов.

Что действительно становится дорогим, так это то, что ObservableCollection будет вызывать событие изменения при каждом изменении, которое может обрабатываться компонентами пользовательского интерфейса для изменения их макета, что в любом случае должно выполняться в потоке пользовательского интерфейса. Благодаря этой обработке событий пользовательского интерфейса ObservableCollection не позволяет вам изменять потоки.

Если вы добавляете / удаляете большое количество элементов, может быть лучше создать новую коллекцию и переназначить DataSource. Если вы всегда это делаете, вы можете использовать вместо этого список. ObservableCollection предназначен для случаев, когда вы хотите изменить список, и элемент управления изменяет только наименьшее возможное количество. Изменение DataSource (например, на List) очистит элемент управления и перестроит его, что может быть лучше для многих изменений.

Видеть:

Обновление ObservableCollection в отдельном потоке

Как мне обновить ObservableCollection через рабочий поток? < / а>

Как лучше всего обновить ObservableCollection из другого нить?

11.03.2014
  • подожди, подожди, я в замешательстве. так что, даже если наблюдаемая коллекция еще не привязана к потоку пользовательского интерфейса, я не могу получить к ней доступ из потока, отличного от пользовательского интерфейса? поэтому мне нужно сделать его списком в фоновом потоке, а затем создать наблюдаемую коллекцию из этого списка в потоке пользовательского интерфейса? это кажется супер неэффективным, если список действительно огромен. Какой смысл работать в фоновом режиме, если мне нужно для начала создать структуру данных в потоке пользовательского интерфейса? если это так, то, возможно, мне лучше вообще не использовать наблюдаемую коллекцию 12.03.2014
  • Если я вас правильно понял, то, думаю, я просто не буду беспокоиться об уведомлениях для этой структуры данных. дело в том, что древовидное представление используется только для отображения свойства имени элемента, которое никогда не должно изменяться после начальной загрузки, поэтому мне действительно не нужны уведомления об изменении свойств в древовидном представлении. 12.03.2014
  • @JamesJoshuaStreet Я предлагаю вам создать список в фоновом потоке для хранения всех ваших данных, а затем снова переключиться на поток пользовательского интерфейса и обновить наблюдаемое. Я дополню ответ более подробной информацией. 12.03.2014
  • тьфу, на самом деле я только что понял, у меня есть наблюдаемые коллекции элементов, которые содержат наблюдаемые коллекции. Это означает, что мое единственное реальное решение - просто добавить к наблюдаемым коллекциям с помощью диспетчера. Кажется глупым иметь фоновую загрузку вещей только для создания объектов с помощью диспетчера. Хотя должен признаться, что волнуюсь. Гарантированно ли диспетчер обработает элементы в том порядке, в котором я их поставил в очередь? 12.03.2014
  • фоновый поток загружает вещи * Все эти проблемы только потому, что я обнаружил, что наблюдаемые коллекции проще использовать в случае с одним потоком. Сейчас я пытаюсь использовать: Dispatcher.CurrentDispatcher.BeginInvoke (новое действие (() = ›ParentViewModel.Submodules.Add (NewModuleViewModule))); везде, где я изменяю наблюдаемую коллекцию 12.03.2014

  • 2

    Думаю, будет проще использовать TPL "Библиотека параллельных задач"

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

    var task = Task.Factory.StartNew(() =>
    {
       // write what you want to do here
    }
    

    Дополнительные примеры можно найти по этой ссылке Параллелизм задач ( Библиотека параллельных задач)

    Итак, чтобы обновить пользовательский интерфейс из потока, вы можете запустить этот поток в том же потоке пользовательского интерфейса, что и ниже:

            var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
    
            _taskFactoryWrapper.StartTask(() => DoSomeWork(viewSettings.AnyValue)).ContinueWith(task =>
            {
    
                    viewSettings.Result= task.Result;
    
            },TaskContinuationOptions.AttachedToParent)
                .ContinueWith(t => EndingUploadingProgress(viewSettings), uiContext);
    

    Таким образом, вы можете создать TaskScheduler, связанный с текущим потоком пользовательского интерфейса.]

    12.03.2014
  • это отличная идея, но я использую .net 3.5 атм 12.03.2014
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..