使用不同的线程更新 GUI (WPF)

发布于 2024-10-03 13:05:58 字数 6878 浏览 0 评论 0原文

只是这里有一个问题,我不知道如何解决。我正在做一个涉及 GUI 和串行数据的小项目。 GUI 由主线程运行,并且由于保存传入串行数据的数据变量需要不断更新,因此这些变量在第二个线程中更新。问题是当我需要更新 GUI 上的一些文本框时,这些文本框需要使用辅助线程中的数据进行更新,这就是我的问题所在。我无法直接从辅助线程更新它们,而且我不知道如何从辅助线程传输数据并制定一个从主线程更新它们的系统。我已将我的代码放在下面:

任何帮助都会很棒。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.IO.Ports;
using System.Threading;

namespace GUIBike
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static string inputdata;
        public static int MaximumSpeed, maximumRiderInput, RiderInput, Time, CurrentSpeed, DistanceTravelled, MaximumMotorOutput, MotorOutput, InputSpeed;
        public static string SaveDataString;
        public Thread Serial;
        public static SerialPort SerialData;
        public static string[] portlist = SerialPort.GetPortNames();
        public static string[] SaveData = new string[4];
        public static string directory = "C:\\";

        public MainWindow()
        {
            Serial = new Thread(ReadData);
            InitializeComponent();
            int Count = 0;
            for (Count = 0; Count < portlist.Length; Count++)
            {
                ComPortCombo.Items.Add(portlist[Count]);
            }
        }

        private void StartDataButton_Click(object sender, RoutedEventArgs e)
        {
            SerialData = new SerialPort(ComPortCombo.Text, 19200, Parity.None, 8, StopBits.One);
            SerialData.Open();
            SerialData.WriteLine("P");
            Serial.Start();
            StartDataButton.IsEnabled = false;
            EndDataButton.IsEnabled = true;
            ComPortCombo.IsEnabled = false;
            CurrentSpeed = 0;
            MaximumSpeed = 0;
            Time = 0;
            DistanceTravelled = 0;
            MotorOutput = 0;
            RiderInput = 0;
            SaveData[0] = "";
            SaveData[1] = "";
            SaveData[2] = "";
            SaveData[3] = "";
            SaveDataButton.IsEnabled = false;
            if (SerialData.IsOpen)
            {
                ComPortStatusLabel.Content = "OPEN";
                SerialData.NewLine = "/n";
                SerialData.WriteLine("0");
                SerialData.WriteLine("/n");
            }
        }

        private void EndDataButton_Click(object sender, RoutedEventArgs e)
        {
            SerialData.Close();
            SaveDataButton.IsEnabled = true;
            SerialData.WriteLine("1");
            SerialData.WriteLine("0");
            if (!SerialData.IsOpen)
            {
                ComPortStatusLabel.Content = "CLOSED";
            }
            int i = 0;
            for (i = 0; i < 4; i++)
            {
                if (i == 0)
                {
                    SaveDataString = "MaximumSpeed during the Ride was = " + Convert.ToString(MaximumSpeed) + "m/h";
                    SaveData[i] = SaveDataString;
                }
                if (i == 1)
                {
                    SaveDataString = "Total Distance Travelled = " + Convert.ToString(DistanceTravelled) + "m";
                    SaveData[i] = SaveDataString;
                }
                if (i == 2)
                {
                    SaveDataString = "Maximum Rider Input Power = " + Convert.ToString(maximumRiderInput) + "Watts";
                    SaveData[i] = SaveDataString;
                }
                if (i == 3)
                {
                    SaveDataString = "Maximum Motor Output Power = " + Convert.ToString(MaximumMotorOutput) + "Watts";
                    SaveData[i] = SaveDataString;
                }
            }
        }

        private void SaveDataButton_Click(object sender, RoutedEventArgs e)
        {
            //File.WriteAllBytes(directory + "image" + imageNO + ".txt", ); //saves the file to Disk    
            File.WriteAllLines(directory + "BikeData.txt", SaveData);
        }

        public void ReadData()
        {
            int counter = 0;

            while (SerialData.IsOpen)
            {
                if (counter == 0)
                {
                    //try
                    //{
                        InputSpeed = Convert.ToInt16(SerialData.ReadChar());
                        CurrentSpeed = InputSpeed;
                        if (CurrentSpeed > MaximumSpeed)
                        {
                            MaximumSpeed = CurrentSpeed;
                        }
                        SpeedTextBox.Text = "Current Wheel Speed = " + Convert.ToString(CurrentSpeed) + "Km/h";
                        DistanceTravelled = DistanceTravelled + (Convert.ToInt16(CurrentSpeed) * Time);
                        DistanceTravelledTextBox.Text = "Total Distance Travelled = " + Convert.ToString(DistanceTravelled) + "Km";
                    //}
                    //catch (Exception) { }
                }
                if (counter == 1)
                {
                    try
                    {
                        RiderInput = Convert.ToInt16(SerialData.ReadLine());
                        if (RiderInput > maximumRiderInput)
                        {
                            maximumRiderInput = RiderInput;
                        }
                        RiderInputTextBox.Text = "Current Rider Input Power =" + Convert.ToString(RiderInput) + "Watts";
                    }
                    catch (Exception) { }
                }
                if (counter == 2)
                {
                    try
                    {
                        MotorOutput = Convert.ToInt16(SerialData.ReadLine());
                        if (MotorOutput > MaximumMotorOutput)
                        {
                            MaximumMotorOutput = MotorOutput;
                        }

                        MotorOutputTextBox.Text = "Current Motor Output = " + Convert.ToString(MotorOutput) + "Watts";
                    }
                    catch (Exception) { }
                }
                counter++;
                if (counter == 3)
                {
                    counter = 0;
                }
            }
        }

        private void ComPortCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            StartDataButton.IsEnabled = true;
        }


        private void Window_Closed(object sender, RoutedEventArgs e)
        {
            if (SerialData.IsOpen)
            {
                SerialData.Close();
            }
        }

