2013-04-25 2 views
-1

Я создал приложение, которое использует Observable Lists. Я сделал класс ObservableList потокобезопасным (я думаю), и теперь он отлично работает в моем приложении.Threading в службе Windows

Теперь я пытаюсь установить мое приложение как услугу. Это прекрасно работает и до тех пор, пока что-то не добавится в список. Я думаю, что нить там просто умирает. У меня есть следующий код:

/// <summary> 
/// Creates a new empty ObservableList of the provided type. 
/// </summary> 
public ObservableList() 
{ 
    //Assign the current Dispatcher (owner of the collection) 
    _currentDispatcher = Dispatcher.CurrentDispatcher; 
} 

/// <summary> 
/// Executes this action in the right thread 
/// </summary> 
///<param name="action">The action which should be executed</param> 
private void DoDispatchedAction(Action action) 
{ 
    if (_currentDispatcher.CheckAccess()) 
     action.Invoke(); 
    else 
     _currentDispatcher.Invoke(DispatcherPriority.DataBind, action); 
} 

/// <summary> 
/// Handles the event when a collection has changed. 
/// </summary> 
/// <param name="e"></param> 
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
{ 
    DoDispatchedAction(() => base.OnCollectionChanged(e)); 
} 

Во время отладки, я видел Collection.Add(object) называют. Он запускает функцию DoDispatchedAction, и последнее, что поражает отладчик, - _currentDispatcher.Invoke(DispatcherPriority.DataBind, action);. После этого приложение продолжается, но код после Collection.Add(object) больше не выполняется. Код, который первоначально добавил элемент в ObservableList, не продолжается. Вот почему я думаю, что нить умирает или что-то в этом роде.

При проверке действия в отладчике, я узнал, что следующее сообщение было:

ApartmentState = «_currentDispatcher.Thread.ApartmentState» бросил исключение типа «System.Threading.ThreadStateException»

Как я могу решить эту проблему? Я даже думаю в правильном направлении?

+0

Почему вы используете 'Диспетчер' в службе? – ken2k

+0

Не знаю точно. У меня есть несколько потоков и просмотр некоторых аппаратных компонентов. Что ты предлагаешь? – Joetjah

+0

Какой обработчик прикреплен к событию 'OnCollectionChanged'? Поскольку у вас нет пользовательского интерфейса (служба Windows), я подозреваю, что не требуется, чтобы маркер возвращал обработчик событий в конкретный поток. – ken2k

ответ

1

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

Вы можете свести их вместе, создав своего рода «нейтральную землю», где они встречаются.

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

В клиенте WPF будет установлен диспетчерский таймер, который вызывает этот метод с установленными интервалами и обновляет ObservableCollections с помощью моментальных снимков данных. Это возможно, потому что это произойдет в потоке пользовательского интерфейса. На самом деле, если возможно, вам следует попытаться добавить и удалить элементы из ObservableCollections, а не создавать новые экземпляры коллекции, если только данные в коллекции полностью не меняются с одного вызова на другой.

Клиент WCF будет только обертки вокруг метода, который создает моментальные снимки данных: он только отправит обратно такой снимок, когда он будет вызван.

Клиент WPF для службы WCF будет работать как локальный клиент WPF, только он будет напрямую обращаться к службе вместо аппаратной библиотеки, и, возможно, я бы выбрал более длинный интервал для DispatcherTimer, чтобы избежать чрезмерного сетевой трафик. Вы также можете оптимизировать это, вернув специальный код, который означает, что «ничего не изменилось», чтобы не отправлять одни и те же данные несколько раз или иметь отдельные методы для запроса, изменились ли данные и извлекли измененные данные.

+0

Мне нравится идея. Затем списки в «нейтральной почве» должны, вероятно, заполняться событиями, такими как «RaiseProperty», но я могу сохранить коллекцию ObservableList в клиенте WPF. – Joetjah

1

Насколько я понимаю, у вас есть код ядра, который должен работать как служба Windows, и приложение WPF, использующее один и тот же код ядра.

Так в основном вы должны иметь что-то вроде 3-х проектов в вашем решении:

  • основной сборки, что делает некоторые связанные с аппаратным обеспечением работы
  • исполняемый файл, который будет установлен в качестве службы Windows. Этот исполняемый код сборки сердечника
  • приложение WPF, который также ссылается на сборку сердечника

диспетчеры полезно Маршаллу обратно действия в потоке пользовательского интерфейса. Это в основном используется для выполнения некоторого кода в потоке пользовательского интерфейса в приложениях WPF. Например, когда вы привязываете коллекцию к DataGrid, событие CollectionChanged должно быть запущено в потоке пользовательского интерфейса, так как благодаря привязке пользовательский интерфейс будет обновляться. И UI должен обновить из потока пользовательского интерфейса.

Ваша основная сборка не должна иметь дело с диспетчерами, поскольку нет обновленного пользовательского интерфейса. Здесь вы можете использовать простой Collection, так как вы не будете привязывать его к любому компоненту пользовательского интерфейса. То же самое для исполняемого файла службы Windows.

Для вашего приложения WPF, с другой стороны, вы можете использовать ObservableCollection, привязанный к компоненту пользовательского интерфейса (например, DataGrid). Только в этой сборке вам нужно будет убедиться, что компоненты пользовательского интерфейса всегда обновляются из потока пользовательского интерфейса (что означает, что для этого вам нужен Dispatcher).

Итак, пример кода:

Основная сборка:

public IEnumerable<SomeClass> GetHardwareInfo() 
{ 
    return new List<SomeClass> { ... }; 
} 

службы Windows исполняемый файл:

internal static void Main(string[] args) 
{ 
    ... 
    var objs = new MyCoreInstance().GetHardwareInfo(); 
    ... 
} 

WPF приложения (скажем, это ViewModel):

// Some UI component is binded to this collection that is obersvable 
public ObservableCollection<SomeClass> MyCol 
{ 
    get 
    { 
     return this.myCol; 
    } 

    set 
    { 
     if (this.myCol != value) 
     { 
      this.myCol = value; 
      this.RaisePropertyChanged("MyCol"); 
     } 
    } 
} 

public void UpdateList() 
{ 
    var info = new MyCoreInstance().GetHardwareInfo(); 

    // Now, marshall back to the UI thread to update the collection 
    Application.Current.Dispatcher.Invoke(() => 
     { 
      this.MyCol = new ObservableCollection(info); 
     }); 
} 
+0

Звучит разумно. Но когда вызывается метод «UpdateList»? Причина, по которой я использовал ObservableList, заключается в том, что ListBox будет обновляться после того, как данные, привязанные к нему, будут изменены. Это все еще возможно, хотя в служебном коде больше нет ObservableList? – Joetjah

+0

@Joetjah В коде, который я предоставил, коллекция 'MyCol' является' ObservableCollection', поэтому вы можете привязать ее к вашему 'ListBox'. Вы можете вызвать «UpdateList» из любого места приложения WPF (поток рабочего потока или основной поток пользовательского интерфейса) благодаря «Application.Current.Dispatcher.Invoke». – ken2k

+0

Аппаратный компонент передает значения при изменении основной логики (службы) с использованием тех же списков ObservableCollection. Означает ли это, что я должен изменить все это на обычные списки и вместо этого использовать обработку событий, например RaisePropertyChanged? Это означает, что ObservableCollection становится бесполезным, как только вы пытаетесь развить услугу, не так ли? – Joetjah

Смежные вопросы