1. 程式人生 > >2018最新串列埠讀寫程式簡化版傻瓜式教程

2018最新串列埠讀寫程式簡化版傻瓜式教程



附:Visual Studio更改程式圖示傻瓜式教程

 

Microsoft Visual Studio 2015

目錄

點選檔案-新建-專案​

點選Visual C#-WPF應用程式,在下方自定義相關資訊。點確定。​

介面介紹​

建立圖示資料夾​。右鍵點選資料夾-點選在檔案資源管理器中開啟資料夾​。將相關圖片放進去​如果看不到,可能是隱藏了​

 請能力高者自主設計樣式。附樣式參考程式碼:

點選MainWindow.xaml-雙擊進入MainWindow.xaml.cs進行功能設計​

點選生成-點選生成(你的程式名)​

成功​



  1. 點選檔案-新建-專案

  2. 點選Visual C#-WPF應用程式,在下方自定義相關資訊。點確定。

  3. 介面介紹

  4. 建立圖示資料夾。右鍵點選資料夾-點選在檔案資源管理器中開啟資料夾。將相關圖片放進去如果看不到,可能是隱藏了

  5.  請能力高者自主設計樣式。附樣式參考程式碼:

<Window x:Class="你的程式名.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:你的程式名"
        mc:Ignorable="d"
        Title="你的程式名"  Height="570" MinHeight="565" Width="800" MinWidth="500"  Closed="Window_Closed" Closing="Window_Closing" Loaded="Window_Loaded" ResizeMode="CanResizeWithGrip"  BorderThickness="0">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Close"
            Executed="Window_Closed" />
    </Window.CommandBindings>
   
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="76*"/>
            <RowDefinition/>
            <RowDefinition Height="0*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="225*"/>
            <ColumnDefinition Width="49*"/>
            <ColumnDefinition Width="418*"/>
        </Grid.ColumnDefinitions>
        <Grid Grid.ColumnSpan="3" Grid.RowSpan="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="83*"></ColumnDefinition>
                <ColumnDefinition Width="263*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="0"></RowDefinition>
                <RowDefinition MinHeight="320" Height="361*"></RowDefinition>
                <RowDefinition MaxHeight="158" Height="158*"></RowDefinition>
                <RowDefinition Height="20"></RowDefinition>
            </Grid.RowDefinitions>
            <DockPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Top" Height="0" Grid.RowSpan="2"   >

                <Menu DockPanel.Dock="Top">
                    <Menu.Background>
                        <ImageBrush/>
                    </Menu.Background>

                </Menu>

            </DockPanel>
            <Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" >
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150" ></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Grid Grid.Row="0">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="230"></RowDefinition>
                        <RowDefinition Height="90"></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid Grid.Row="0" Grid.Column="0" Margin="0,4,0,87" Grid.RowSpan="2">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="60" ></ColumnDefinition>
                            <ColumnDefinition></ColumnDefinition>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                            <RowDefinition Height="25"></RowDefinition>
                            <RowDefinition Height="50"></RowDefinition>
                        </Grid.RowDefinitions>

                        <TextBlock Name="Port" Text="串列埠號:" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="0" Grid.Column="0" Margin="10,25,10,22" Grid.RowSpan="2"></TextBlock>
                        <TextBlock Name="BaundRate" Text="波特率:" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="1" Grid.Column="0" Margin="10,25,10,22" Grid.RowSpan="2"></TextBlock>

                        <ComboBox Name="AvailableComCbobox" ToolTip="點選重新整理" Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" Margin="0,22,0,0" PreviewMouseDown="AvailableComCbobox_PreviewMouseDown" Grid.RowSpan="2" />
                        <ComboBox Name="RateListCbobox" Grid.Row="1" Grid.Column="1" VerticalAlignment="Top" Margin="0,22,0,0" SelectionChanged="RateListCbobox_SelectionChanged" Grid.RowSpan="2"/>
                        <Button Content="重置" Name="defaultSet" Grid.Row="4" Grid.ColumnSpan="2" Margin="40,18,48,0" Click="defaultSet_Click" Background="#FFF3F1C1" Grid.RowSpan="2" />
                        <Button  Content="開啟通訊埠" Click="Button_Open" Name="openBtn" Grid.Row="6" VerticalAlignment="Center"  Height="45" Margin="27,50,33,-45" RenderTransformOrigin="0.444,0" Background="{DynamicResource {x:Static SystemColors.MenuBrushKey}}" Grid.ColumnSpan="2" />
                        <Image Name="OpenImage" Source="image\Off.png" HorizontalAlignment="Center" VerticalAlignment="Center" Height="40"  Grid.Row="6"   Width="40" Margin="52,109,58,-99" RenderTransformOrigin="1.4,-0.325" Grid.ColumnSpan="2"/>
                    </Grid>
                    <Grid Grid.Row="1" Grid.Column="0" >
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="27*"/>
                            <ColumnDefinition Width="23*"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                        </Grid.RowDefinitions>
                        <CheckBox Content="16進位制接收" Name="recModeCheck"    FontSize="15" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="23,-124,0,150" Grid.Row="0" Grid.ColumnSpan="2" Height="20"/>

                    </Grid>
                </Grid>
                <Grid Grid.Row="0" Grid.Column="1" Margin="5,0,0,0">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="0*"/>
                        <ColumnDefinition Width="105*"/>
                        <ColumnDefinition Width="437*"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="25"></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <TextBlock  Margin="10,9,0,1" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"><Run Text=" "/><Run Text="接收區"/><Run Text=":"/></TextBlock>
                    <Label Content="已暫停接收,點選開啟→" Name="recPrompt" Grid.Row="0" Grid.Column="2" Margin="0,0,170,0" HorizontalAlignment="Right" Visibility="Hidden" Foreground="#FFFFFF2F" Background="{x:Null}"  />
                    <Button Content="暫停接收" Name="stopRecBtn" HorizontalAlignment="Right" Grid.Row="0" Grid.Column="2" Width="75" Margin="0,3,102,0" Click="stopRecBtn_Click"/>
                    <Button Content="清空接收區" Name="recClearBtn" HorizontalAlignment="Right"  Grid.Row="0" Grid.Column="2" VerticalAlignment="Bottom" Width="74" Click="recClearBtn_Click" Height="22" Margin="0,0,7,0"/>
                    <Border Name="recBorder" BorderThickness="1" Margin="11,1,6,1" Grid.Row="1" Grid.Column="0" BorderBrush="#FF911C1C"  Background="White" Opacity="0.4" Grid.ColumnSpan="3"   />
                    <ScrollViewer   Name="recScrol" VerticalScrollBarVisibility="Auto" Grid.Row="1" Grid.Column="0" Padding="0,0,0,0" Margin="12,2,7,2" Grid.ColumnSpan="3"  >

                        <TextBox x:Name="recTBox"   TextWrapping="Wrap"  ScrollViewer.VerticalScrollBarVisibility="Auto" AcceptsReturn="True" Background="{x:Null}" ClipToBounds="True" Foreground="Black" TextChanged="recTBox_TextChanged" BorderBrush="#FF8BA08B" IsEnabled="False"   />
                    </ScrollViewer>
                    <Line Width="500" Height="500" Fill="#FFD13535" Stroke="#FFD81010" OpacityMask="Black" Grid.ColumnSpan="3" Margin="21,0,21,-139" Grid.RowSpan="2"></Line>
                </Grid>
            </Grid>


            <Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,1,0,19" Grid.RowSpan="2">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="101*"/>
                    <ColumnDefinition Width="97*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="25"></RowDefinition>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition Width="Auto" ></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <Border BorderThickness="1" Margin="10,0,0,0"  Grid.Row="0" Grid.Column="0" Background="White" Opacity="0.4"  />
                    <ScrollViewer Name="sendScrol"  VerticalScrollBarVisibility="Auto" Grid.Row="0" Grid.Column="0" Padding="0,0,0,0"  MinHeight="100" MinWidth="460" Margin="10,0,0,0">
                        <TextBox x:Name="sendTBox"  TextWrapping="Wrap" ClipToBounds="True" Background="{x:Null}" AcceptsReturn="True"  />
                    </ScrollViewer>
                    <Grid Grid.Row="0" Grid.Column="2" Margin="0,3,0,0" >
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition></ColumnDefinition>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="32*"></RowDefinition>
                            <RowDefinition Height="33*"></RowDefinition>
                            <RowDefinition Height="32*"></RowDefinition>
                            <RowDefinition Height="21*"></RowDefinition>
                            <RowDefinition Height="12*"/>
                        </Grid.RowDefinitions>
                        <CheckBox Content="16進位制傳送" Name="sendModeCheck" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="15" Grid.Row="0" Grid.Column="0" Margin="0,7"/>
                        <CheckBox Content="自動傳送" Name="autoSendCheck" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="15" Grid.Row="1" Grid.Column="0" Click="autoSendCheck_Click" Margin="0,8,0,7" />
                        <TextBlock Text="週期:" Name="Cycle" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="15" Grid.Row="2" Grid.Column="0" Margin="0,19,0,14" Grid.RowSpan="2"></TextBlock>
                        <TextBox Text="1000" Name="Time" HorizontalAlignment="Right" VerticalAlignment="Top" Grid.Row="2" Grid.Column="0" Margin="0,21,23,0" Width="38" KeyDown="Time_KeyDown" LostFocus="Time_LostFocus" TextChanged="Time_TextChanged" Grid.RowSpan="2"/>
                        <TextBlock Text="ms" Name="Unit" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="15" Grid.Row="2" Grid.Column="0" Margin="0,19,2,14" Grid.RowSpan="2"></TextBlock>

                        <Button Content="清空傳送區" Name="sendClearBtn" HorizontalAlignment="Center" VerticalAlignment="Center" Click="sendClearBtn_Click"  Grid.Row="0" Grid.Column="1" Height="24" Width="80" Margin="5,4"/>
                        <Button  Content="計數清零" x:Name="countClearBtn" HorizontalAlignment="Center" VerticalAlignment="Bottom"  Grid.Row="1"  Grid.Column="1" Height="25" Width="80" Click="countClearBtn_Click" Margin="5,0"/>
                        <Button  Content="傳送資料" Click="Button_Send" x:Name="sendBtn" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="5,0,5,5" Grid.Row="2" Grid.RowSpan="3" Grid.Column="1" Height="50" Width="80" Background="#FFB9B55A"/>
                    </Grid>
                </Grid>
                <TextBlock Text="傳送區:" Grid.Row="0" Grid.Column="0" Margin="10,8,0,2" Grid.ColumnSpan="2"/>
            </Grid>
            <TextBlock Grid.Row="3" Grid.Column="0" Text="傳送數:" Margin="10,2,0,3" Grid.ColumnSpan="2"/>
            <TextBlock Grid.Row="3" Grid.Column="0" Text="0" Name="sendCount" Margin="80,0,0,2" VerticalAlignment="Bottom" Grid.ColumnSpan="2" Height="15"></TextBlock>
            <TextBlock Grid.Row="3" Grid.Column="0" Text="接收數:" Margin="160,0,0,3" VerticalAlignment="Bottom" Grid.ColumnSpan="2" Height="15"></TextBlock>
            <TextBlock Grid.Row="3" Grid.Column="1" Text="0" Name="recCount" Margin="41,0,371,3" VerticalAlignment="Bottom" Height="15"/>
        </Grid>
    </Grid>
