Делать что-то во время приема данных с последовательного порта в WPF
Я хочу создать программу, которая будет раскрашивать эллипс любым способом в зависимости от полученных данных в "реальном времени". Данные такие:: x1-1
, x2-1
и т.д.
У меня есть странная проблема, я вижу во время отладки, что цвет заполнения эллипса должен измениться, но этого не происходит.
Часть моего кода с получением данных:
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
это эллипс, который я хочу сделать красным или синим. Я могу установить точку останова в этой функции, и я вижу, что она должна измениться. Я думаю, проблема в том, что программа ждет закрытия порта и завершения передачи, и тогда, возможно, она изменится, но мне нужно иметь ее в "реальном времени". Кто-нибудь знает, как это делается?
2 ответа:
Я считаю, что вы идете по этому неверному пути. Вместо того, чтобы постоянно проверять значение
teststring
, вам нужно просто запустить прослушиватель comm - порта и позволить ему работать в фоновом режиме-так как это будет в его собственном потоке. Затем необходимо создать привязку данных к цвету. Всякий раз, когда прослушиватель comm-порта анализирует строку, он может автоматически обновить цвет.Во-первых, в классе 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(); } }
Не вешайте поток пользовательского интерфейса, имея
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; } }