Just have a problem here that I have no idea how to fix. I am doing a small project which involves a GUI and serial data. The GUI is being run by the main thread and since the data variables that hold my incoming serial data need to be updated continuously, these are being updated in a second thread. The problem is when I need to update some textboxes on the GUI, these need to be updated with data from the secondary thread and that is where my problem lies. I can't update them directly from the secondary thread and I have no idea how I would transfer data from my secondary thread and work out a system of updating them from main thread. I have put my code below:

Any help would be great.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.IO.Ports;
using System.Threading;

namespace GUIBike
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static string inputdata;
        public static int MaximumSpeed, maximumRiderInput, RiderInput, Time, CurrentSpeed, DistanceTravelled, MaximumMotorOutput, MotorOutput, InputSpeed;
        public static string SaveDataString;
        public Thread Serial;
        public static SerialPort SerialData;
        public static string[] portlist = SerialPort.GetPortNames();
        public static string[] SaveData = new string[4];
        public static string directory = "C:\\";

        public MainWindow()
        {
            Serial = new Thread(ReadData);
            InitializeComponent();
            int Count = 0;
            for (Count = 0; Count < portlist.Length; Count++)
            {
                ComPortCombo.Items.Add(portlist[Count]);
            }
        }

        private void StartDataButton_Click(object sender, RoutedEventArgs e)
        {
            SerialData = new SerialPort(ComPortCombo.Text, 19200, Parity.None, 8, StopBits.One);
            SerialData.Open();
            SerialData.WriteLine("P");
            Serial.Start();
            StartDataButton.IsEnabled = false;
            EndDataButton.IsEnabled = true;
            ComPortCombo.IsEnabled = false;
            CurrentSpeed = 0;
            MaximumSpeed = 0;
            Time = 0;
            DistanceTravelled = 0;
            MotorOutput = 0;
            RiderInput = 0;
            SaveData[0] = "";
            SaveData[1] = "";
            SaveData[2] = "";
            SaveData[3] = "";
            SaveDataButton.IsEnabled = false;
            if (SerialData.IsOpen)
            {
                ComPortStatusLabel.Content = "OPEN";
                SerialData.NewLine = "/n";
                SerialData.WriteLine("0");
                SerialData.WriteLine("/n");
            }
        }

        private void EndDataButton_Click(object sender, RoutedEventArgs e)
        {
            SerialData.Close();
            SaveDataButton.IsEnabled = true;
            SerialData.WriteLine("1");
            SerialData.WriteLine("0");
            if (!SerialData.IsOpen)
            {
                ComPortStatusLabel.Content = "CLOSED";
            }
            int i = 0;
            for (i = 0; i < 4; i++)
            {
                if (i == 0)
                {
                    SaveDataString = "MaximumSpeed during the Ride was = " + Convert.ToString(MaximumSpeed) + "m/h";
                    SaveData[i] = SaveDataString;
                }
                if (i == 1)
                {
                    SaveDataString = "Total Distance Travelled = " + Convert.ToString(DistanceTravelled) + "m";
                    SaveData[i] = SaveDataString;
                }
                if (i == 2)
                {
                    SaveDataString = "Maximum Rider Input Power = " + Convert.ToString(maximumRiderInput) + "Watts";
                    SaveData[i] = SaveDataString;
                }
                if (i == 3)
                {
                    SaveDataString = "Maximum Motor Output Power = " + Convert.ToString(MaximumMotorOutput) + "Watts";
                    SaveData[i] = SaveDataString;
                }
            }
        }

        private void SaveDataButton_Click(object sender, RoutedEventArgs e)
        {
            //File.WriteAllBytes(directory + "image" + imageNO + ".txt", ); //saves the file to Disk    
            File.WriteAllLines(directory + "BikeData.txt", SaveData);
        }

        public void ReadData()
        {
            int counter = 0;

            while (SerialData.IsOpen)
            {
                if (counter == 0)
                {
                    //try
                    //{
                        InputSpeed = Convert.ToInt16(SerialData.ReadChar());
                        CurrentSpeed = InputSpeed;
                        if (CurrentSpeed > MaximumSpeed)
                        {
                            MaximumSpeed = CurrentSpeed;
                        }
                        SpeedTextBox.Text = "Current Wheel Speed = " + Convert.ToString(CurrentSpeed) + "Km/h";
                        DistanceTravelled = DistanceTravelled + (Convert.ToInt16(CurrentSpeed) * Time);
                        DistanceTravelledTextBox.Text = "Total Distance Travelled = " + Convert.ToString(DistanceTravelled) + "Km";
                    //}
                    //catch (Exception) { }
                }
                if (counter == 1)
                {
                    try
                    {
                        RiderInput = Convert.ToInt16(SerialData.ReadLine());
                        if (RiderInput > maximumRiderInput)
                        {
                            maximumRiderInput = RiderInput;
                        }
                        RiderInputTextBox.Text = "Current Rider Input Power =" + Convert.ToString(RiderInput) + "Watts";
                    }
                    catch (Exception) { }
                }
                if (counter == 2)
                {
                    try
                    {
                        MotorOutput = Convert.ToInt16(SerialData.ReadLine());
                        if (MotorOutput > MaximumMotorOutput)
                        {
                            MaximumMotorOutput = MotorOutput;
                        }

                        MotorOutputTextBox.Text = "Current Motor Output = " + Convert.ToString(MotorOutput) + "Watts";
                    }
                    catch (Exception) { }
                }
                counter++;
                if (counter == 3)
                {
                    counter = 0;
                }
            }
        }

        private void ComPortCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            StartDataButton.IsEnabled = true;
        }


        private void Window_Closed(object sender, RoutedEventArgs e)
        {
            if (SerialData.IsOpen)
            {
                SerialData.Close();
            }
        }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

