[C#] MultiThreading COMObject и поток пользовательского интерфейса (C #)


Answers

Я не знаю, сколько данных вы обрабатываете, или сколько времени требуется для выполнения части GUI. Вы также можете рассмотреть возможность использования заблокированных очередей. Вы можете использовать очередь в вашем ModelObj, чтобы ставить в очередь новые задачи. Это вы делаете со всем, что получаете. Тогда у вас может быть поток таймера (в потоке GUI).

Здесь вы просто проверяете заблокированную очередь, есть ли какие-то новые данные для отображения в графическом интерфейсе. Вы можете удалить весь список здесь локально. Затем вы также можете проверить, есть ли несколько данных для отображения на одном компоненте. Таким образом вы можете пропустить обновления, в которых у вас уже есть новые обновления. И вы пропускаете время для вызова потока gui для выполнения действия. Вы можете сделать несколько обновлений графического интерфейса сразу. Если у вас слишком много дел, вы можете удалить только до определенного количества элементов, чтобы графический интерфейс реагировал на взаимодействие пользователя. Однако вам нужно проверить, что очередь не постоянно растет.

Question

Это мой первый пост здесь, поскольку на самом деле я обычно решаю всю свою проблему с удивительной почтовой базой, которую вы можете найти здесь. Но я фактически застрял прямо сейчас:

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

interface IComUpdate
{
    void Update();
}

Поэтому, когда я создаю свой объект COM, каждый раз, когда появляется обновление (я не знаю, когда, его случайный), COM-сервер вызывается Update() класса объектов COM, который я реализовал.

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

На самом деле он работает:

В начале моей модели ViewModel я создаю коллекцию определенного объекта.

Этот объект, назовем его ModelObj , является частью модели и определяет статический конструктор, в котором приложение, помимо инициализации некоторых переменных, создает и запускает новый поток для COM-объекта:

Thread t = new System.Threading.Thread(() =>
           {
               System.Threading.Thread.CurrentThread.Name = "Thread of COM Object";
               IComUpdate myComObj;
               myComObj = (IComUpdate)Activator.CreateInstance(blabla);
               Application.Run();
           });

t.SetApartmentState(ApartmentState.STA);
t.Start();

Это действительно работает очень хорошо, в реализации моего COM-объекта Update() , я действительно вижу, что поток только что создан, а не поток пользовательского интерфейса.

Теперь проблема заключается в следующем: этот ModelObj я создаю, реализует интерфейс ModelObj .

Мое мышление было следующим: каждый раз, когда объект COM получает обновление, я обрабатываю данные из потока объектов COM и обновляю некоторое свойство моего экземпляра ModelObj из этого потока, поэтому эти свойства затем повышают изменение свойств моего ModelObj и Пользовательский интерфейс обновит пользовательский интерфейс.

Если обновление пользовательского интерфейса занимает слишком много времени, я могу пропустить некоторое Update() будет отображаться на экране, но объект COM будет записывать их в моем экземпляре ModelObj поэтому не очень важно, чтобы пользовательский интерфейс улавливал все обновления, я просто не сделал хотите, чтобы COM-объект должен был дождаться обновления интерфейса для повторного вызова.

Я прочитал RaisePropertyChanged("property") сообщений и подумал, что мой RaisePropertyChanged("property") потерпит неудачу.

Фактически даже в потоке COM-объекта успешно выполняется RaisePropertyChanged , поэтому, отслеживая мой код, я вижу, что он переключается на мою сборку ViewModel, где я

// Here I'm still in the thread of my COM object!
base.NotifyOfPropertyChange<string>(() => this.property)

а затем обновить пользовательский интерфейс.

Примечание. Я использую Caliburn Micro для привязки между моим представлением в WPF и моей ViewModel.

Поэтому я не могу отслеживать после этой base.NotifyOfPropertyChange<string>(() => this.property) . Возможно, Caliburn обрабатывает переключатель потоков, это не моя проблема.

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

Я хочу, чтобы поток COM-объекта ModelObj мой ModelObj который отправит для отправки пользовательскому интерфейсу сообщение для обновления (поскольку некоторые поля этого ModelObj были изменены) и продолжить немедленно , не зная, действительно ли пользовательский интерфейс обновляется или нет.

Кто-нибудь получил представление об этом поведении?

Большое спасибо.

####ОБНОВИТЬ####

Спасибо всем за такие быстрые ответы.

Я действительно сделал, как сказал З.Войкович:

Вы всегда должны обновлять графический интерфейс из потока графического интерфейса пользователя

Для полноты здесь, как я это сделал:

Поскольку мой просмотр - это полный WPF без кода, за которым я не имею никаких элементов управления или форм для вызова BeginInvoke, поэтому в статическом конструкторе моего ModelObj я создал невидимый элемент управления из потока пользовательского интерфейса, чтобы иметь возможность называть BeginInvoke на нем ,

Поэтому я объявил это:

public static Control mInvokeControl;
delegate void MyDelegate();
private MyDelegate _NotifyDelegate;

а затем сделал это в статическом конструкторе моего объекта:

mInvokeControl = new Control();
mInvokeControl.CreateControl();

в нормальном конструкторе i Инициализируйте делегат следующим образом:

_NotifyDelegate = new MyDelegate(this.NotifyByInvoke);

Тогда после того, как я просто использую его так:

ModelObj.mInvokeControl.BeginInvoke(this._NotifyDelegate );

При использовании метода:

public void NotifyByInvoke()
{
    RaisePropertyChanged("Update");
}

Все работает отлично!




Links