C# WPF 上位机开发:批量电子元器件清点系统
By
jerryxjr1220
at 2023-10-25 • 0人收藏 • 769人看过
上位机与电子台秤用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