C# WPF 上位机开发:批量电子元器件清点系统
By
jerryxjr1220
at 2023-10-25 • 0人收藏 • 449人看过
上位机与电子台秤用TCP实现通讯
<hc:GlowWindow x:Class="WPFDigitalBalance.Views.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:vm="clr-namespace:WPFDigitalBalance.ViewModels" xmlns:hc="https://handyorg.github.io/handycontrol" d:DataContext="{d:DesignInstance Type=vm:MainViewModel}" mc:Ignorable="d" Title="Digital Balance" Height="450" Width="800" FontFamily="JetBrains Mono" Background="White" FontSize="{StaticResource TextFontSize}"> <Window.Resources> </Window.Resources> <hc:SimplePanel> <ScrollViewer x:Name="scrollViewer" VerticalScrollBarVisibility="Auto"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="3*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="5*" /> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Grid.Column="0" Grid.RowSpan="2"> <TextBlock Text="Switch" HorizontalAlignment="Center" FontSize="18" Style="{StaticResource TextBlockDefaultPrimary}" Margin="10" /> <hc:Shield Subject="Balance Power" Status="{Binding PowerStatus}" Color="{Binding PowerColor}" Margin="5" Command="{Binding PowerOnOffCommand}" /> <TextBlock Text="Balance Reading" HorizontalAlignment="Center" FontSize="18" Style="{StaticResource TextBlockDefaultPrimary}" Margin="20" /> <TextBox Text="{Binding BalanceReading, StringFormat={}{0:F3} g}" HorizontalContentAlignment="Center" Style="{StaticResource TextBoxExtend}" Foreground="{StaticResource SecondaryTextBrush}" IsReadOnly="True" /> <Button Content="Calculate" Style="{StaticResource ButtonPrimary}" Margin="0,100" Command="{Binding CalculateCommand}" /> </StackPanel> <StackPanel Grid.Column="1" Grid.Row="0"> <TextBlock Text="Balance" Style="{StaticResource TextBlockDefaultSuccess}" FontSize="20" Margin="10" /> <hc:Shield Subject="Balance Calibration" Status="Calibrated" Color="Green" HorizontalAlignment="Right" Margin="5" /> </StackPanel> <Grid Grid.Row="1" Grid.Column="1"> <Grid.RowDefinitions> <RowDefinition Height="3*" /> <RowDefinition Height="*" /> <RowDefinition Height="*" /> <RowDefinition Height="2*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="2*" /> <ColumnDefinition Width="3*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <TextBox Grid.ColumnSpan="3" Text="{Binding CalculateResult}" HorizontalContentAlignment="Center" FontSize="16" Margin="10" Style="{StaticResource TextBoxExtend}" IsReadOnly="True" Foreground="DarkSlateBlue" /> <TextBlock Grid.Column="0" Grid.Row="1" Text="Balance Read for 1 pcs" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource TextBlockDefaultPrimary}" /> <TextBox Grid.Column="1" Grid.Row="1" IsReadOnly="True" HorizontalContentAlignment="Center" VerticalAlignment="Center" Style="{StaticResource TextBoxExtend}" Foreground="Gray" Text="{Binding ReadingForOnePcs, StringFormat={}{0:F3} g}" /> <Button Grid.Column="2" Grid.Row="1" Content="Read" Style="{StaticResource ButtonSuccess}" Command="{Binding ReadForOnePcsCommand}" /> <TextBlock Grid.Column="0" Grid.Row="2" Text="Balance Read for 5 pcs" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource TextBlockDefaultPrimary}" /> <TextBox Grid.Column="1" Grid.Row="2" IsReadOnly="True" HorizontalContentAlignment="Center" VerticalAlignment="Center" Style="{StaticResource TextBoxExtend}" Foreground="Gray" Text="{Binding ReadingForFivePcs, StringFormat={}{0:F3} g}" /> <Button Grid.Column="2" Grid.Row="2" Content="Read" Style="{StaticResource ButtonSuccess}" Command="{Binding ReadForFivePcsCommand}" /> <TextBox Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="3" Text="{Binding TooltipInformation}" HorizontalContentAlignment="Center" FontSize="16" Margin="10" Style="{StaticResource TextBoxExtend}" IsReadOnly="True" Foreground="DarkOrange" /> </Grid> </Grid> </ScrollViewer> </hc:SimplePanel> </hc:GlowWindow>
using System; using System.Net; using System.Net.Sockets; using System.Text; using CommunityToolkit.Mvvm.ComponentModel; namespace WPFDigitalBalance.Models; public partial class TcpClientModel : ObservableObject { [ObservableProperty] private double _reading; [ObservableProperty] private TcpClient _tcpClient; [ObservableProperty] private TcpListener _tcpClientListener; public TcpClientModel() { TcpClientListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 34569); TcpClientListener.Start(); } public void CloseListening() { TcpClientListener.Stop(); } public void OnListening(bool switchflag = true) { while (switchflag) { TcpClient = TcpClientListener.AcceptTcpClient(); // 获取客户端的网络流 var stream = TcpClient.GetStream(); // 接收客户端发送的数据 var buffer = new byte[1024]; var bytesRead = stream.Read(buffer, 0, buffer.Length); var dataReceived = Encoding.UTF8.GetString(buffer, 0, bytesRead); try { var reading = double.Parse(dataReceived); Reading = reading; } catch (Exception e) { //ignored } // 关闭连接 TcpClient.Close(); } } }
using System; using System.Threading.Tasks; using System.Windows.Media; using System.Windows.Threading; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using WPFDigitalBalance.Models; namespace WPFDigitalBalance.ViewModels; public partial class MainViewModel : ObservableObject { [ObservableProperty] private double _balanceReading; [ObservableProperty] private string _calculateResult; [ObservableProperty] private SolidColorBrush _powerColor; [ObservableProperty] private string _powerStatus; [ObservableProperty] private double _readingForFivePcs; [ObservableProperty] private double _readingForOnePcs; [ObservableProperty] private TcpClientModel _tcpClientModel; [ObservableProperty] private string _tooltipInformation; private readonly DispatcherTimer timer; public MainViewModel() { PowerStatus = "Off"; PowerColor = Brushes.Red; BalanceReading = 0; CalculateResult = string.Empty; ReadingForOnePcs = 0; ReadingForFivePcs = 0; TooltipInformation = string.Empty; TcpClientModel = new TcpClientModel(); timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromMilliseconds(200); timer.Tick += (sender, args) => { BalanceReading = TcpClientModel.Reading; }; //发送消息 //WeakReferenceMessenger.Default.Send(new CustomizedMessage(new MessageModel())); } [RelayCommand] public void PowerOnOff() { if (PowerStatus == "On") { TcpClientModel.CloseListening(); timer.Stop(); PowerStatus = "Off"; PowerColor = Brushes.Red; } else { Task.Run(() => TcpClientModel.OnListening()); timer.Start(); PowerStatus = "On"; PowerColor = Brushes.Green; } } [RelayCommand] public void ReadForOnePcs() { ReadingForOnePcs = BalanceReading; } [RelayCommand] public void ReadForFivePcs() { ReadingForFivePcs = BalanceReading; } [RelayCommand] public void Calculate() { if (ReadingForOnePcs == 0 || ReadingForFivePcs == 0) { TooltipInformation = "No Reading! \r\nPlease check the balance!"; return; } if (Math.Abs(ReadingForFivePcs / 5 - ReadingForOnePcs) > 0.05) { TooltipInformation = "Variation too much! \r\nPlease check the balance!"; return; } CalculateResult = $"Total Count: {(int)(BalanceReading / (ReadingForFivePcs / 5))} pcs"; TooltipInformation = "Items Counted!"; } } //定义消息 // public class CustomizedMessage : ValueChangedMessage<MessageModel> // PropertyChangedMessage // RequestMessage ( Async + ..) // { // public CustomizedMessage(MessageModel value) : base(value) // { // } // }
using System.ComponentModel; using HandyControl.Controls; using WPFDigitalBalance.ViewModels; namespace WPFDigitalBalance.Views; /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : GlowWindow { private readonly MainViewModel mainViewModel; public MainWindow() { InitializeComponent(); #region 注册并接受消息 //WeakReferenceMessenger.Default.Register<CustomizedMessage>(this, (o, m) => { MessageBox.Show("Received!"); }); #endregion mainViewModel = new MainViewModel(); DataContext = mainViewModel; } protected override void OnClosing(CancelEventArgs e) { base.OnClosing(e); mainViewModel.TcpClientModel.CloseListening(); } }
TCP发送端:模拟电子天平发送数据
using System.Net.Sockets; using System.Text; var serverIP = "127.0.0.1"; var serverPort = 34569; for (var i = 10; i < 20; i++) { // 创建TcpClient对象并连接到服务器 var client = new TcpClient(serverIP, serverPort); Console.WriteLine("已连接到服务器"); // 获取客户端的网络流 var stream = client.GetStream(); // 向服务器发送数据 var requestData = (new Random().NextDouble() * 0.01 + 999).ToString(); var requestBytes = Encoding.UTF8.GetBytes(requestData); stream.Write(requestBytes, 0, requestBytes.Length); Console.WriteLine("请求数据已发送"); // 关闭连接 client.Close(); Thread.Sleep(500); }
3 个回复 | 最后更新于 2023-10-25
2023-10-25
#3
改造为异步方法,后台TCP服务器异步开启
前台通过CancellationToken来控制后台的TCP服务器的开关。
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; namespace WPFDigitalBalance.Models; public partial class TcpClientModel : ObservableObject { [ObservableProperty] private double _reading; [ObservableProperty] private TcpClient _tcpClient; [ObservableProperty] private TcpListener _tcpClientListener; [ObservableProperty] private CancellationTokenSource _cts; private CancellationToken ct; public TcpClientModel() { Cts = new CancellationTokenSource(); ct = Cts.Token; TcpClientListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 34569); } public void CloseListening() { TcpClientListener.Stop(); } public Task OnListeningAsync() { return Task.Run(() => { TcpClientListener.Start(); while (ct.IsCancellationRequested == false) { TcpClient = TcpClientListener.AcceptTcpClient(); // 获取客户端的网络流 var stream = TcpClient.GetStream(); // 接收客户端发送的数据 var buffer = new byte[1024]; var bytesRead = stream.Read(buffer, 0, buffer.Length); var dataReceived = Encoding.UTF8.GetString(buffer, 0, bytesRead); try { var reading = double.Parse(dataReceived); Reading = reading; } catch (Exception e) { //ignored } // 关闭连接 TcpClient.Close(); } }, ct); } }
using System; using System.Threading.Tasks; using System.Windows.Media; using System.Windows.Threading; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using WPFDigitalBalance.Models; namespace WPFDigitalBalance.ViewModels; public partial class MainViewModel : ObservableObject { [ObservableProperty] private double _balanceReading; [ObservableProperty] private string _calculateResult; [ObservableProperty] private SolidColorBrush _powerColor; [ObservableProperty] private string _powerStatus; [ObservableProperty] private SolidColorBrush _calibrationColor; [ObservableProperty] private string _calibrationStatus; [ObservableProperty] private double _readingForFivePcs; [ObservableProperty] private double _readingForOnePcs; [ObservableProperty] private TcpClientModel _tcpClientModel; [ObservableProperty] private string _tooltipInformation; private readonly DispatcherTimer timer; public MainViewModel() { PowerStatus = "Off"; PowerColor = Brushes.Red; CalibrationStatus = "Calibrated"; CalibrationColor = Brushes.Green; BalanceReading = 0; CalculateResult = string.Empty; ReadingForOnePcs = 0; ReadingForFivePcs = 0; TooltipInformation = string.Empty; TcpClientModel = new TcpClientModel(); timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromMilliseconds(200); timer.Tick += (sender, args) => { BalanceReading = TcpClientModel.Reading; }; //发送消息 //WeakReferenceMessenger.Default.Send(new CustomizedMessage(new MessageModel())); } [RelayCommand] public void PowerOnOff() { if (PowerStatus == "On") { TcpClientModel.Cts.Cancel(); TcpClientModel.CloseListening(); timer.Stop(); PowerStatus = "Off"; PowerColor = Brushes.Red; } else { TcpClientModel = new TcpClientModel(); TcpClientModel.OnListeningAsync(); timer.Start(); PowerStatus = "On"; PowerColor = Brushes.Green; } } [RelayCommand] public void ReadForOnePcs() { ReadingForOnePcs = BalanceReading; } [RelayCommand] public void ReadForFivePcs() { ReadingForFivePcs = BalanceReading; } [RelayCommand] public void Calculate() { if (ReadingForOnePcs == 0 || ReadingForFivePcs == 0) { TooltipInformation = "No Reading! \r\nPlease check the balance!"; return; } if (Math.Abs(ReadingForFivePcs / 5 - ReadingForOnePcs) > 0.05) { TooltipInformation = "Variation too much! \r\nPlease check the balance!"; return; } CalculateResult = $"Total Count: {(int)(BalanceReading / (ReadingForFivePcs / 5))} pcs"; TooltipInformation = "Items Counted!"; } } //定义消息 // public class CustomizedMessage : ValueChangedMessage<MessageModel> // PropertyChangedMessage // RequestMessage ( Async + ..) // { // public CustomizedMessage(MessageModel value) : base(value) // { // } // }
using System.ComponentModel; using HandyControl.Controls; using WPFDigitalBalance.ViewModels; namespace WPFDigitalBalance.Views; /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : GlowWindow { private readonly MainViewModel mainViewModel; public MainWindow() { InitializeComponent(); #region 注册并接受消息 //WeakReferenceMessenger.Default.Register<CustomizedMessage>(this, (o, m) => { MessageBox.Show("Received!"); }); #endregion mainViewModel = new MainViewModel(); DataContext = mainViewModel; } protected override void OnClosing(CancelEventArgs e) { base.OnClosing(e); mainViewModel.TcpClientModel.CloseListening(); mainViewModel.TcpClientModel.Cts.Dispose(); } }
登录后方可回帖
孜孜不倦啊,另外glowwindow在我电脑上报错用不了,win7