我的目的是更新 UI 上的 ping 状态。我在 MAUI 桌面应用程序中使用 MVVM 模式。
在 MainPage.xaml.cs
namespace MauiSampleApp
{
public partial class MainPage : ContentPage
{
//int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
Shell.Current.GoToAsync("/Sample1");
SampleM sampleM = new SampleM();
sampleM.StartThreadfunction();
}
}
}
示例1.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiSampleApp.View.Sample1"
xmlns:vm="clr-namespace:MauiSampleApp.ViewModel"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
Title="Sample1">
<ContentPage.BindingContext>
<vm:SampleVM/>
</ContentPage.BindingContext>
<VerticalStackLayout>
<Label
Text="{Binding ServerStatus}"
VerticalOptions="Center"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
SampleVM.cs
namespace MauiSampleApp.ViewModel
{
public partial class SampleVM : ObservableObject
{
[ObservableProperty]
public string serverStatus = "Test";
public void setServerStatus(string currStatus)
{
ServerStatus = currStatus;
}
}
}
SampleM.cs
namespace MauiSampleApp.Model
{
internal class SampleM
{
public void StartThreadfunction()
{
Thread t1 = new Thread(() => CheckServerConnectivity());
t1.Start();
}
public static void CheckServerConnectivity()
{
SampleVM sampleVM = new SampleVM();
while (true)
{
try
{
Ping x = new Ping();
PingReply reply = x.Send(IPAddress.Parse("192.168.x.xxx"));
if (reply.Status == IPStatus.Success)
{
Console.WriteLine("Address is accessible");
sampleVM.setServerStatus("connected");
}
else
{
Console.WriteLine("Address is not accessible");
sampleVM.setServerStatus("Disconnected");
//break;
}
Thread.Sleep(5000);
}
catch (Exception ex)
{
Console.WriteLine("Exception message : {0}", ex.Message);
sampleVM.setServerStatus(ex.Message);
break;
}
}
return;
}
}
}
显示标签值“测试”,但线程状态未更新。在调试模式下,“ServerStatus”已更新,但未显示在 UI 中。我在执行哪一步是错误的?
您声称您正在应用 MVVM 模式,但实际上您没有。在这里您可以找到有关 MVVM 模式和 MAUI 中数据绑定的更多信息。
MVVM 应用程序中的依赖关系图通常如下所示(其中箭头表示“依赖于”):
View -> ViewModel -> Model
在您的情况下,依赖关系如下所示:
View -> Model -> ViewModel
模型通常保存数据,而视图模型是业务逻辑所在的地方,你可能会感到困惑。
现在,您的代码不起作用,因为您有两个 ViewModel 实例,其中一个是在 XAML 内创建并用作
BindingContext
<ContentPage.BindingContext>
<vm:SampleVM/>
</ContentPage.BindingContext>
还有另一个由您所谓的“模型”实例化的(错误!):
public static void CheckServerConnectivity()
{
SampleVM sampleVM = new SampleVM();
//...
}
UI 对第二个实例一无所知,它与用作
BindingContext
的实例没有任何关系。
每次单击按钮时,您都会创建一个新的
SampleM
实例,并且每次都会启动一个新线程,这将导致许多并发线程,这将产生不可预见的副作用,例如潜在的死锁、竞争条件等。
我不打算在这里详细介绍,因为您当前的问题与更新 UI 有关。
要解决绑定问题并使应用程序兼容 MVVM,您应该首先交换 Model 和 ViewModel,然后仅创建 ViewModel 的单个实例,然后将其用作
BindingContext
(最后一步):
型号
namespace MauiSampleApp.Model
{
public partial class SampleM : ObservableObject
{
[ObservableProperty]
private string serverStatus = "Test";
public void setServerStatus(string currStatus)
{
ServerStatus = currStatus;
}
}
}
视图模型
namespace MauiSampleApp.ViewModel
{
internal class SampleVM
{
public SampleM Model { get; } = new();
public void StartThreadfunction()
{
//Thread t1 = new Thread(() => CheckServerConnectivity());
//t1.Start();
Task.Run(CheckServerConnectivity);
}
public void CheckServerConnectivity()
{
while (true)
{
try
{
Ping x = new Ping();
PingReply reply = x.Send(IPAddress.Parse("192.168.x.xxx"));
if (reply.Status == IPStatus.Success)
{
Console.WriteLine("Address is accessible");
Model.setServerStatus("connected");
}
else
{
Console.WriteLine("Address is not accessible");
Model.setServerStatus("Disconnected");
//break;
}
Thread.Sleep(5000);
}
catch (Exception ex)
{
Console.WriteLine("Exception message : {0}", ex.Message);
Model.setServerStatus(ex.Message);
break;
}
}
}
}
}
查看
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiSampleApp.View.Sample1"
xmlns:vm="clr-namespace:MauiSampleApp.ViewModel"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
Title="Sample1">
<VerticalStackLayout>
<Label
Text="{Binding Model.ServerStatus}"
VerticalOptions="Center"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
namespace MauiSampleApp
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
SampleVM sampleVM = new SampleVM();
sampleVM.StartThreadfunction();
BindingContext = sampleVM;
}
}
}
注意,这只会解决绑定问题并防止启动多个线程,它不会解决任何其他设计或线程问题。