</Window>
  1. 點選MainWindow.xaml-雙擊進入MainWindow.xaml.cs進行功能設計

#define MULTITHREAD
using Microsoft.Win32;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
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.Windows.Threading;

namespace 你的程式名
{
    /// <summary>
    /// MainWindow.xaml 的互動邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        SerialPort ComPort = new SerialPort();//宣告一個串列埠      
        private string[] ports;//可用串列埠陣列
        private bool recStaus = true;//接收狀態字
        private bool ComPortIsOpen = false;//COM口開啟狀態字,在開啟/關閉串列埠中使用,這裡沒有使用自帶的ComPort.IsOpen,因為在串列埠突然丟失的時候,ComPort.IsOpen會自動false,邏輯混亂
        private bool Listening = false;//用於檢測是否沒有執行完invoke相關操作,僅在單執行緒收發使用,但是在公共程式碼區有相關設定,所以未用#define隔離
        private bool WaitClose = false;//invoke裡判斷是否正在關閉串列埠是否正在關閉串列埠,執行Application.DoEvents,並阻止再次invoke ,解決關閉串列埠時,程式假死, 僅在單執行緒收發使用,但是在公共程式碼區有相關設定,所以未用#define隔離
        IList<customer> comList = new List<customer>();//可用串列埠集合
        DispatcherTimer autoSendTick = new DispatcherTimer();//定時傳送
#if MULTITHREAD
        private static bool Sending = false;//正在傳送資料狀態字
        private static Thread _ComSend;//傳送資料執行緒
        Queue recQueue = new Queue();//接收資料過程中,接收資料執行緒與資料處理執行緒直接傳遞的佇列,先進先出
        private SendSetStr SendSet = new SendSetStr();//傳送資料執行緒傳遞引數的結構體
        private struct SendSetStr//傳送資料執行緒傳遞引數的結構體格式
        {
            public string SendSetData;//傳送的資料
            public bool? SendSetMode;//傳送模式
        }
#endif

