xamarin - 使用 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);
没有击中休息,但图像显示
我在拦截属性更改方面做错了什么,还是我从文档中遗漏了什么?
解决方案
您看到的主要问题是因为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.
推荐阅读
- windows - 使用 Windows 任务计划器执行 Php 命令
- python - python中的以下代码行是什么意思?我不知道“ List[str] ”是如何工作的
- python - 考虑到可能的列排列,删除 spark 数据帧重复项
- mongodb - 使用单独的过滤器对数据进行分组(MongoDB 查询)
- sql - Spark sql-基于另一个聚合选项进行聚合
- node.js - 如何使用用两种不同语言(Flask、Node.js)编写的后端 docker 在单个服务器上运行
- android - 使用 customword 数组适配器而不是资源字符串数组 KOTLIN
- javascript - 询问如何在 Telegram 中为内联查询创建数组
- r - 在 R 中选择多个历史日期后,Rvest Web 抓取
- c++ - 将 [[no_unique_address]] 与空基类继承组合时得到意外结果