feat: 实现打开及关闭串口
parent
4fd583d9f9
commit
d0ea556775
|
@ -9,4 +9,15 @@
|
|||
<Application.Styles>
|
||||
<FluentTheme Mode="Light"/>
|
||||
</Application.Styles>
|
||||
|
||||
<Application.Resources>
|
||||
<SolidColorBrush x:Key="BrightGrayBrush">#474445</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MediumGrayBrush">#3b393a</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="ComboGrayBrush">#3a3a3a</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="DarkGrayBrush">#222121</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="DarkBlueBrush">#0865b1</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="BrightBlueBrush">#0f88eb</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="BrightRedBrush">#ef2244</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="DarkRedBrush">#c71e3a</SolidColorBrush>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.18" />
|
||||
<PackageReference Include="EventBinder.Avalonia" Version="2.5.0.1" />
|
||||
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using Autolabor;
|
||||
|
||||
namespace LoraGamepad.Models;
|
||||
|
||||
public class CBPortItem
|
||||
{
|
||||
public string PortName { get; set; }
|
||||
|
||||
public CBPortItem(string name)
|
||||
{
|
||||
PortName = name;
|
||||
}
|
||||
public static ObservableCollection<CBPortItem> GetPortList()
|
||||
{
|
||||
ObservableCollection<CBPortItem> portList = new ObservableCollection<CBPortItem>();
|
||||
List<SerialDevice> infos = SerialPort.FindPorts();
|
||||
foreach (var portInfo in infos)
|
||||
{
|
||||
portList.Add(new CBPortItem(portInfo.port));
|
||||
}
|
||||
|
||||
return portList;
|
||||
}
|
||||
}
|
||||
|
||||
public class CBPortItemCompare : IEqualityComparer<CBPortItem>
|
||||
{
|
||||
public bool Equals(CBPortItem? x, CBPortItem? y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.PortName == y.PortName;
|
||||
}
|
||||
|
||||
public int GetHashCode(CBPortItem obj)
|
||||
{
|
||||
return obj.PortName.GetHashCode();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Autolabor;
|
||||
|
||||
namespace LoraGamepad.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 串口驱动封装单例模式
|
||||
/// </summary>
|
||||
public class SerialPort
|
||||
{
|
||||
/// <summary>
|
||||
/// 串口单例
|
||||
/// </summary>
|
||||
public static readonly SerialPort Me = new();
|
||||
|
||||
/// <summary>
|
||||
/// 串口驱动基类
|
||||
/// </summary>
|
||||
private readonly SerialBase _serial = new();
|
||||
|
||||
private bool _isPortOpen = false;
|
||||
|
||||
private Action? _onWriteError;
|
||||
/// <summary>
|
||||
/// 串口是否打开属性
|
||||
/// </summary>
|
||||
public bool IsPortOpen => _isPortOpen;
|
||||
|
||||
/// <summary>
|
||||
/// 搜索串口列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<SerialDevice> FindPorts()
|
||||
{
|
||||
return SerialBase.EnumeratePorts();
|
||||
}
|
||||
|
||||
public void LisenningPort(Action? onWriteError)
|
||||
{
|
||||
_onWriteError = onWriteError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保护性构造函数
|
||||
/// </summary>
|
||||
private SerialPort() { }
|
||||
|
||||
/// <summary>
|
||||
/// 打开串口
|
||||
/// </summary>
|
||||
/// <param name="port">串口名</param>
|
||||
/// <param name="baudRate">波特率</param>
|
||||
/// <param name="timeout">超时时间</param>
|
||||
public void Open(string port,int baudRate,int timeout)
|
||||
{
|
||||
_serial.Port = port;
|
||||
_serial.Baudrate = baudRate;
|
||||
_serial.ReadTimeout = timeout;
|
||||
try
|
||||
{
|
||||
_serial.Open();
|
||||
_isPortOpen = true;
|
||||
}
|
||||
catch (SerialBaseException e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 串口发送
|
||||
/// </summary>
|
||||
/// <param name="data">Byte数据</param>
|
||||
public void Write(byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Me.IsPortOpen)
|
||||
{
|
||||
_serial.Write(data);
|
||||
}
|
||||
}
|
||||
catch (SerialBaseException e)
|
||||
{
|
||||
_onWriteError?.Invoke();
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取串口
|
||||
/// </summary>
|
||||
/// <returns>Byte数组</returns>
|
||||
public byte[] Read()
|
||||
{
|
||||
try
|
||||
{
|
||||
return _serial.Read();
|
||||
}
|
||||
catch (SerialBaseException e)
|
||||
{
|
||||
Console.WriteLine("My Line:" + e);
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryRead(out byte[] data)
|
||||
{
|
||||
if (_isPortOpen)
|
||||
{
|
||||
try
|
||||
{
|
||||
data = _serial.Read();
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
data = Array.Empty<byte>();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭串口
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
try
|
||||
{
|
||||
_isPortOpen = false;
|
||||
_serial.Close();
|
||||
}
|
||||
catch (SerialBaseException e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,88 @@
|
|||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using LoraGamepad.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace LoraGamepad.ViewModels;
|
||||
|
||||
public class TProViewModel : ViewModelBase
|
||||
{
|
||||
|
||||
private bool _isOpenPortButtonVisible = true;
|
||||
private bool _isClosePortButtonVisible;
|
||||
|
||||
private ObservableCollection<CBPortItem> _portList = new();
|
||||
public CBPortItem PortSelectItem { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> OpenPort { get; }
|
||||
public ReactiveCommand<Unit, Unit> ClosePort { get; }
|
||||
public TProViewModel()
|
||||
{
|
||||
PortList = CBPortItem.GetPortList();
|
||||
|
||||
OpenPort = ReactiveCommand.Create(PortOpenButtonClick);
|
||||
ClosePort = ReactiveCommand.Create(PortCloseButtonClick);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ComboBox串口列表绑定对象
|
||||
/// </summary>
|
||||
public ObservableCollection<CBPortItem> PortList
|
||||
{
|
||||
get => _portList;
|
||||
set => this.RaiseAndSetIfChanged(ref _portList, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新串口列表事件处理函数
|
||||
/// </summary>
|
||||
public void OnPortListComboBoxPressed()
|
||||
{
|
||||
var newList = CBPortItem.GetPortList();
|
||||
PortList.Except(newList,new CBPortItemCompare()).ToList().ForEach(a => { PortList.Remove(a); });
|
||||
newList.Except(PortList, new CBPortItemCompare()).ToList().ForEach(a => { PortList.Add(a); });
|
||||
newList.Except(PortList, new CBPortItemCompare()).ToList().ForEach(a => { PortList.Add(a); });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭串口按键可见性属性
|
||||
/// </summary>
|
||||
public bool IsClosePortButtonVisible
|
||||
{
|
||||
get => _isClosePortButtonVisible;
|
||||
set => this.RaiseAndSetIfChanged(ref _isClosePortButtonVisible, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开串口按键可见性属性
|
||||
/// </summary>
|
||||
public bool IsOpenPortButtonVisible
|
||||
{
|
||||
get => _isOpenPortButtonVisible;
|
||||
set => this.RaiseAndSetIfChanged(ref _isOpenPortButtonVisible, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开串口按键响应
|
||||
/// </summary>
|
||||
private void PortOpenButtonClick()
|
||||
{
|
||||
if (PortSelectItem.PortName == "") return;
|
||||
SerialPort.Me.Open(PortSelectItem.PortName,420000,1000);
|
||||
IsOpenPortButtonVisible = false;
|
||||
IsClosePortButtonVisible = true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭串口按键响应
|
||||
/// </summary>
|
||||
private void PortCloseButtonClick()
|
||||
{
|
||||
SerialPort.Me.Close();
|
||||
IsOpenPortButtonVisible = true;
|
||||
IsClosePortButtonVisible = false;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,18 +2,63 @@
|
|||
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:viewModels="clr-namespace:LoraGamepad.ViewModels"
|
||||
xmlns:eventBinder="clr-namespace:EventBinder;assembly=EventBinder.Avalonia"
|
||||
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="400"
|
||||
x:Class="LoraGamepad.Views.TProView">
|
||||
<UserControl.DataContext>
|
||||
<viewModels:TProViewModel/>
|
||||
</UserControl.DataContext>
|
||||
<!-- 样式设置 -->
|
||||
<UserControl.Styles>
|
||||
<Style Selector="Button.open">
|
||||
<Setter Property="Background" Value="{DynamicResource DarkBlueBrush}"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="FontSize" Value="18"/>
|
||||
</Style>
|
||||
<Style Selector="Button.close">
|
||||
<Setter Property="Background" Value="{DynamicResource DarkRedBrush}"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="FontSize" Value="18"/>
|
||||
</Style>
|
||||
<Style Selector="Button.open:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource BrightBlueBrush}"/>
|
||||
<Setter Property="TextBlock.Foreground" Value="White"/>
|
||||
</Style>
|
||||
<Style Selector="Button.close:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource BrightRedBrush}"/>
|
||||
<Setter Property="TextBlock.Foreground" Value="White"/>
|
||||
</Style>
|
||||
</UserControl.Styles>
|
||||
<!-- 页面布局 -->
|
||||
<Grid RowDefinitions="60,*,40,2*">
|
||||
<Grid Grid.Row="0" Background="Blue" ColumnDefinitions="*,3*,*">
|
||||
<Slider Grid.Column="0"/>
|
||||
<Button Grid.Column="2" Width="100" Height="40"/>
|
||||
<Grid Grid.Row="0" Background="Blue" ColumnDefinitions="*,2*,2*,*">
|
||||
<Slider Grid.Column="0" Width="80" HorizontalAlignment="Center"/>
|
||||
<ComboBox Grid.Column="1" SelectedIndex="0" VerticalAlignment="Center" Width="120" HorizontalAlignment="Right" Margin="10,0"
|
||||
Items="{Binding PortList}"
|
||||
SelectedItem="{Binding PortSelectItem}"
|
||||
PointerPressed="{eventBinder:EventBinding OnPortListComboBoxPressed}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock FontSize="18" Foreground="White" Text="{Binding PortName}"/>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<Button Grid.Column="2" Classes="open" Command="{Binding OpenPort}" IsVisible="{Binding IsOpenPortButtonVisible}"
|
||||
HorizontalAlignment="Left" Margin="0,0,10,0" Content="打开串口" HorizontalContentAlignment="Center" Width="100"
|
||||
Name="BtnPortOpen">
|
||||
</Button>
|
||||
<Button Grid.Column="2" Classes="close" Command="{Binding ClosePort}" IsVisible="{Binding IsClosePortButtonVisible}"
|
||||
HorizontalAlignment="Left" Margin="0,0,10,0" Content="关闭串口" HorizontalContentAlignment="Center" Width="100"
|
||||
Name="BtnPortClose">
|
||||
</Button>
|
||||
<Button Grid.Column="3" Width="100" Height="40"/>
|
||||
</Grid>
|
||||
<Grid Grid.Row="1" Background="Gray" ColumnDefinitions="2*,*,4*,*,2*">
|
||||
<Button Grid.Column="0" Width="80" Height="60"/>
|
||||
<Slider Grid.Column="1" Orientation="Vertical"/>
|
||||
<Slider Grid.Column="3" Orientation="Vertical"/>
|
||||
<Button Grid.Column="4" Width="80" Height="60"/>
|
||||
<Button Grid.Column="0" Width="80" Height="60" HorizontalAlignment="Center"/>
|
||||
<Slider Grid.Column="1" Orientation="Vertical" HorizontalAlignment="Center"/>
|
||||
<Slider Grid.Column="3" Orientation="Vertical" HorizontalAlignment="Center"/>
|
||||
<Button Grid.Column="4" Width="80" Height="60" HorizontalAlignment="Center"/>
|
||||
</Grid>
|
||||
<Grid Grid.Row="2" Background="Yellow">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
|
|
Loading…
Reference in New Issue