        public MainWindow()
        {
            InitializeComponent();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)//主視窗初始化
        {
            //↓↓↓↓↓↓↓↓↓可用串列埠下拉控制元件↓↓↓↓↓↓↓↓↓
            ports = SerialPort.GetPortNames();//獲取可用串列埠
            if (ports.Length > 0)//ports.Length > 0說明有串列埠可用
            {
                for (int i = 0; i < ports.Length; i++)
                {
                    comList.Add(new customer() { com = ports[i] });//下拉控制元件裡新增可用串列埠
                }
                AvailableComCbobox.ItemsSource = comList;//資源路勁
                AvailableComCbobox.DisplayMemberPath = "com";//顯示路徑
                AvailableComCbobox.SelectedValuePath = "com";//值路徑
                AvailableComCbobox.SelectedValue = ports[0];//預設選第1個串列埠
            }
            else//未檢測到串列埠
            {
                MessageBox.Show("無可用串列埠");
            }
            //↑↑↑↑↑↑↑↑↑可用串列埠下拉控制元件↑↑↑↑↑↑↑↑↑

            //↓↓↓↓↓↓↓↓↓波特率下拉控制元件↓↓↓↓↓↓↓↓↓
            IList<customer> rateList = new List<customer>();//可用波特率集合
            rateList.Add(new customer() { BaudRate = "1200" });
            rateList.Add(new customer() { BaudRate = "2400" });
            rateList.Add(new customer() { BaudRate = "4800" });
            rateList.Add(new customer() { BaudRate = "9600" });
            rateList.Add(new customer() { BaudRate = "14400" });
            rateList.Add(new customer() { BaudRate = "19200" });
            rateList.Add(new customer() { BaudRate = "28800" });
            rateList.Add(new customer() { BaudRate = "38400" });
            rateList.Add(new customer() { BaudRate = "57600" });
            rateList.Add(new customer() { BaudRate = "115200" });
            RateListCbobox.ItemsSource = rateList;
            RateListCbobox.DisplayMemberPath = "BaudRate";
            RateListCbobox.SelectedValuePath = "BaudRate";
            //↑↑↑↑↑↑↑↑↑波特率下拉控制元件↑↑↑↑↑↑↑↑↑        

            //↓↓↓↓↓↓↓↓↓預設設定↓↓↓↓↓↓↓↓↓
            RateListCbobox.SelectedValue = "115200";//波特率預設設定115200
            ComPort.ReadTimeout = 8000;//串列埠讀超時8秒
            ComPort.WriteTimeout = 8000;//串列埠寫超時8秒,在1ms自動傳送資料時拔掉串列埠,寫超時5秒後,會自動停止傳送,如果無超時設定,這時程式假死
            ComPort.ReadBufferSize = 1024;//資料讀快取
            ComPort.WriteBufferSize = 1024;//資料寫快取
            sendBtn.IsEnabled = false;//傳送按鈕初始化為不可用狀態
            sendModeCheck.IsChecked = true;//傳送模式預設為未選中狀態
            recModeCheck.IsChecked = true;//接收模式預設為未選中狀態
            //↑↑↑↑↑↑↑↑↑預設設定↑↑↑↑↑↑↑↑↑
            ComPort.DataReceived += new SerialDataReceivedEventHandler(ComReceive);//串列埠接收中斷
            autoSendTick.Tick += new EventHandler(autoSend);//定時傳送中斷
#if MULTITHREAD
            Thread _ComRec = new Thread(new ThreadStart(ComRec)); //查詢串列埠接收資料執行緒宣告
            _ComRec.Start();//啟動執行緒
#endif

        }


        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)//關閉視窗closing
        {
            MessageBoxResult result = MessageBox.Show("確認是否要退出?", "退出", MessageBoxButton.YesNo);//顯示確認視窗
            if (result == MessageBoxResult.No)
            {
                e.Cancel = true;//取消操作
            }
        }

        private void Window_Closed(object sender, EventArgs e)//關閉視窗確認後closed ALT+F4
        {
            Application.Current.Shutdown();//先停止執行緒,然後終止程序.
            Environment.Exit(0);//直接終止程序.
        }

        public class customer//各下拉控制元件訪問介面
        {

            public string com { get; set; }//可用串列埠
            public string com1 { get; set; }//可用串列埠
            public string BaudRate { get; set; }//波特率
        }
        private void Button_Open(object sender, RoutedEventArgs e)//開啟/關閉串列埠事件
        {
            if (AvailableComCbobox.SelectedValue == null)//先判斷是否有可用串列埠
            {
                MessageBox.Show("無可用串列埠,無法開啟!");
                return;//沒有串列埠,提示後直接返回
            }
            #region 開啟串列埠
            if (ComPortIsOpen == false)//ComPortIsOpen == false當前串列埠為關閉狀態,按鈕事件為開啟串列埠
            {

                try//嘗試開啟串列埠
                {
                    ComPort.PortName = AvailableComCbobox.SelectedValue.ToString();//設定要開啟的串列埠
                    ComPort.BaudRate = Convert.ToInt32(RateListCbobox.SelectedValue);//設定當前波特率

                    ComPort.Open();//開啟串列埠

                }
                catch//如果串列埠被其他佔用,則無法開啟
                {
                    MessageBox.Show("無法開啟串列埠,請檢測此串列埠是否有效或被其他佔用!");
                    GetPort();//重新整理當前可用串列埠
                    return;//無法開啟串列埠,提示後直接返回
                }

                //↓↓↓↓↓↓↓↓↓成功開啟串列埠後的設定↓↓↓↓↓↓↓↓↓
                openBtn.Content = "關閉通訊埠";//按鈕顯示改為“關閉按鈕”
                OpenImage.Source = new BitmapImage(new Uri("image\\On.png", UriKind.Relative));//開關狀態圖片切換為ON
                ComPortIsOpen = true;//串列埠開啟狀態字改為true
                WaitClose = false;//等待關閉串列埠狀態改為false                
                sendBtn.IsEnabled = true;//使能“傳送資料”按鈕
                defaultSet.IsEnabled = false;//開啟串列埠後失能重置功能
                AvailableComCbobox.IsEnabled = false;//失能可用串列埠控制元件
                RateListCbobox.IsEnabled = false;//失能可用波特率控制元件
                //↑↑↑↑↑↑↑↑↑成功開啟串列埠後的設定↑↑↑↑↑↑↑↑↑

                if (autoSendCheck.IsChecked == true)//如果開啟前,自動傳送控制元件就被選中,則開啟串列埠後自動開始傳送資料
                {
                    autoSendTick.Interval = TimeSpan.FromMilliseconds(Convert.ToInt32(Time.Text));//設定自動傳送間隔
                    autoSendTick.Start();//開啟自動傳送
                }

            }
            #endregion
            #region 關閉串列埠
            else//ComPortIsOpen == true,當前串列埠為開啟狀態,按鈕事件為關閉串列埠
            {
                try//嘗試關閉串列埠
                {
                    autoSendTick.Stop();//停止自動傳送
                    autoSendCheck.IsChecked = false;//停止自動傳送控制元件改為未選中狀態
                    ComPort.DiscardOutBuffer();//清發送快取
                    ComPort.DiscardInBuffer();//清接收快取
                    WaitClose = true;//啟用正在關閉狀態字,用於在串列埠接收方法的invoke裡判斷是否正在關閉串列埠
                    while (Listening)//判斷invoke是否結束
                    {
                        DispatcherHelper.DoEvents(); //迴圈時,仍進行等待事件中的程序,該方法為winform中的方法,WPF裡面沒有,這裡在後面自己實現
                    }
                    ComPort.Close();//關閉串列埠
                    WaitClose = false;//關閉正在關閉狀態字,用於在串列埠接收方法的invoke裡判斷是否正在關閉串列埠
                    SetAfterClose();//成功關閉串列埠或串列埠丟失後的設定
                }

                catch//如果在未關閉串列埠前,串列埠就已丟失,這時關閉串列埠會出現異常
                {
                    if (ComPort.IsOpen == false)//判斷當前串列埠狀態,如果ComPort.IsOpen==false,說明串列埠已丟失
                    {
                        SetComLose();
                    }
                    else//未知原因,無法關閉串列埠
                    {
                        MessageBox.Show("無法關閉串列埠,原因未知!");
                        return;//無法關閉串列埠,提示後直接返回
                    }
                }
            }
            #endregion

        }

        private void Button_Send(object sender, RoutedEventArgs e)//傳送資料按鈕點選事件
        {
            Send();//呼叫傳送方法
        }

        void autoSend(object sender, EventArgs e)//自動傳送
        {
            Send();//呼叫傳送方法
        }
        void Send()//傳送資料,分為多執行緒方式和單執行緒方式
        {
#if MULTITHREAD
            if (Sending == true) return;//如果當前正在傳送,則取消本次傳送,本句註釋後,可能阻塞在ComSend的lock處
            _ComSend = new Thread(new ParameterizedThreadStart(ComSend)); //new傳送執行緒
            SendSet.SendSetData = sendTBox.Text;//傳送資料執行緒傳遞引數的結構體--傳送的資料
            SendSet.SendSetMode = sendModeCheck.IsChecked;//傳送資料執行緒傳遞引數的結構體--傳送方式
            _ComSend.Start(SendSet);//傳送執行緒啟動
#endif
        }
