在分层体系结构中调用主线程上的委托

时间:2010-07-01 16:05:31

标签: c# delegates multithreading n-tier-architecture

我有一个后台进程,我想定期维护gps位置的状态。当线程方法在另一个类中时,我不清楚如何在ui层中的主线程上调用委托。这是示例代码。我的表单在加载时启动线程:

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;
    }
}

感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

您应该使用SynchronizationContext class

在UI线程(任何类)中,将字段(可能static)设置为SynchronizationContext.Current

然后,您可以在已保存的实例上调用SendPost以在UI线程上执行代码。

答案 1 :(得分: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);

答案 2 :(得分: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; }
  }
}