毛伊岛 Windows 应用程序标签文本未在 UI 中更新

问题描述 投票:0回答:1

我的目的是更新 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 中。我在执行哪一步是错误的?

c# mvvm maui observablecollection
1个回答
0
投票

MVVM 模式

您声称您正在应用 MVVM 模式,但实际上您没有。在这里您可以找到有关 MVVM 模式和 MAUI 中数据绑定的更多信息

MVVM 应用程序中的依赖关系图通常如下所示(其中箭头表示“依赖于”):

View -> ViewModel -> Model

在您的情况下,依赖关系如下所示:

View -> Model -> ViewModel

模型通常保存数据,而视图模型是业务逻辑所在的地方,你可能会感到困惑。

问题1:BindingContext

现在,您的代码不起作用,因为您有两个 ViewModel 实例,其中一个是在 XAML 内创建并用作

BindingContext

<ContentPage.BindingContext>
    <vm:SampleVM/>
</ContentPage.BindingContext>

还有另一个由您所谓的“模型”实例化的(错误!)

public static void CheckServerConnectivity()
{
    SampleVM sampleVM = new SampleVM();

    //...
}

UI 对第二个实例一无所知,它与用作

BindingContext
的实例没有任何关系。

问题2:多线程

每次单击按钮时,您都会创建一个新的

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

注意,这只会解决绑定问题并防止启动多个线程,它不会解决任何其他设计或线程问题。

© www.soinside.com 2019 - 2024. All rights reserved.