2017-02-15 3 views
2

Я хочу создать программу, которая будет цветовым эллипсом каким-либо образом в зависимости от полученных данных в режиме реального времени. Данные похожи на: x1-1, x2-1 и т. Д.Выполнение чего-то во время приема данных из последовательного порта в WPF

У меня есть странная проблема, я вижу, что при отладке, цвет заполнения эллипса должен меняться, но этого не происходит.

часть моего кода с получением данных:

private void ReceiveData() 
      { 
       SerialPort serialPort = new SerialPort("COM1", 9600); 
       serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); 
       serialPort.Open(); 
      } 

private static void DataReceivedHandler(
       object sender, 
       SerialDataReceivedEventArgs e) 
      { 
       SerialPort sp = (SerialPort)sender; 
       string indata = sp.ReadExisting(); 
       if (indata.Contains(" ")) 
       { 
        testString = indata.Substring(0, 4); 

       } 
       Console.Write(indata); 
      } 

Я могу видеть полученные данные в консоли, даже после щелчка на кнопке, которая начинает прием данных. testString должен извлечь один x1-1 от indata, который все еще растет во время приема данных. Я знаю, что это не работает, как должно, но теперь это не имеет значения.

Код действия на кнопке:

private void button1_Click(object sender, RoutedEventArgs e) 
     { 
      ReceiveData(); 
      while (true) 
      { 
       if (testString == "x1-1") x1.Fill = Brushes.Blue; 
       else x1.Fill = Brushes.Red; 
      } 
     } 

x1 является эллипсом, что я хочу сделать красным или синим. Я могу установить точку останова в этой функции, и я вижу, что она должна измениться. Я думаю, проблема в том, что программа ждет закрытия порта и завершения передачи, а затем, возможно, это изменится, но мне нужно иметь его в режиме реального времени. Кто-нибудь знает, как это сделать?

+0

Покажите нам 'Console.Write (СравниваемаяСтрока);' –

+0

Первая итерация пуста, но тогда это выглядит нормально, как 'x1-1',' x2-1' – Vades

+0

И если поставить бряк на свой " if ', имеет ли teststring когда-либо равную «x1-1»? Если это так, ваш поток пользовательского интерфейса никогда не получает возможность перерисовывать, потому что вы выполняете 'while (true)' ... вы забиваете процессор. это для себя - откройте диспетчер задач и посмотрите, не скапливается ли ядро ​​на 100%. Подумайте об обновлении пользовательского интерфейса по таймеру, который выполняется каждые 300-500 мсек. Это даст потоку пользовательского интерфейса возможность выполнить свою работу. –

ответ

1

Я считаю, что вы идете об этом не так. Вместо того, чтобы постоянно проверять значение teststring, вам нужно просто запустить прослушиватель коммуникационного порта и позволить ему работать в фоновом режиме - так как это будет в его собственном потоке. Затем вам нужно создать привязку данных к цвету. Всякий раз, когда прослушиватель сообщений COM обрабатывает строку, он может автоматически обновлять цвет.

Во-первых, в классе CommPort:

class MyCommPort : INotifyPropertyChanged 
{ 
    SerialPort serialPort = null; 
    public MyCommPort() 
    { 
     serialPort = new SerialPort("COM3", 9600); 
     serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); 
     serialPort.Open(); 
    } 
    ~MyCommPort() 
    { 
     serialPort.Close(); 
    } 

    private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) 
    { 
     SerialPort sp = (SerialPort)sender; 
     string testString = null; 
     string indata = sp.ReadLine(); 
     if (indata.Length >= 4) 
     { 
      testString = indata.Substring(0, 4); 
      // Update the value 
      if (testString == "x1-1") EllipseBrush = Brushes.Blue; 
      else EllipseBrush = Brushes.Red; 
     } 
     Console.Write(testString); 
    } 

    // Create a property that will be bound 
    private SolidColorBrush ellipseBrush = Brushes.Red; 
    public SolidColorBrush EllipseBrush 
    { 
     get { return ellipseBrush; } 
     set 
     { 
      ellipseBrush = value; 
      OnPropertyChanged("EllipseBrush"); 
     } 
    } 

    // Extend the INotifyPropertyChanged interface 
    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      // Alert anyone bound to this that the value has changed 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

Затем установите DataContext Эллипс к классу CommPort и привязать заливку свойство эллипса к EllipseBrush. Теперь все, что вам нужно сделать, это запустить прослушиватель Commport (ReceiveData();), и обновления цвета должны произойти автоматически.

Например: MainWindow.xaml

<Window x:Class="delete_me.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Ellipse x:Name="ellipse" Fill="{Binding Path=EllipseBrush}" /> 
    </Grid> 
</Window> 

И код позади: MainWindow.xaml.cs

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     ellipse.DataContext = new MyCommPort(); 
    } 
} 
+0

Существует проблема с этой частью кода: 'if (testString ==" x1-1 ") EllipseBrush = Brushes.Blue; else EllipseBrush = Brushes.Red; ' , потому что EllipseBrush нельзя использовать в этом месте в этом статическом контексте. – Vades

+0

Вы можете удалить' static' из функции. Я обновил ответ. Кроме того, я просто написал тестовое приложение, и это работает. –

+0

Полезно знать. Ну, так спасибо. Я постараюсь сделать это tommorow, я должен найти информацию, как сделать то, что вы написали ниже кода, потому что это не так очевидно для меня. – Vades

0

Не вешайте нить UI путем иметь while(true) внутри кнопки мыши мероприятие. Используйте DispatchTimer для работы каждые 500 секунд.

System.Windows.Threading.DispatcherTimer MyTimer = null; 
private void ReceiveData() 
{ 
    MyTimer = new System.Windows.Threading.DispatcherTimer(); 
    MyTimer.Interval = new TimeSpan(0, 0, 0, 0, 500); 
    MyTimer.Tick += MyTimer_Tick; 
    MyTimer.Start(); 
    SerialPort serialPort = new SerialPort("COM1", 9600); 
    serialPort.DataReceived += new 
      SerialDataReceivedEventHandler(DataReceivedHandler); 
    serialPort.Open(); 
} 

private static void DataReceivedHandler(
       object sender, 
       SerialDataReceivedEventArgs e) 
{ 
    SerialPort sp = (SerialPort)sender; 
    string indata = sp.ReadExisting(); 
    if (indata.Contains(" ")) 
    { 
     testString = indata.Substring(0, 4); 

    } 
} 

private void button1_Click(object sender, RoutedEventArgs e) 
{ 
    ReceiveData(); 
} 

private void MyTimer_Tick(object sender, EventArgs e) 
{ 
    if (testString == "x1-1") 
    { 
     x1.Fill = Brushes.Blue; 
    } 
    else 
    { 
     x1.Fill = Brushes.Red; 
    } 
} 
+0

В чем разница между 'EllipseBrush = Brushes.Blue;' и 'x1.Fill = Brushes.Blue'? С 'EllipseBrush = Brushes.Blue;' он не может быть скомпилирован из-за отсутствия декларации, с 'x1.Fill = Brushes.Blue' он по-прежнему не работает. – Vades

+0

Но это все еще не работает. Ошибка должна быть в другом месте. – Vades

+0

Я редактировал код в событии Timer_Tick. Если вы обновите его до того, что у меня есть, и вы остановите код и входите в него, что вы видите? –

Смежные вопросы