【问题标题】:Invoke a delegate on the main thread in a tiered architecture在分层架构中的主线程上调用委托
【发布时间】:2010-07-01 16:05:31
【问题描述】:

我有一个后台进程,我想定期维护 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;
    }
}

感谢您的帮助。

【问题讨论】:

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


    【解决方案1】:

    这是一种方法,就在我的脑海中:

    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】:

      您应该使用SynchronizationContext class。

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

      然后您可以在保存的实例上调用Send 或Post 以在UI 线程上执行代码。

      【讨论】:

        【解决方案3】:

        这是使用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; }
          }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-04-09
          • 1970-01-01
          • 2014-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多