Home > database >  WPF I want to pass the data received by SerialDataReceivedEventHandler to the UI
WPF I want to pass the data received by SerialDataReceivedEventHandler to the UI

Time:09-13

I am creating a serial communication app in my WPF application.

I'm using SerialDataReceivedEventHandler as a data reception event from a communication device, and I want to pass the received data to the UI, but I'm having trouble figuring out how to do it.

My source code is below.

Git Hub

I thought it would be better to separate the communication logic part from the UI, so I wrote the communication processing part in Port.cs. (I'm not very knowledgeable about this, so I could be wrong...)

However, with this configuration, you cannot pass values ​​from Port.cs to MainWindow.xaml.cs.

Is there a way to pass the data received by EventReciveAsync() in this Port.cs to the UI?

Currently, I don't know how to do it, so I'm displaying it in a message box, but I want to display it in the UI textBlock.

MainWindow.xaml

<Window x:Class="SerialConnectWPF.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:SerialConnectWPF"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="17*"/>
        <RowDefinition Height="14*"/>
    </Grid.RowDefinitions>
    <Border BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Left" Height="167" Margin="40,10,0,0" Grid.Row="1" VerticalAlignment="Top" Width="743"/>
    <ComboBox x:Name="cmbComPort" HorizontalAlignment="Left" Height="26" Margin="186,86,0,0" VerticalAlignment="Top" Width="356"/>
    <Button x:Name="btnOpen" Content="Connect Open" HorizontalAlignment="Left" Height="26" Margin="582,92,0,0" VerticalAlignment="Top" Width="173" Click="btnOpen_Click"/>
    <TextBox x:Name="txtSendData" HorizontalAlignment="Left" Height="36" Margin="186,169,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="356" Cursor="Arrow"/>
    <Label Content="COM Port:" HorizontalAlignment="Left" Height="33" Margin="80,95,0,0" VerticalAlignment="Top" Width="78"/>
    <Label Content="Send Data" HorizontalAlignment="Left" Height="29" Margin="80,187,0,0" VerticalAlignment="Top" Width="69"/>
    <Button x:Name="btnSend" Content="Send" HorizontalAlignment="Left" Height="30" Margin="582,183,0,0" VerticalAlignment="Top" Width="173" Background="#FF301253" Click="btnSend_Click"/>
    <TextBlock x:Name="txtLog" HorizontalAlignment="Center" Height="144" Margin="0,20,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="739"/>
</Grid>

MainWindow.xaml.cs

namespace SerialConnectWPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    Port p = new Port();

    public MainWindow()
    {
        InitializeComponent();

        btnOpen.IsEnabled = true;
        btnSend.IsEnabled = false;
        cmbComPort.ItemsSource = p.GetPortNum();
    }

    private void btnOpen_Click(object sender, RoutedEventArgs e)
    {
        if (cmbComPort.Text == "") return;

        if (p.PortOpen(cmbComPort.Text))
        {
            btnSend.IsEnabled = true;
        }
        else
        {
            btnSend.IsEnabled = false;
        }
    }

    private void btnSend_Click(object sender, RoutedEventArgs e)
    {
        btnSend.IsEnabled = false;

        if (txtSendData.Text == "") return;

        p.Send(txtSendData.Text);

        btnSend.IsEnabled = true;
    }
}

}

Port.cs

namespace SerialConnectWPF
{
class Port
{
    private SerialPort _serialPort = null;

    public bool PortOpen(string comNum)
    {
        _serialPort ??= new SerialPort
        {
            PortName = comNum,
            BaudRate = 9600,
            DataBits = 8,
            Parity = Parity.None,
            StopBits = StopBits.One,
            Handshake = Handshake.None,
            Encoding = Encoding.UTF8,
            WriteTimeout = 100000,
            ReadTimeout = 100000,
            NewLine = "\r\n",
        };


        _serialPort.DataReceived  = new SerialDataReceivedEventHandler(EventReciveAsync);

        if (!_serialPort.IsOpen)
        {
            try
            {
                _serialPort.Open();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }
        return true;
    }


    public void PortClose()
    {
        _serialPort?.Close();
        _serialPort = null;
    }


    public void Send(string serialTxt)
    {
        if (!_serialPort.IsOpen) return;

        try
        {
            var tmp = serialTxt.Split("-").Select(hex => Convert.ToByte(hex, 16));
            byte[] sendData = tmp.ToArray();

            // データ書き込み
            _serialPort.Write(sendData, 0, sendData.Length);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }


    public void EventReciveAsync(object sender, SerialDataReceivedEventArgs e)
    {
        if (!_serialPort.IsOpen) return;

        var srtDataReceived = "";
        var buf = new byte[_serialPort.BytesToRead];

        try
        {
            _serialPort.Read(buf, 0, buf.Length);
            srtDataReceived = BitConverter.ToString(buf);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        if (_serialPort.IsOpen)
        {
            MessageBox.Show(srtDataReceived);
        }
    }


    public string[] GetPortNum()
    {
        return SerialPort.GetPortNames();
    }
}
}

CodePudding user response:

You can pass the UI updating code to the port via an action..

Port p = new Port();

public MainWindow()
{
    InitializeComponent();

    btnOpen.IsEnabled = true;
    btnSend.IsEnabled = false;
    cmbComPort.ItemsSource = p.GetPortNum();
    p.UpdateUiAction = data => {
        Application.Current.Dispatcher.Invoke(() => txtLog.Text = data);
    };
}

In Port.cs, add the action property

public Action<string> UpdateUiAction {set; get;}

public void EventReciveAsync(object sender, SerialDataReceivedEventArgs e)
{
    if (!_serialPort.IsOpen) return;

    var srtDataReceived = "";
    var buf = new byte[_serialPort.BytesToRead];

    try
    {
        _serialPort.Read(buf, 0, buf.Length);
        srtDataReceived = BitConverter.ToString(buf);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

    if (_serialPort.IsOpen)
    {
        UpdateUiAction?.Invoke(srtDataReceived);
    }
}
  • Related