2010-07-01 3 views
1

У меня есть фоновый процесс, который я хочу регулярно поддерживать состояние gps-местоположения. Я не понимаю, как вызвать делегата в основном потоке в слое ui, когда метод threaded находится в другом классе. Вот пример кода. Моя форма запускает поток на нагрузке:Вызов делегата на основной поток в многоуровневой архитектуре

public partial class MainScreen : Form 
    { 
    . 
    . // form stuff 
    . 
    private void MainScreen_Load(object sender, EventArgs e) 
    { 
     var gpsStatusManager = new GpsStatusManager(); 
     Thread t = new Thread(gpsStatusManager.UpdateLocation); 
     t.IsBackground = true; 
     t.Start(); 
    } 

    delegate void GpsDataParameterDelegate(GpsStatus value); 
    public void UpdateGpsStatus(GpsStatus value) 
    { 
     if (InvokeRequired) 
     { 
      // We're not in the UI thread, so we need to call BeginInvoke 
      BeginInvoke(new GpsDataParameterDelegate(UpdateGpsStatus), new object[] { value }); 
      return; 
     } 
     // Must be on the UI thread if we've got this far 
     gpsStatus.SetGpsStatus(value); 
    } 
} 

У меня есть класс объектов домена для информации GPS:

public class GpsStatus 
{ 
    public void SetGpsStatus(GpsStatus gpsStatus) 
    { 
     Latitude = gpsStatus.Latitude; 
     Longitude = gpsStatus.Longitude; 
     CurrentDateTime = gpsStatus.CurrentDateTime; 
     NumberOfSatellites = gpsStatus.NumberOfSatellites; 
     TotalNumberSatellites = gpsStatus.TotalNumberSatellites; 
    } 

    public float Latitude { get; private set; } 
    public float Longitude { get; private set; } 
    public DateTime CurrentDateTime { get; private set; } 
    public int NumberOfSatellites { get; private set; } 
    public int TotalNumberSatellites { get; private set; } 
} 

Затем мой менеджер класса, где я обновить статус в дополнительном потоке:

public class GpsStatusManager 
{ 
    private GpsStatus _gpsStatus; 

    public void UpdateLocationx() 
    { 
     while (UpdateGpsData()) 
     { 
      Thread.Sleep(2000); 
     } 
    } 

    private bool UpdateGpsData() 
    { 
     SError error; 
     SGpsPosition gpsPosition; 
     try 
     { 
      if (CApplicationAPI.GetActualGpsPosition(out error, out gpsPosition, true, 0) != 1) 
       return false; 
     } 
     catch (Exception) 
     { 
      return false; 
     } 

     var numberOfSatellites = gpsPosition.Satellites; 
     var totalSatellites = gpsPosition.satellitesInfo; 
     var datetime = gpsPosition.Time; 
     var lat = gpsPosition.Latitude; 
     var lon = gpsPosition.Longitude; 
     _gpsStatus.SetGpsStatus(lat, lon, datetime, numberOfSatellites, totalSatellites); 

     //How do I invoke the delegate to send the _gpsStatus data to my main thread? 
     return true; 
    } 
} 

Спасибо за любую помощь.

ответ

0

Вот один из способов сделать это, в непосредственной близости от верхней части моей головы:

public class GpsStatusEventArgs : EventArgs 
{ 
    public GpsStatus Status { get; private set; } 
    public GpsStatusEventArgs(GpsStatus status) 
    { 
     Status = status; 
    } 
} 

public class GpsStatusManager 
{ 
    ... 
    public event EventHandler<GpsStatusEventArgs> GpsStatusUpdated; 

    private void OnGpsStatusUpdated(GpsStatus gpsStatus) 
    { 
     EventHandler<GpsStatusEventArgs> temp = GpsStatusUpdated; 
     if (temp != null) 
      temp.Invoke(this, new GpsStatusEventArgs(gpsStatus)); 
    } 

} 

public partial class MainScreen : Form 
{ 
    ... 
    private void MainScreen_Load(object sender, EventArgs e) 
    { 
     var gpsStatusManager = new GpsStatusManager(); 
     gpsStatusManager.GpsStatusUpdated += new EventHandler<GpsStatusEventArgs>(GpsStatusManager_GpsStatusUpdated); 
     ... 
    } 

    private void GpsStatusManager_GpsStatusUpdated(object sender, GpsStatusEventArgs e) 
    { 
     UpdateGpsStatus(e.Status); 
    } 
    ... 
} 

Затем добавьте в нижней части UpdateGpsData:

OnGpsStatusUpdated(_gpsStatus); 
0

Вы должны использовать SynchronizationContext class.

В потоке пользовательского интерфейса (в любом классе) установите поле (возможно, static) на SynchronizationContext.Current.

Затем вы можете позвонить Send или Post в сохраненный экземпляр для выполнения кода в потоке пользовательского интерфейса.

0

Вот другой подход, использующий интерфейс ISynchronizeInvoke , Это тот же шаблон, который использует класс System.Timers.Timer, чтобы поднять событие Elapsed.

public class GpsStatusManager 
{ 
    public ISynchronizeInvoke SynchronizingObject { get; set; } 

    public event EventHandler Update; 

    public void UpdateGpsData() 
    { 
    // Code omitted for brevity. 
    OnUpdate(_gpsStatus); 
    return true; 
    } 

    private OnUpdate(GpsStatus status) 
    { 
    if (SynchronizingObject != null && SynchronizingObject.IsInvokeRequired) 
    { 
     ThreadStart ts =() => { OnUpdate(status); }; 
     SynchronizingObject.Invoke(ts, null); 
    } 
    else 
    { 
     if (Update != null) 
     { 
     Update(this, status); 
     } 
    } 
    } 

    public class UpdateEventArgs : EventArgs 
    { 
    public GpsStatus Status { get; set; } 
    } 
}