2017-11-09 2 views
0

Es ist mein erstes Mal, dass ich WPF und ich ein Problem haben. Ich kann mein Oxyplot-Modell nicht von einem anderen Thread aktualisieren. Ich kann in keinen anderen Thread zeichnen, aber wenn ich versuche, es in einem anderen zu tun passiert nichts. Jetzt habe ich diesen Code:Update Oxyplot-Modell aus einem anderen Thread

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); 
      }); 

}

Alle Arbeiten wie erwartet mit Ausnahme des Teils, wenn Dispatcher.CurrentDispatcher. Ich habe nicht verstanden, warum meine Handlung nicht aktualisiert wurde.

Ich habe eine Idee, die ich nicht verstehe, was Thread ist UI-Thread in diesem Fall mit WPF und vielleicht sollte ich meine Threads in doComputingThread Konstruktor initiieren.

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> 

Antwort

2

Der Code wird in der Schleife die gleiche Koordinate auf der Warteschlange hinzufügen. Sie erstellen nicht jedes Mal während der Schleife eine neue Coordinate Instanz.

Auch Ihre _queue.TryDequeue(out Coordinate) Zeile erzeugt einen Syntaxfehler für mich, wie es versucht, Coordinate als eine Variable und nicht als eine Klasse zu verwenden.

Ohne die Definition für Coordinate kann ich nichts davon bestätigen.

Auch, Ich kann nicht sehen, wo Sie Ihre DataPlot zu Ihrem Formular oder Steuerelement in Ihrem Formular tatsächlich hinzugefügt haben. Es scheint einfach nicht, dass Sie irgendetwas auf jeden Fall anzeigen.

Die Quintessenz ist, dass Ihr Beispielcode kein minimales, vollständiges und überprüfbares Beispiel ist. Ich kann also nur raten, was die Probleme sind.

Ich werde dir eine Alternative geben, von der ich denke, dass sie dir geben wird, was du willst.

Zunächst Ich bin eine einfache Definition für Coordinate Bereitstellung:

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

Nun sind alle Einfädeln, Berechnung und Versand des Codes zu tun, ich werde Microsofts Reactive Framework verwenden - hier wie ich die Button_Click Handler schreiben würde:

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); 
      }); 
} 

Mit diesem Code, den Sie nicht mehr benötigen, um Ihre doComputingThread Klasse überhaupt.

Der Observable.Generate Code erzeugt die t Werte für die 60 Datenpunkte, die Ihren ursprünglichen Code erzeugt, aber es tut dies nur ein Wert zu einem Zeitpunkt alle 10.0 Millisekunden. Dieser Code ist effektiv ein Timer und der Produzent der t Schritte.

Der .Select bildet den t Wert auf einen Coordinate Wert ab.

Die subscription ist die Ausführung der query.Der erste Schritt besteht darin, die Werte mit dem Aufruf .ObserveOnDispatcher() an den UI-Thread zurückzuverteilen, und dann nimmt der Wert .Subscribe jeden Wert an und führt den Delegaten c => ... auf dem UI-Thread aus.

Dies sollte die Handlung schön aktualisieren.

Wenn Sie das Plotten früh stoppen möchten, rufen Sie einfach subscription.Dispose() und es wird aufhören.

Sie müssen NuGet "System.Reactive" und "System.Reactive.Windows.Threading" um die Bits zu erhalten. Sie müssen auch die folgenden using Aussagen den Code zu kompilieren:

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

Nur nicht vergessen - Sie noch die DataPlot zum Formular irgendwie hinzufügen müssen.

Verwandte Themen