风追烟花雨 2024-10-10 13:05:58

您可以使用Dispatcher.Invoke从辅助线程更新您的GUI。

这是一个例子:

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        new Thread(DoSomething).Start();
    }
    public void DoSomething()
    {
        for (int i = 0; i < 100000000; i++)
        {
               this.Dispatcher.Invoke(()=>{
               textbox.Text=i.ToString();
               });    
        } 
    }

You can use Dispatcher.Invoke to update your GUI from a secondary thread.

Here is an example:

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        new Thread(DoSomething).Start();
    }
    public void DoSomething()
    {
        for (int i = 0; i < 100000000; i++)
        {
               this.Dispatcher.Invoke(()=>{
               textbox.Text=i.ToString();
               });    
        } 
    }
何时共饮酒 2024-10-10 13:05:58

您可以使用委托来解决此问题。
这是一个示例,显示如何使用不同的线程更新文本框

public delegate void UpdateTextCallback(string message);

private void TestThread()
{
    for (int i = 0; i <= 1000000000; i++)
    {
        Thread.Sleep(1000);                
        richTextBox1.Dispatcher.Invoke(
            new UpdateTextCallback(this.UpdateText),
            new object[] { i.ToString() }
        );
    }
}
private void UpdateText(string message)
{
    richTextBox1.AppendText(message + "\n");
}

private void button1_Click(object sender, RoutedEventArgs e)
{
   Thread test = new Thread(new ThreadStart(TestThread));
   test.Start();
}