#if MULTITHREAD
        private void ComSend(Object obj)//傳送資料 獨立執行緒方法 傳送資料時UI可以響應
        {

            lock (this)//由於send()中的if (Sending == true) return,所以這裡不會產生阻塞,如果沒有那句,多次啟動該執行緒,會在此處排隊
            {
                Sending = true;//正在發生狀態字
                byte[] sendBuffer = null;//傳送資料緩衝區
                string sendData = SendSet.SendSetData;//複製傳送資料,以免傳送過程中資料被手動改變
                if (SendSet.SendSetMode == true)//16進位制傳送
                {
                    try //嘗試將傳送的資料轉為16進位制Hex
                    {
                        sendData = sendData.Replace(" ", "");//去除16進位制資料中所有空格
                        sendData = sendData.Replace("\r", "");//去除16進位制資料中所有換行
                        sendData = sendData.Replace("\n", "");//去除16進位制資料中所有換行
                        if (sendData.Length % 2 != 0)//資料長度為奇數位時,去除最後一位資料
                        {
                            sendData = sendData + "0";
                        }

                        List<string> sendData16 = new List<string>();//將傳送的資料,2個合為1個,然後放在該快取裡 如:123456→12,34,56
                        for (int i = 0; i < sendData.Length; i += 2)
                        {
                            sendData16.Add(sendData.Substring(i, 2));
                        }
                        sendBuffer = new byte[sendData16.Count];//sendBuffer的長度設定為:傳送的資料2合1後的位元組數
                        for (int i = 0; i < sendData16.Count; i++)
                        {
                            sendBuffer[i] = (byte)(Convert.ToInt32(sendData16[i], 16));//傳送資料改為16進位制
                        }
                    }
                    catch //無法轉為16進位制時,出現異常
                    {
                        UIAction(() =>
                        {
                            autoSendCheck.IsChecked = false;//自動傳送改為未選中
                            autoSendTick.Stop();//關閉自動傳送
                            MessageBox.Show("請輸入正確的16進位制資料");
                        });

                        Sending = false;//關閉正在傳送狀態
                        _ComSend.Abort();//終止本執行緒
                        return;//輸入的16進位制資料錯誤,無法傳送,提示後返回  
                    }

                }
                else //ASCII碼文字傳送
                {
                    sendBuffer = System.Text.Encoding.Default.GetBytes(sendData);//轉碼
                }
                try//嘗試傳送資料
                {//如果傳送位元組數大於1000,則每1000位元組傳送一次
                    int sendTimes = (sendBuffer.Length / 1000);//傳送次數
                    for (int i = 0; i < sendTimes; i++)//每次發生1000Bytes
                    {
                        ComPort.Write(sendBuffer, i * 1000, 1000);//傳送sendBuffer中從第i * 1000位元組開始的1000Bytes
                        UIAction(() =>//啟用UI
                        {
                            sendCount.Text = (Convert.ToInt32(sendCount.Text) + 1000).ToString();//刷新發送位元組數
                        });
                    }
                    if (sendBuffer.Length % 1000 != 0)//傳送位元組小於1000Bytes或上面傳送剩餘的資料
                    {
                        ComPort.Write(sendBuffer, sendTimes * 1000, sendBuffer.Length % 1000);
                        UIAction(() =>
                        {
                            sendCount.Text = (Convert.ToInt32(sendCount.Text) + sendBuffer.Length % 1000).ToString();//刷新發送位元組數
                        });
                    }


                }
                catch//如果無法傳送,產生異常
                {
                    UIAction(() =>//啟用UI
                    {
                        if (ComPort.IsOpen == false)//如果ComPort.IsOpen == false,說明串列埠已丟失
                        {
                            SetComLose();//串列埠丟失後的設定
                        }
                        else
                        {
                            MessageBox.Show("無法傳送資料,原因未知!");
                        }
                    });
                }
                //sendScrol.ScrollToBottom();//傳送資料區滾動到底部
                Sending = false;//關閉正在傳送狀態
                _ComSend.Abort();//終止本執行緒
            }

        }

