C# WPF 上位机开发:批量电子元器件清点系统

By jerryxjr1220 at 2023-10-25 • 0人收藏 • 375人看过

上位机与电子台秤用TCP实现通讯

屏幕截图 2023-10-25 131952.png

<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   #1

孜孜不倦啊,另外glowwindow在我电脑上报错用不了,win7

2023-10-25   #2

回复#1 @aubreychao :

glowwindow换成普通window也是一样的,只不过窗体多了一点发光特效

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();
    }
}


登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...