TestThread 方法由名为 test 的线程使用来更新文本框

You may use a delegate to solve this issue.
Here is an example that is showing how to update a textBox using diffrent thread

public delegate void UpdateTextCallback(string message);

private void TestThread()
{
    for (int i = 0; i <= 1000000000; i++)
    {
        Thread.Sleep(1000);                
        richTextBox1.Dispatcher.Invoke(
            new UpdateTextCallback(this.UpdateText),
            new object[] { i.ToString() }
        );
    }
}
private void UpdateText(string message)
{
    richTextBox1.AppendText(message + "\n");
}

private void button1_Click(object sender, RoutedEventArgs e)
{
   Thread test = new Thread(new ThreadStart(TestThread));
   test.Start();
}

TestThread method is used by thread named test to update textBox

风铃鹿 2024-10-10 13:05:58

那里。

我也在使用WPF开发一个串口测试工具,
我想分享一下我的一些经验。

我认为你应该根据 MVVM 设计模式重构你的源代码。

一开始,我遇到了与您遇到的相同的问题,我使用以下代码解决了它:

new Thread(() => 
{
    while (...)
    {
        SomeTextBox.Dispatcher.BeginInvoke((Action)(() => SomeTextBox.Text = ...));
    }
}).Start();

这可行,但太丑陋了。
我不知道如何重构它,直到我看到这个:
http://www.codeproject.com/Articles/165368/WPF -MVVM-Quick-Start-Tutorial

这是针对初学者的非常友好的分步 MVVM 教程。
没有闪亮的 UI,没有复杂的逻辑,只有 MVVM 的基础。

there.

I am also developing a serial port testing tool using WPF,
and I'd like to share some experience of mine.

I think you should refactor your source code according to MVVM design pattern.

At the beginning, I met the same problem as you met, and I solved it using this code:

new Thread(() => 
{
    while (...)
    {
        SomeTextBox.Dispatcher.BeginInvoke((Action)(() => SomeTextBox.Text = ...));
    }
}).Start();

This works, but is too ugly.
I have no idea how to refactor it, until I saw this:
http://www.codeproject.com/Articles/165368/WPF-MVVM-Quick-Start-Tutorial

This is a very kindly step-by-step MVVM tutorial for beginners.
No shiny UI, no complex logic, only the basic of MVVM.

厌倦 2024-10-10 13:05:58

使用以下方法更新 GUI。

     Public Void UpdateUI()
     {
         //Here update your label, button or any string related object.

         //Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));    
         Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
     }

请记住,当您当时使用此方法时,不要直接从调度程序线程更新同一对象,否则您只能得到更新后的字符串,并且此方法是无助/无用的。
如果仍然不起作用,则注释方法内的该行和取消注释注释两者具有几乎相同的效果,只是访问它的方式不同。

Use Following Method to Update GUI.

     Public Void UpdateUI()
     {
         //Here update your label, button or any string related object.

         //Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));    
         Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
     }

Keep it in Mind when you use this method at that time do not Update same object direct from dispatcher thread otherwise you get only that updated string and this method is helpless/useless.
If still not working then Comment that line inside method and un-comment commented one both have nearly same effect just different way to access it.

伴梦长久 2024-10-10 13:05:58

的完整示例

<Window x:Class="WpfThreading.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:WpfThreading"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="216.84">
<Grid Margin="0,0,2,0">
    <Button Content="Button" HorizontalAlignment="Left" Margin="10,10,0,0"
            VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    <TextBox HorizontalAlignment="Left" Margin="10,35,0,10" TextWrapping="Wrap" Name="mtextBox" Width="87"   VerticalScrollBarVisibility="Auto"/>
    <TextBox HorizontalAlignment="Left" Margin="111,35,0,10" TextWrapping="Wrap" x:Name="mtextBox2" Width="87"   VerticalScrollBarVisibility="Auto"/>
</Grid></Window>

这是更新 UI 文本框和代码中

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        new Thread(DoSomething).Start();
        new Thread(DoSomething2).Start();
    }


    public void DoSomething()
    {
        for (int i = 0; i < 100; i++)
        {
            Dispatcher.BeginInvoke(new Action(() => {
                mtextBox.Text += $"{i.ToString()}{Environment.NewLine}";
            }), DispatcherPriority.SystemIdle);

            Thread.Sleep(100);
        }

    }

    public void DoSomething2()
    {
        for (int i = 100; i > 0; i--)
        {
            Dispatcher.BeginInvoke(new Action(() => {
                mtextBox2.Text += $"{i.ToString()}{Environment.NewLine}";
            }), DispatcherPriority.SystemIdle);

            Thread.Sleep(100);
        }

    }
}

