0

受信したデータ ポイントをプロットするリアルタイム WPF グラフィカル プロッターを作成しています。動的データ表示ライブラリを利用します。( http://dynamicdatadisplay.codeplex.com/ )

現在、アプリケーションは次のように設定されています。

  • WPF アプリケーション内でインスタンス化した ObservableCollection に変更があるたびに、グラフィカル プロッターを更新します。

  • ObservableCollection を変更する AddDataPoint(...) というカスタム メソッドを使用してデータ ポイントを追加します。

アプリケーションは環境内で期待どおりに実行されますが (F5 キーを押してソリューションをデバッグすると)、アプリケーションをテストするために「偽の」データ ポイントを渡しているためです。内部の DispatchTimer/Random.Next(..) を使用して、生成されたデータ ポイントを内部でインスタンス化された ObservableCollection に継続的にフィードします。ただし、外部クラスまたは外部データソースが「実際の」データをフィードしてグラフ化できるようにする方法がわかりません。

私は一般的にWPFとC#に本当に慣れていないので、この件に関して多くのGoogle検索を行いましたが、具体的な答えを見つけることができませんでした(つまり、データバインディング-使用のみのようですアプリケーション内でも)。外部ソースから私の WPF アプリケーションにリアルタイム データを渡すことになると、私は立ち往生します。

WPF の .exe ファイルをリソースとしてデータを提供する外部クラス/ソリューションに追加し、次を使用して WPF のインスタンスを開始しようとしました。

      "WPFAppNameSpace".MainWindow w = new "WPFAppNameSpace".MainWindow();  
      w.Show();
      w.AddDataPoint(...);

しかし、うまくいきませんでした。ウィンドウも表示されません!外部クラス (WPF アプリではない) からデータを WPF グラフ作成アプリケーションに渡すことはできますか? もしそうなら、どうすればこれを行うことができ、何を調査する必要がありますか?

これが私のプロジェクトのコード スニペットです:
XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d3="http://research.microsoft.com/DynamicDataDisplay/1.0"
        Title="MainWindow" Height="480" Width="660" Loaded="Window_Loaded" WindowState="Maximized">
    <Grid>     
        <d3:ChartPlotter Name="plotter" Margin="12,10,12,14">

            <d3:ChartPlotter.MainHorizontalAxis>
                <d3:HorizontalAxis Name="xAxis"></d3:HorizontalAxis>
            </d3:ChartPlotter.MainHorizontalAxis>

            <d3:ChartPlotter.MainVerticalAxis>
                <d3:VerticalAxis Name="yAxis"></d3:VerticalAxis>
            </d3:ChartPlotter.MainVerticalAxis>

            <d3:VerticalAxisTitle Content="Voltage"/>
            <d3:HorizontalAxisTitle Content="Test Identifier"/>
            <d3:Header TextBlock.FontSize="20" Content="Dynamically Updated Graph"/>

        </d3:ChartPlotter>

    </Grid>

</Window>

MainWindow.xaml.cs

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //Dummy Variables for Testing
        private readonly Random rand = new Random();
        private DispatcherTimer dt = new DispatcherTimer();

        ...

        //Data Sources for Graph
        private List<EnumerableDataSource<DataPoint>> enumSources;
        private List<ObservableCollection<DataPoint>> observableSources;
        private int dataSourceIndex = 0;

        public MainWindow()
        {
            InitializeComponent();
        }

        //Automatically Called after MainWindow() Finishes. Initlialize Graph.
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //Initlizes Data Sources for Graph
            enumSources = new List<EnumerableDataSource<DataPoint>>();
            observableSources = new List<ObservableCollection<DataPoint>>();

            //Adds a new Source to the Graph (New Line on Graph)
            addNewSource("Test Data " + dataSourceIndex);

            //TESTING PURPOSES
            dt.Interval = new TimeSpan(25000);
            dt.Tick += new EventHandler(timerAction);
            dt.IsEnabled = true;
            dt.Start();
        }

        //Adds data into the observableSource and alerts the enumSource to add point into Graph
        private void AsyncAppend(...) {...}

        //Adds a new DataPoint onto the Graph and Specifies if it starts a new Line.
        public void AddDataPoint(..., bool newLine) {...}

        //Tests Function for Adding New Points/New Lines to Graph; Called by Timer
        private void timerAction(object sender, EventArgs e)
        { 
            //current count of points in a particular line
            var count = observableSources[dataSourceIndex].Count;
            if (count < 100)
            {
                //Adds Data to Current Line
                AddDataPoint(...);
            }
            else
            {
                //Starts New Line and Adds Data
                AddDataPoint(..., true);
            }
        }

        //Adds a new Data Source onto the Graph (Starts a New Line)
        private void addNewSource(string legendKey){...}

        //DataPoint Object to Pass into the Graph
        private class DataPoint
        {
            //X-Coord of the Point
            public double xCoord { get; set; }

            //Y-Coord of the Point
            public double yCoord { get; set; }

            //DataPoint's Label Name
            public string labelName { get; set; }

            //Constructor for DataPoint
            public DataPoint(double x, double y, string label = "MISSNG LBL")
            {
                xCoord = x;
                yCoord = y;
                labelName = label;
            }
        }
}
4

1 に答える 1

1

Reactive Extensions の例として、0~5 秒のランダムな間隔でシミュレーションによってデータを取得するクラスを次に示します。

public class DataAquisitionSimulator:IObservable<int>
{
    private static readonly Random RealTimeMarketData = new Random();
    public IDisposable Subscribe(IObserver<int> observer)
    {
        for (int i = 0; i < 10; i++)
        {
            int data = RealTimeMarketData.Next();
            observer.OnNext(data);
            Thread.Sleep(RealTimeMarketData.Next(5000));
        }
        observer.OnCompleted();
        return Disposable.Create(() => Console.WriteLine("cleaning up goes here"));
    }
}

市場データ (この場合はランダムな整数のみ) の取得とオブザーバーへの投稿をシミュレートします。市場の待ち時間をシミュレートするために、観測の間にしばらくスリープします。

これは、コンシューマとして設定されたスケルトン クラスです...

public class DataConsumer : IObserver<int>
{
    private readonly IDisposable _disposable;
    public DataConsumer(DataAquisitionSimulator das)
    {
        _disposable = das.Subscribe(this);
        _disposable.Dispose();
    }
    public void OnCompleted()
    {
        Console.WriteLine("all done");
    }
    public void OnError(Exception error)
    {
        throw error;
    }
    public void OnNext(int value)
    {
        Console.WriteLine("New data " + value + " at " + DateTime.Now.ToLongTimeString());
    }
}

必要な 3 つのメソッドを実装し、新しいデータが出現するたびに「OnNext」が呼び出されることに注意してください。おそらく、このクラスは VM に実装され、ユーザーが視覚化できるように新しいデータをバインディング パイプラインにすぐに挿入します。

これら 2 つのクラスの相互作用を確認するには、これをコンソール アプリに追加します...

static void Main(string[] args)
{
    DataAquisitionSimulator v = new DataAquisitionSimulator();
    DataConsumer c = new DataConsumer(v);
}

スレッドを設計することが重要ですが、それ以外は、レイテンシーと不規則な観察を伴う外部データを構造化された方法でキャプチャする方法のサンプルです。

于 2013-06-05T22:44:21.303 に答える