0

我有 Arduino 连续发送数据而不关心延迟,我想将延迟放在 C# 中的显示器上,所以我可以打印所有值而不会丢失任何东西,但在每一行我想延迟(让说)两秒钟。我以Thread.Sleep某种方式阻止并延迟了我的用户界面并且Task.Delay无济于事。有谁知道如何解决这个问题?

我的代码:

 private SerialPort mySerialPort;
    private readonly StreamWriter sw = new(@"D:\MAAT\readcoba.csv");
    public MainWindow()
    {
        InitializeComponent();
        Configure();
    }

    private void Configure()
    {
        mySerialPort = new(Port())
        {
            BaudRate = 9600,
            Parity = Parity.None,
            StopBits = StopBits.One,
            DataBits = 8,
        };
        mySerialPort.DataReceived += DataReceivedHandler;
        mySerialPort.Open();
    }

    private string Port()
    {
        string port = "";
        string[] ports = SerialPort.GetPortNames();
        foreach (string x in ports)
        {
            port = x;
        }
        return port;
    }

    private async void DataReceivedHandler(
        object sender,
        SerialDataReceivedEventArgs e)
    {
        // It's still not work
        await Task.Delay(2000);
        string indata = mySerialPort.ReadExisting();
        string[] arrData = indata.Split(',');
      
        Application.Current.Dispatcher.Invoke(() =>
        {
            foreach (string item in arrData)
            {
                raw_data_label.Content = raw_data_label.Content.ToString().Contains("Nothing to Display") ?
                $"{item}" : $"{raw_data_label.Content}" + $"{item}";
            }
            sw.WriteLine(indata);
        });
    }

    private void WindowClosed(object sender, EventArgs e)
    {
        sw.Close();
        mySerialPort.Close();
    }
}
4

1 回答 1

1

而不是调用 UI 线程(您没有控制 te 限制)。将数据放入变量/字段并使用 DispatcherTimer 显示它。这样您就可以控制屏幕上的更新速度。

这是一个例子:

private SerialPort mySerialPort;
private readonly StreamWriter sw = new(@"D:\MAAT\readcoba.csv");

// create a dispatcher timer
private DispatcherTimer timer = new DispatcherTimer(TimeSpan.FromMilliseconds(200), DispatcherPriority.Normal, UpdateLabel, Dispatcher.CurrentDispatcher)

// a lock object to use threadsafe object access
private object lockObject = new Object();

private static void UpdateLabel(object sender, EventArgs e)
{
    // never update UI within a lock (which is used on other threads)
    // Create a copy or if the field is only written (on the other end) copy the reference.

    string[] data;

    lock(lockObject)
        data = _arduinoData; // You don't need to create a copy, but that's only because the _arduinoData isn't used.
    
    foreach (string item in data)
    {
        // ????? why write to the same label over and over? Rather use a StringBuilder
        raw_data_label.Content = raw_data_label.Content.ToString().Contains("Nothing to Display") ?
        $"{item}" : $"{raw_data_label.Content}" + $"{item}";
    }
}

public MainWindow()
{
    InitializeComponent();
    Configure();
}

private void Configure()
{
    mySerialPort = new(Port())
    {
        BaudRate = 9600,
        Parity = Parity.None,
        StopBits = StopBits.One,
        DataBits = 8,
    };
    mySerialPort.DataReceived += DataReceivedHandler;
    Thread.Sleep(2000);
    mySerialPort.Open();
}

private string Port()
{
    string port = "";
    string[] ports = SerialPort.GetPortNames();
    foreach (string x in ports)
    {
        port = x;
    }
    return port;
}

private string[] arduinoData;

private void DataReceivedHandler(
    object sender,
    SerialDataReceivedEventArgs e)
{
    // It's still not work
    // await Task.Delay(2000);  <-- don't delay here!
    string indata = mySerialPort.ReadExisting();
    string[] arrData = indata.Split(',');

    sw.WriteLine(indata);

    // lock and assigny the reference to the field (this is only allowed when the reference isn't used anymore _(if the string array isn't yours, Use a ToArray to create a copy)_
    // That's why the s.WriteLine(..) is move above this.
    lock(lockObject)
        arduinoData = arrData;
  
}

private void WindowClosed(object sender, EventArgs e)
{
    sw.Close();
    mySerialPort.Close();
于 2021-07-08T09:42:20.523 回答