Example E5204
Visible to All Users

WinForms Spreadsheet - Implement a Real-Time Data Server and Use the RTD Function

This example demonstrates how to use the RTD function to retrieve data in real time from a COM Automation server.

In this example, we use a custom server that implements the IRtdServer interface. Our server provides data for stock prices, number of shares, and price change. You can use the SpreadsheetControl.Options.RealTimeData property to specify whether to update data manually or to use a timer for automatic updates.

To run the project, start Microsoft Visual Studio as an administrator. Elevated permissions are required to register the COM server after it is built.

Files to Reivew

Documentation

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

TestRTDClient/Form1.cs(vb)
C#
using DevExpress.XtraSpreadsheet; using System; namespace TestRTDClient { public partial class Form1 : DevExpress.XtraBars.Ribbon.RibbonForm { public Form1() { InitializeComponent(); spreadsheetControl1.LoadDocument("Portfolio.xlsx"); } private void barEditRefreshMode_EditValueChanged(object sender, EventArgs e) { RealTimeDataRefreshMode mode = (RealTimeDataRefreshMode)Enum.Parse(typeof(RealTimeDataRefreshMode), barEditRefreshMode.EditValue.ToString()); spreadsheetControl1.Options.RealTimeData.RefreshMode = mode; } private void barEditSpinThrottleInterval_EditValueChanged(object sender, EventArgs e) { spreadsheetControl1.Options.RealTimeData.ThrottleInterval = Int32.Parse(barEditSpinThrottleInterval.EditValue.ToString()); } private void barbButtonRefreshData_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { spreadsheetControl1.Document.RealTimeData.RefreshData(); } private void barButtonRestartServers_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { spreadsheetControl1.Document.RealTimeData.RestartServers(); } } }
TestRTDServer/RtdServer.cs(vb)
C#
using Microsoft.Office.Interop.Excel; using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows.Forms; namespace TestExcelRTDServer { [ Guid("B6AF4673-200B-413c-8536-1F778AC14DE1"), ProgId("My.Sample.RtdServer"), ComVisible(true) ] public class RtdServer : IRtdServer { IRTDUpdateEvent m_callback; Timer m_timer; Dictionary<int, TopicData> m_topics; Dictionary<string, CompanyData> companies; public RtdServer() { this.companies = new Dictionary<string, CompanyData>(); this.companies.Add("MSFT", new CompanyData("MSFT", 40, 176)); this.companies.Add("FB", new CompanyData("FB", 60, 210)); this.companies.Add("YHOO", new CompanyData("YHOO", 36, 54)); this.companies.Add("NOK", new CompanyData("NOK", 50, 100)); UpdatePrices(); } public int ServerStart(IRTDUpdateEvent callback) { m_callback = callback; m_timer = new Timer(); m_timer.Tick += new EventHandler(TimerEventHandler); m_timer.Interval = 500; m_topics = new Dictionary<int, TopicData>(); return 1; } public void ServerTerminate() { if (null != m_timer) { m_timer.Dispose(); m_timer = null; } } public object ConnectData(int topicId, ref Array strings, ref bool newValues) { if (2 != strings.Length) return "Two parameters are required"; string symbol = strings.GetValue(0).ToString(); string type = strings.GetValue(1).ToString(); TopicData data = new TopicData(symbol, type); m_topics[topicId] = data; m_timer.Start(); return GetNextValue(data); } public void DisconnectData(int topicId) { m_topics.Remove(topicId); } public Array RefreshData(ref int topicCount) { object[,] data = new object[2, m_topics.Count]; int index = 0; foreach (int topicId in m_topics.Keys) { data[0, index] = topicId; data[1, index] = GetNextValue(m_topics[topicId]); ++index; } topicCount = m_topics.Count; m_timer.Start(); return data; } public int Heartbeat() { return 1; } void TimerEventHandler(object sender, EventArgs args) { m_timer.Stop(); UpdatePrices(); m_callback.UpdateNotify(); } object GetNextValue(TopicData data) { CompanyData companyData; if (companies.TryGetValue(data.Symbol, out companyData)) { switch (data.Type) { case "PRICE": return companyData.Price; case "CHANGE": return companyData.Change; case "SHARES": return companyData.Shares; } } return "#Invalid"; } void UpdatePrices() { foreach (CompanyData companyData in companies.Values) companyData.UpdatePrice(); } } } public class TopicData { public TopicData(string symbol, string type) { Symbol = symbol; Type = type; } public string Symbol { get; } public string Type { get; } } public class CompanyData { static Random random = new Random(); public CompanyData(string symbol, double quote, int shares) { this.Symbol = symbol; this.Quote = quote; this.Shares = shares; } double Quote { get; } public string Symbol { get; } public int Shares { get; } public double Price { get; private set; } public double Change { get; private set; } public void UpdatePrice() { this.Price = Quote + (random.NextDouble() * 10.0 - 5.0); this.Change = (this.Price - this.Quote) / this.Quote; } } namespace Microsoft.Office.Interop.Excel { [Guid("A43788C1-D91B-11D3-8F39-00C04F3651B8")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] [ComImport()] [TypeIdentifier] [ComVisible(true)] public interface IRTDUpdateEvent { void UpdateNotify(); // int HeartbeatInterval { get; set; } // void Disconnect(); } [Guid("EC0E6191-DB51-11D3-8F3E-00C04F3651B8")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] [ComImport()] [TypeIdentifier] [ComVisible(true)] public interface IRtdServer { [DispId(10)] int ServerStart(IRTDUpdateEvent callback); [DispId(11)] object ConnectData(int topicId, [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] ref Array strings, ref bool newValues); [DispId(12)] [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] Array RefreshData(ref int topicCount); [DispId(13)] void DisconnectData(int topicId); [DispId(14)] int Heartbeat(); [DispId(15)] void ServerTerminate(); } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.