#endif

#if MULTITHREAD
        private void ComReceive(object sender, SerialDataReceivedEventArgs e)//接收資料 中斷只標誌有資料需要讀取,讀取操作在中斷外進行
        {
            if (WaitClose) return;//如果正在關閉串列埠,則直接返回
            Thread.Sleep(10);//傳送和接收均為文字時,接收中為加入判斷是否為文字的演算法,傳送你(C4E3),接收可能識別為C4,E3,可用在這裡加延時解決
            if (recStaus)//如果已經開啟接收
            {
                byte[] recBuffer;//接收緩衝區
                try
                {
                    recBuffer = new byte[ComPort.BytesToRead];//接收資料快取大小
                    ComPort.Read(recBuffer, 0, recBuffer.Length);//讀取資料
                    recQueue.Enqueue(recBuffer);//讀取資料入列Enqueue(全域性)
                }
                catch
                {
                    UIAction(() =>
                    {
                        if (ComPort.IsOpen == false)//如果ComPort.IsOpen == false,說明串列埠已丟失
                        {
                            SetComLose();//串列埠丟失後相關設定
                        }
                        else
                        {
                            MessageBox.Show("無法接收資料,原因未知!");
                        }
                    });
                }

            }
            else//暫停接收
            {
                ComPort.DiscardInBuffer();//清接收快取
            }
        }
        void ComRec()//接收執行緒,視窗初始化中就開始啟動執行
        {
            while (true)//一直查詢串列埠接收執行緒中是否有新資料
            {
                if (recQueue.Count > 0)//當串列埠接收執行緒中有新的資料時候,佇列中有新進的成員recQueue.Count > 0
                {
                    string recData;//接收資料轉碼後快取
                    byte[] recBuffer = (byte[])recQueue.Dequeue();//出列Dequeue(全域性)
                    recData = System.Text.Encoding.Default.GetString(recBuffer);//轉碼
                    UIAction(() =>
                    {
                        if (recModeCheck.IsChecked == false)//接收模式為ASCII文字模式
                        {
                            recTBox.Text += recData;//加顯到接收區
                        }
                        else
                        {
                            StringBuilder recBuffer16 = new StringBuilder();//定義16進位制接收快取
                            for (int i = 0; i < recBuffer.Length; i++)
                            {
                                recBuffer16.AppendFormat("{0:X2}" + " ", recBuffer[i]);//X2表示十六進位制格式(大寫),域寬2位,不足的左邊填0。
                            }
                            recTBox.Text += recBuffer16.ToString();//加顯到接收區
                        }
                        recCount.Text = (Convert.ToInt32(recCount.Text) + recBuffer.Length).ToString();//接收資料位元組數
                        recScrol.ScrollToBottom();//接收文字框滾動至底部
                    });
                }
                else
                    Thread.Sleep(100);//如果不延時,一直查詢,將佔用CPU過高
            }

        }

