.NET MAUI Ping应用单按钮实现启停功能故障求助
.NET MAUI Ping应用:实现按钮启停切换功能
核心问题分析
原代码存在以下关键问题导致启停功能失效:
- 按钮同时绑定
Command和Clicked事件,逻辑冲突 flag字段未实现属性通知,状态变化无法同步到UI和命令逻辑Startc方法用Task.Delay().Wait()阻塞UI线程- 循环复用同一个
PingData对象,导致列表数据引用冲突 - 未实现停止逻辑,按钮文本无法随状态切换
解决方案与修改代码
步骤1:重构PingViewModel,实现状态管理与异步安全
using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Input; using System.Net.NetworkInformation; namespace YourNamespace.ViewModels { public class PingViewModel : INotifyPropertyChanged { private string _ip; private bool _isRunning; private string _buttonText = "Start"; private CancellationTokenSource _cts; // 用于安全取消异步任务 public ObservableCollection<PingData> PingCollection { get; set; } public ICommand TogglePingCommand { get; } public string Ip { get => _ip; set { _ip = value; OnPropertyChanged(); } } public bool IsRunning { get => _isRunning; set { _isRunning = value; ButtonText = value ? "Stop" : "Start"; OnPropertyChanged(); } } public string ButtonText { get => _buttonText; set { _buttonText = value; OnPropertyChanged(); } } public PingViewModel() { PingCollection = new ObservableCollection<PingData>(); TogglePingCommand = new Command(ExecuteTogglePing); } private async void ExecuteTogglePing() { if (IsRunning) { // 停止Ping任务 _cts?.Cancel(); IsRunning = false; } else { if (string.IsNullOrWhiteSpace(Ip)) return; // 校验IP输入 IsRunning = true; _cts = new CancellationTokenSource(); await StartPingAsync(_cts.Token); } } private async Task StartPingAsync(CancellationToken token) { var pingOptions = new PingOptions { Ttl = 200 }; while (!token.IsCancellationRequested) { var pingData = new PingData(); // 每次循环创建新实例,避免数据覆盖 using (var ping = new Ping()) { try { var reply = await ping.SendPingAsync(Ip, 1000, null, pingOptions); pingData.Status_ip = reply.Status.ToString(); pingData.IPAddress = reply.Address?.ToString() ?? Ip; if (reply.Status == IPStatus.Success) { pingData.TTL = reply.Options.Ttl.ToString(); pingData.ResponseTime = reply.RoundtripTime.ToString(); } } catch (PingException ex) { pingData.Status_ip = $"Error: {ex.Message}"; } } PingCollection.Insert(0, pingData); await Task.Delay(1000, token); // 非阻塞延迟 } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
步骤2:简化MainPage.xaml.cs,移除无用事件
namespace YourNamespace { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); BindingContext = new ViewModels.PingViewModel(); } } }
步骤3:调整MainPage.xaml,绑定动态文本与单一命令
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="YourNamespace.MainPage"> <StackLayout Padding="20" Spacing="15"> <Entry x:Name="IPEntry" Text="{Binding Ip}" Placeholder="IP Address" HorizontalOptions="Center" VerticalOptions="Center" WidthRequest="200" /> <Button x:Name="togglePingBtn" Text="{Binding ButtonText}" Command="{Binding TogglePingCommand}" HorizontalOptions="Center" /> <ListView x:Name="listViewRes" HorizontalScrollBarVisibility="Always" HeightRequest="400" WidthRequest="400" VerticalScrollBarVisibility="Always" ItemsSource="{Binding PingCollection}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout Orientation="Horizontal" Spacing="10"> <Label Text="{Binding Status_ip}" WidthRequest="100" /> <Label Text="{Binding IPAddress}" WidthRequest="120" /> <Label Text="{Binding TTL}" WidthRequest="50" /> <Label Text="{Binding ResponseTime}" WidthRequest="80" /> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage>
步骤4:PingData.cs保持原结构(无需修改)
public class PingData { public string IPAddress { get; set; } public string Status_ip { get; set; } public string TTL { get; set; } public string ResponseTime { get; set; } public int Count { get; set; } }
关键改进说明
- 异步安全:使用
CancellationTokenSource实现Ping任务的安全取消,避免线程冲突 - UI响应:所有异步操作使用
await,彻底解决UI阻塞问题 - 数据正确性:每次Ping创建新的
PingData实例,保证列表条目独立无覆盖 - 动态UI:按钮文本随
IsRunning状态自动切换,提升用户体验 - MVVM规范:移除冗余的
Clicked事件,完全使用Command绑定,符合MVVM设计原则
内容的提问来源于stack exchange,提问作者Zaid
相关产品推荐
相关产品推荐

