2017-11-09 11 views
0

WPFを初めて使用するときに問題があります。 別のスレッドから私のoxyplotモデルを更新できません。 別のスレッドでポイントを描画することはできますが、別のスレッドでポイントを描画することはできますが、別のスレッドでポイントを描画することはできません。 は、今私はこのコードを持っている:別のスレッドからオキシプロットモデルを更新する

private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     doComputingThread compute = new doComputingThread(); 
     Thread _MainThread = new Thread(new ThreadStart(compute.MainThread)); 
     _MainThread.Start(); 
    } 

class doComputingThread{ 
    public doComputingThread() 
    { 
     DataPlot = new PlotModel(); 
     DataPlot.Series.Add(new LineSeries()); 
    } 
    public void MainThread() 
    { 
     bool flag; 

     _timer = new System.Timers.Timer(); 
     _timer.Interval = 10; 
     _timer.Elapsed += (sender, e) => { GuiRefresher(true); }; 
     _timer.Enabled = true; 

     Thread _ComputeThread = new Thread(new ThreadStart(ProducerThread)); 
     _ComputeThread.Start(); 
    } 
    public void ProducerThread() 
    { 
     //populate queue 

     int X = 0; 
     int Y = 0; 

     for (double t = 0; t < 2 * 3.14; t = t + 0.1) 
     { 
      X = (int)(Math.Cos(t) * 5000); 
      Y = (int)(Math.Sin(t) * 5000); 


      Coordinate.X = X; 
      Coordinate.Y = Y; 
      _queue.Enqueue(Coordinate); 
     } 
    public void GuiRefresher(object flag) 
    { 

     if (_queue.TryDequeue(out Coordinate)) 
     { 
      //this part didn't refresh my oxyplot 
      Dispatcher.CurrentDispatcher.Invoke(() => 
      { 
       (DataPlot.Series[0] as LineSeries).Points.Add(new DataPoint(Coordinate.X, Coordinate.Y)); 
       DataPlot.InvalidatePlot(true); 
      }); 

}

一部Dispatcher.CurrentDispatcher除いて期待通りにすべての作業します。なぜ私のプロットが更新されなかったのか分からなかった。

私はWPFでこの場合UIスレッドがどのスレッドであるのか分からず、おそらくdoComputingThreadコンストラクタでスレッドを開始する必要があるという考えがあります。

XAML:

<ui:WslMainWindow x:Class="fpga_control.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:oxy="http://oxyplot.org/wpf" 
    xmlns:local="clr-namespace:fpga_control" 
    xmlns:ui="clr-namespace:Keysight.Ccl.Wsl.UI;assembly=Keysight.Ccl.Wsl" 
    xmlns:DynamicVectorImages="clr-namespace:Keysight.Ccl.Wsl.UI.Controls.DynamicVectorImages;assembly=Keysight.Ccl.Wsl" 
    Title="Example 1 (WPF)" Height="461.311" Width="621.393"> 
<Window.DataContext> 
    <local:MainViewModel/> 
</Window.DataContext> 
<Grid > 
    <oxy:PlotView Model="{Binding DataPlot}" Margin="10,10,152,0" Height="418" VerticalAlignment="Top"/> 
    <Button Content="Button" HorizontalAlignment="Left" Margin="464,10,0,0" VerticalAlignment="Top" Width="137" Height="38" RenderTransformOrigin="0.303,1.929" Click="Button_Click"/> 
    <TextBox x:Name="txb" HorizontalAlignment="Left" Height="23" Margin="468,53,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="133"/> 
</Grid> 

答えて

2

あなたのコードでは、ループ内でキューに同じ座標を追加しているように見えます。ループ中に毎回新しいCoordinateインスタンスを作成していません。

また、あなたの_queue.TryDequeue(out Coordinate)行は、クラスではなく変数としてCoordinateを使用しようとしているので、私には構文エラーが発生します。

Coordinateの定義がありません。これは何も確認できません。

また、フォームに実際にDataPlotを追加した場所がわかりません。いずれにしても何も表示していないようです。

例のコードは、最小限で完全で検証可能な例ではありません。だから私は問題が何であるかを推測するだけです。

私はあなたにあなたが望むものを与えると思う選択肢を提供します。 - ここだ

public class Coordinate 
{ 
    public int X; 
    public int Y; 
} 

は、今私は、スレッド、計算、およびコードの派遣のすべてを行うには、Microsoftの反応Frameworkのを使用するつもりです:私はCoordinateのための簡単な定義を提供していますで開始する

私はButton_Clickハンドラ書くでしょうか:

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    DataPlot = new PlotModel(); 
    DataPlot.Series.Add(new LineSeries()); 

    int steps = 60; 
    IObservable<Coordinate> query = 
     Observable 
      .Generate(
       0, 
       n => n < steps, 
       n => n + 1, 
       n => n * 2.0 * Math.PI/steps, 
       n => TimeSpan.FromMilliseconds(10.0)) 
      .Select(t => new Coordinate() 
      { 
       X = (int)(Math.Cos(t) * 5000), 
       Y = (int)(Math.Sin(t) * 5000), 
      }); 

    IDisposable subscription = 
     query 
      .ObserveOnDispatcher() 
      .Subscribe(c => 
      { 
       (DataPlot.Series[0] as LineSeries).Points.Add(new DataPoint(c.X, c.Y)); 
       DataPlot.InvalidatePlot(true); 
      }); 
} 

このコードでは、あなたは、もはや全くあなたdoComputingThreadクラスを必要としません。

Observable.Generateコードは、元のコードが生成60データ・ポイントのt値を生成するが、それはすべての10.0ミリ秒の時間でこれだけ一つの値を行います。このコードは実質的にタイマーであり、tステップのプロデューサーです。

.Selectは、tの値をCoordinate値にマッピングします。

subscriptionは、queryの実行です。最初のステップは、.ObserveOnDispatcher()コールを使用して値をUIスレッドにマーシャリングし、.Subscribeが各値を取り、UIスレッドでc => ...デリゲートを実行することです。

これはプロットをうまく更新するはずです。

早くプロットを停止したい場合は、subscription.Dispose()に電話すると停止します。

ビットを取得するには、NuGet "System.Reactive"と "System.Reactive.Windows.Threading"が必要です。また、次のusing文はコードをコンパイルするために取得する必要があります。

using System.Reactive; 
using System.Reactive.Linq; 

ただ忘れないでください - あなたはまだ何とかフォームに DataPlotを追加する必要があります。

関連する問題