Here is a full example that updates UI textboxes

<Window x:Class="WpfThreading.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:WpfThreading"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="216.84">
<Grid Margin="0,0,2,0">
    <Button Content="Button" HorizontalAlignment="Left" Margin="10,10,0,0"
            VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    <TextBox HorizontalAlignment="Left" Margin="10,35,0,10" TextWrapping="Wrap" Name="mtextBox" Width="87"   VerticalScrollBarVisibility="Auto"/>
    <TextBox HorizontalAlignment="Left" Margin="111,35,0,10" TextWrapping="Wrap" x:Name="mtextBox2" Width="87"   VerticalScrollBarVisibility="Auto"/>
</Grid></Window>

and in the code

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        new Thread(DoSomething).Start();
        new Thread(DoSomething2).Start();
    }


    public void DoSomething()
    {
        for (int i = 0; i < 100; i++)
        {
            Dispatcher.BeginInvoke(new Action(() => {
                mtextBox.Text += $"{i.ToString()}{Environment.NewLine}";
            }), DispatcherPriority.SystemIdle);

            Thread.Sleep(100);
        }

    }

    public void DoSomething2()
    {
        for (int i = 100; i > 0; i--)
        {
            Dispatcher.BeginInvoke(new Action(() => {
                mtextBox2.Text += $"{i.ToString()}{Environment.NewLine}";
            }), DispatcherPriority.SystemIdle);

            Thread.Sleep(100);
        }

    }
}
感情旳空白 2024-10-10 13:05:58

您需要使用Dispatcher.BeginInvoke。我没有测试它,但您可以检查链接(这是Julio G 提供的相同链接)可以更好地了解如何从不同线程更新 UI 控件。我修改了您的 ReadData() 代码

public void ReadData()
{
    int counter = 0;

    while (SerialData.IsOpen)
    {
        if (counter == 0)
        {
            //try
            //{
                InputSpeed = Convert.ToInt16(SerialData.ReadChar());
                CurrentSpeed = InputSpeed;
                if (CurrentSpeed > MaximumSpeed)
                {
                    MaximumSpeed = CurrentSpeed;
                }
    SpeedTextBox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
        new Action(delegate() { SpeedTextBox.Text = "Current Wheel Speed = " + Convert.ToString(CurrentSpeed) + "Km/h"; });//update GUI from this thread


                DistanceTravelled = DistanceTravelled + (Convert.ToInt16(CurrentSpeed) * Time);

    DistanceTravelledTextBox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
        new Action(delegate() {DistanceTravelledTextBox.Text = "Total Distance Travelled = " + Convert.ToString(DistanceTravelled) + "Km"; });//update GUI from this thread

            //}
            //catch (Exception) { }
        }
        if (counter == 1)
        {
            try
            {
                RiderInput = Convert.ToInt16(SerialData.ReadLine());
                if (RiderInput > maximumRiderInput)
                {
                    maximumRiderInput = RiderInput;
                }                       
    RiderInputTextBox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, 
        new Action(delegate() { RiderInputTextBox.Text = "Current Rider Input Power =" + Convert.ToString(RiderInput) + "Watts"; });//update GUI from this thread
            }
            catch (Exception) { }
        }
        if (counter == 2)
        {
            try
            {
                MotorOutput = Convert.ToInt16(SerialData.ReadLine());
                if (MotorOutput > MaximumMotorOutput)
                {
                    MaximumMotorOutput = MotorOutput;
                }
    MotorOutputTextBox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, 
        new Action(delegate() { MotorOutputTextBox.Text = "Current Motor Output = " + Convert.ToString(MotorOutput) + "Watts"; });//update GUI from this thread                        
            }
            catch (Exception) { }
        }
        counter++;
        if (counter == 3)
        {
            counter = 0;
        }
    }
}

You need to use Dispatcher.BeginInvoke. I did not test it but you can check this link(this is the same link provided by Julio G) to have better understanding on how to update the UI controls from different thread. I have modified your ReadData() code