#endif
        void UIAction(Action action)//在主執行緒外啟用執行緒方法
        {
            System.Threading.SynchronizationContext.SetSynchronizationContext(new System.Windows.Threading.DispatcherSynchronizationContext(App.Current.Dispatcher));
            System.Threading.SynchronizationContext.Current.Post(_ => action(), null);
        }
        private void SetAfterClose()//成功關閉串列埠或串列埠丟失後的設定
        {

            openBtn.Content = "開啟通訊埠";//按鈕顯示為“開啟串列埠”
            OpenImage.Source = new BitmapImage(new Uri("image\\Off.png", UriKind.Relative));
            ComPortIsOpen = false;//串列埠狀態設定為關閉狀態
            sendBtn.IsEnabled = false;//失能傳送資料按鈕
            defaultSet.IsEnabled = true;//開啟串列埠後使能重置功能
            AvailableComCbobox.IsEnabled = true;//使能可用串列埠控制元件
            RateListCbobox.IsEnabled = true;//使能可用波特率下拉控制元件

        }
        private void SetComLose()//成功關閉串列埠或串列埠丟失後的設定
        {
            autoSendTick.Stop();//串列埠丟失後要關閉自動傳送
            autoSendCheck.IsChecked = false;//自動傳送改為未選中
            WaitClose = true;//;//啟用正在關閉狀態字,用於在串列埠接收方法的invoke裡判斷是否正在關閉串列埠
            while (Listening)//判斷invoke是否結束
            {
                DispatcherHelper.DoEvents(); //迴圈時,仍進行等待事件中的程序,該方法為winform中的方法,WPF裡面沒有,這裡在後面自己實現
            }
            MessageBox.Show("串列埠已丟失");
            WaitClose = false;//關閉正在關閉狀態字,用於在串列埠接收方法的invoke裡判斷是否正在關閉串列埠
            GetPort();//重新整理可用串列埠
            SetAfterClose();//成功關閉串列埠或串列埠丟失後的設定
        }


        private void AvailableComCbobox_PreviewMouseDown(object sender, MouseButtonEventArgs e)//重新整理可用串列埠
        {
            GetPort();//重新整理可用串列埠
        }


        private void GetPort()//重新整理可用串列埠
        {

            comList.Clear();//情況控制元件連結資源
            AvailableComCbobox.DisplayMemberPath = "com1";
            AvailableComCbobox.SelectedValuePath = null;//路徑都指為空,清空下拉控制元件顯示,下面重新新增

            ports = new string[SerialPort.GetPortNames().Length];//重新定義可用串列埠陣列長度
            ports = SerialPort.GetPortNames();//獲取可用串列埠
            if (ports.Length > 0)//有可用串列埠
            {
                for (int i = 0; i < ports.Length; i++)
                {
                    comList.Add(new customer() { com = ports[i] });//下拉控制元件裡新增可用串列埠
                }
                AvailableComCbobox.ItemsSource = comList;//可用串列埠下拉控制元件資源路徑
                AvailableComCbobox.DisplayMemberPath = "com";//可用串列埠下拉控制元件顯示路徑
                AvailableComCbobox.SelectedValuePath = "com";//可用串列埠下拉控制元件值路徑
            }


        }


        private void sendClearBtn_Click(object sender, RoutedEventArgs e)//清空傳送區
        {
            sendTBox.Text = "";
        }

        private void recClearBtn_Click(object sender, RoutedEventArgs e)//清空接收區
        {
            recTBox.Text = "";
        }


        private void countClearBtn_Click(object sender, RoutedEventArgs e)//計數清零
        {
            sendCount.Text = "0";
            recCount.Text = "0";
        }

        private void stopRecBtn_Click(object sender, RoutedEventArgs e)//暫停/開啟接收按鈕事件
        {
            if (recStaus == true)//當前為開啟接收狀態
            {
                recStaus = false;//暫停接收
                stopRecBtn.Content = "開啟接收";//按鈕顯示為開啟接收
                recPrompt.Visibility = Visibility.Visible;//顯示已暫停接收提示
                recBorder.Opacity = 0;//接收區透明度改為0
            }
            else//當前狀態為關閉接收狀態
            {
                recStaus = true;//開啟接收
                stopRecBtn.Content = "暫停接收";//按鈕顯示狀態改為暫停接收
                recPrompt.Visibility = Visibility.Hidden;//隱藏已暫停接收提示
                recBorder.Opacity = 1;////接收區透明度改為1
            }
        }



        private void autoSendCheck_Click(object sender, RoutedEventArgs e)//自動傳送控制元件點選事件
        {

            if (autoSendCheck.IsChecked == true && ComPort.IsOpen == true)//如果當前狀態為開啟自動傳送且串列埠已開啟,則開始自動傳送
            {
                autoSendTick.Interval = TimeSpan.FromMilliseconds(Convert.ToInt32(Time.Text));//設定自動傳送間隔
                autoSendTick.Start();//開始自動傳送定時器
            }
            else//點選之前為開啟自動傳送狀態,點選後關閉自動傳送
            {
                autoSendTick.Stop();//關閉自動傳送定時器
            }
        }

        private void Time_KeyDown(object sender, KeyEventArgs e)//傳送週期文字控制元件-鍵盤按鍵事件
        {
            if (e.Key >= Key.D0 && e.Key <= Key.D9 || e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9)//只能輸入數字
            {
                e.Handled = false;
            }
            else e.Handled = true;
            if (e.Key == Key.Enter)//輸入回車
            {
                if (Time.Text.Length == 0 || Convert.ToInt32(Time.Text) == 0)//時間為空或時間等於0,設定為1000
                {
                    Time.Text = "1000";
                }
                autoSendTick.Interval = TimeSpan.FromMilliseconds(Convert.ToInt32(Time.Text));//設定自動傳送週期
            }
        }

        private void Time_TextChanged(object sender, TextChangedEventArgs e)//傳送週期文字控制元件-文字內容改變事件,與上面Time_KeyDown事件相比,可以防止貼上進來非數字資料
        {
            //只允許輸入數字
            TextBox textBox = sender as TextBox;
            TextChange[] change = new TextChange[e.Changes.Count];
            byte[] checkText = new byte[textBox.Text.Length];
            bool result = true;
            e.Changes.CopyTo(change, 0);
            int offset = change[0].Offset;
            checkText = System.Text.Encoding.Default.GetBytes(textBox.Text);
            for (int i = 0; i < textBox.Text.Length; i++)
            {
                result &= 0x2F < (Convert.ToInt32(checkText[i])) & (Convert.ToInt32(checkText[i])) < 0x3A;//0x2f-0x3a之間是數字0-10的ASCII碼
            }
            if (change[0].AddedLength > 0)
            {

                if (!result || Convert.ToInt32(textBox.Text) > 100000)//不是數字或資料大於100000,取消本次change
                {
                    textBox.Text = textBox.Text.Remove(offset, change[0].AddedLength);
                    textBox.Select(offset, 0);
                }
            }

        }

        private void Time_LostFocus(object sender, RoutedEventArgs e)//傳送週期文字控制元件-失去事件
        {
            if (Time.Text.Length == 0 || Convert.ToInt32(Time.Text) == 0)//時間為空或時間等於0,設定為1000
            {
                Time.Text = "1000";
            }
            autoSendTick.Interval = TimeSpan.FromMilliseconds(Convert.ToInt32(Time.Text));//設定自動傳送週期
        }


        public static class DispatcherHelper
        {
            [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
            public static void DoEvents()
            {
                DispatcherFrame frame = new DispatcherFrame();
                Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrames), frame);
                try { Dispatcher.PushFrame(frame); }
                catch (InvalidOperationException) { }
            }
            private static object ExitFrames(object frame)
            {
                ((DispatcherFrame)frame).Continue = false;
                return null;
            }
        }

        private void defaultSet_Click(object sender, RoutedEventArgs e)//重置按鈕click事件
        {
            RateListCbobox.SelectedValue = "115200";//波特率預設設定9600
        }



        private void recTBox_TextChanged(object sender, TextChangedEventArgs e)
        {

        }

        private void ParityComCbobox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }

        private void RateListCbobox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {

        }

        private void sendTBox_TextChanged(object sender, TextChangedEventArgs e)
        {

        }
    }
}
  1. 想加背景的可在GUI程式碼區加入以下程式碼:
 <Window.Background >
        <ImageBrush ImageSource="圖片地址"/>
    </Window.Background>
  1. 點選生成-點選生成(你的程式名)

  2. 成功





期間可點選除錯進行測試

除錯效果如圖



所生成的程式位置:你的程式名\你的程式名\bin\Debug