首页 > 解决方案 > 使用 CommunityToolKit.Mvvm amd Xamarin Forms 拦截属性更改

问题描述

我一直在使用我的 Xamarin Forms 项目将代码从 mvvmlight 移动到 CommunityToolkit.Mvvm 框架,但遇到了障碍。

在 mvvmlight 中,我会有这样的属性

bool loginOK;
public bool LoginOK
{
    get => loginOK;
    set => Set(()=>LoginOK, ref loginOK, value, true);
}

在 CommunityToolkit.Mvvm 中,这变成

bool loginOK;
public bool LoginOK
{
     get => loginOK;
     set => SetProperty(ref loginOK, value);
}

根据文档,如果属性更改,则会触发 PropertyChanging 事件

在我后面的代码中(在 Xam.Forms 中),我有这个

protected override void OnAppearing()
{
    base.OnAppearing();
    ViewModel.PropertyChanged += ObservableObject_PropertyChanged;
}

async void ObservableObject_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    switch (e.PropertyName)
    {
            case "LoginOK":
                if (ViewModel.LoginOK)
                {
                    if (ViewModel.SkipWelcome)
                    {
                        var d1 = await image.ScaleTo(4, 500);
                        if (!d1)
                        {
                            Device.StartTimer(TimeSpan.FromMilliseconds(500), () =>
                            {
                                Device.BeginInvokeOnMainThread(async () => await Shell.Current.GoToAsync("//TabBar"));
                                return false;
                            });
                        }
                    }
                }
                else
                {
                    var d2 = await image.ScaleTo(8, 500);
                    if (!d2)
                    {
                        var d3 = await image.ScaleTo(0, 500);
                        if (!d3)
                        {
                            Device.StartTimer(TimeSpan.FromMilliseconds(500), () =>
                            {
                                Device.BeginInvokeOnMainThread(async () => await Shell.Current.GoToAsync("//Welcome"));
                                return false;
                            });
                        }
                    }
                }
                break;
        }
    }

当我运行它并在行上设置一个断点

var d2 = await image.ScaleTo(8,500);

没有击中休息,但图像显示

我在拦截属性更改方面做错了什么,还是我从文档中遗漏了什么?

标签: xamarinxamarin.formswindows-community-toolkit

解决方案


您看到的主要问题是因为loginOK默认设置false和登录尝试失败时LoginOK不会在技术上发生变化,因此SetProperty不会导致引发PropertyChanged事件。如果您查看工具包的代码库,您会注意到他们总是在发出任何通知之前检查值是否已更改。

您可以考虑使用多种选项来解决此问题:

1 - 切换到布尔?

如果您切换到使用可空bool值,那么它的值将默认为空,因此当登录尝试失败false时将导致PropertyChanged触发。

2 - 使用枚举

类似于布尔?方法在第 1 点,而是使用类似如下的LoginResult枚举:

public enum LoginResult
{
    None = 0,
    Failed,
    Success
}

这将使您的代码比第 1 点更具可读性。

3 - 触发特定事件

与其依赖您,PropertyChanged您可以创建自己的事件(例如LoginAttempted),然后如果您愿意,您可以保持bool指示成功与否。

4 - 使用命令

事件有时被认为是过去的错误概念,因此您可以改为在视图上创建一个ICommand属性并将其分配给您的视图模型,从而允许视图模型调用Execute它并将日志结果传递给视图。就像是:

看法

public ViewConstructor()
{
    ViewModel.LoginAttemptCommand = new RelayCommand<bool>(() => OnLoginAttempted());
}

public void OnLoginAttempted(bool result)
{
    // Old logic on whether login succeeded.
}

视图模型

public ICommand LoginAttemptCommand { get; set; }

// Wherever you set LoginOK = false/true call:
LoginAttemptCommand.Execute(false); // or true if it succeeds.

推荐阅读