public void ReadData()
{
    int counter = 0;

    while (SerialData.IsOpen)
    {
        if (counter == 0)
        {
            //try
            //{
                InputSpeed = Convert.ToInt16(SerialData.ReadChar());
                CurrentSpeed = InputSpeed;
                if (CurrentSpeed > MaximumSpeed)
                {
                    MaximumSpeed = CurrentSpeed;
                }
    SpeedTextBox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
        new Action(delegate() { SpeedTextBox.Text = "Current Wheel Speed = " + Convert.ToString(CurrentSpeed) + "Km/h"; });//update GUI from this thread


                DistanceTravelled = DistanceTravelled + (Convert.ToInt16(CurrentSpeed) * Time);

    DistanceTravelledTextBox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
        new Action(delegate() {DistanceTravelledTextBox.Text = "Total Distance Travelled = " + Convert.ToString(DistanceTravelled) + "Km"; });//update GUI from this thread

            //}
            //catch (Exception) { }
        }
        if (counter == 1)
        {
            try
            {
                RiderInput = Convert.ToInt16(SerialData.ReadLine());
                if (RiderInput > maximumRiderInput)
                {
                    maximumRiderInput = RiderInput;
                }                       
    RiderInputTextBox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, 
        new Action(delegate() { RiderInputTextBox.Text = "Current Rider Input Power =" + Convert.ToString(RiderInput) + "Watts"; });//update GUI from this thread
            }
            catch (Exception) { }
        }
        if (counter == 2)
        {
            try
            {
                MotorOutput = Convert.ToInt16(SerialData.ReadLine());
                if (MotorOutput > MaximumMotorOutput)
                {
                    MaximumMotorOutput = MotorOutput;
                }
    MotorOutputTextBox.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, 
        new Action(delegate() { MotorOutputTextBox.Text = "Current Motor Output = " + Convert.ToString(MotorOutput) + "Watts"; });//update GUI from this thread                        
            }
            catch (Exception) { }
        }
        counter++;
        if (counter == 3)
        {
            counter = 0;
        }
    }
}
凉宸 2024-10-10 13:05:58

正如 akjoshi 和 Julio 所说,这是关于在与 GUI 项相同的线程上调度一个 Action 来更新 GUI,但从处理后台数据的方法。您可以在上面 akjoshi 的答案中以特定形式看到此代码。这是通用版本。

myTextBlock.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
                                   new Action(delegate() 
                                      {
                                      myTextBlock.Text = Convert.ToString(myDataObject.getMeData());
                                      }));

关键部分是调用 UI 对象的调度程序 - 确保您拥有正确的线程。

从个人经验来看,像这样创建和使用内联操作似乎要容易得多。在类级别声明它给我带来了很多静态/非静态上下文的问题。

As akjoshi and Julio say this is about dispatching an Action to update the GUI on the same thread as the GUI item but from the method that is handling the background data. You can see this code in specific form in akjoshi's answer above. This is a general version.

myTextBlock.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
                                   new Action(delegate() 
                                      {
                                      myTextBlock.Text = Convert.ToString(myDataObject.getMeData());
                                      }));

The critical part is to call the dispatcher of your UI object - that ensures you have the correct thread.

From personal experience it seems much easier to create and use the Action inline like this. Declaring it at class level gave me lots of problems with static/non-static contexts.

倾听心声的旋律 2024-10-10 13:05:58

我想你有几个选择。

一种是使用BackgroundWorker。这是应用程序中多线程的常见助手。它公开了一个 DoWork 事件(在线程池的后台线程上处理)和一个 RunWorkerCompleted 事件(当后台线程完成时在主线程上调用)。它还具有尝试/捕获在后台线程上运行的代码的优点,以便未处理的异常不会终止应用程序。

如果您不想走这条路,可以使用 WPF 调度程序对象来调用一个操作,将 GUI 更新回主线程。随机参考:

http://www.switchonthecode.com/tutorials/working- with-the-wpf-dispatcher

还有许多其他选项,但这是我想到的最常见的两个。

You have a couple of options here, I think.

One would be to use a BackgroundWorker. This is a common helper for multithreading in applications. It exposes a DoWork event which is handled on a background thread from the Thread Pool and a RunWorkerCompleted event which is invoked back on the main thread when the background thread completes. It also has the benefit of try/catching the code running on the background thread so that an unhandled exception doesn't kill the application.

If you don't want to go that route, you can use the WPF dispatcher object to invoke an action to update the GUI back onto the main thread. Random reference:

http://www.switchonthecode.com/tutorials/working-with-the-wpf-dispatcher

There are many other options around too, but these are the two most common that come to mind.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文