using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using TradeIdeas.TIProData; using TradeIdeas.MiscSupport; namespace TradeIdeas.TIProGUI { /// /// This is a wrapper around StockDataManager to help it work with a GUI. /// It handles things like automatically unsubscribing to the data when /// the a window is closed, and moving the callbacks into the correct thread. /// /// The most obvious approach to threading would be to just wrap each event /// in a call to BeginInvoke(). However, this could do much more. Perhaps /// for efficiency we only make one call to BeginInvoke for each message /// from the server, rather than one for each call to the GUI. Perhaps we /// consolidate multiple updates when the CPU is taxed. /// public class StockDataAdapter { StockDataManager _stockDataManager = StockDataManager.Find(GuiEnvironment.FindConnectionMaster("").SendManager); // Toward the user. private readonly Control _control; private readonly Action _callback; private readonly string[] _formulas; // Toward the server. private StockDataManager.Token _token; public StockDataAdapter(Control control, Action callback, params string[] formulas) { _control = control; _callback = callback; _formulas = formulas; control.Disposed += new EventHandler(control_Disposed); } void control_Disposed(object sender, EventArgs e) { Symbol = null; } private string _symbol; private bool _canceled; // For debugging and assertions, only. public string Symbol { get { System.Diagnostics.Debug.Assert(!_canceled); return _symbol; } set { System.Diagnostics.Debug.Assert(!_canceled); if (_symbol == value) // No change. return; _symbol = value; if (null != _token) { _token.Cancel(); _token = null; } if (null != _symbol) { _token = _stockDataManager.Subscribe(OnResponse, null, _symbol, _formulas); } } } public void Cancel() { Symbol = null; _control.Disposed -= control_Disposed; _canceled = true; } public RowData RowData { get; set; } private void OnResponse(StockDataManager.Response response) { _control.BeginInvokeIfRequired(delegate { if (response.Token != _token) { // This can happen sometimes, but it shouldn't happen a lot. StringBuilder sb = new StringBuilder(); sb.Append(DateTime.Now).Append(" StockDataAdpter.OnResponse(), old token"); if (_canceled) sb.Append(", this object canceled"); sb.Append(". Token.Symbol=").Append(response.Token.Symbol); foreach (string formula in response.Token.Formulas) sb.Append(", Formula=").Append(formula); sb.Append(". RowData=").Append(response.RowData); System.Diagnostics.Debug.WriteLine(sb); } else { RowData = response.RowData; _callback(this); } }); } } }