鉴于之前已经询问过 Prism 的多项功能(包括异步验证),我将提供一个精简且聚焦的回答,基于 WPF 环境,避免重复之前的内容
Prism 异步验证的示例。鉴于之前已经询问过 Prism 的多项功能包括异步验证我将提供一个精简且聚焦的回答基于 WPF 环境避免重复之前的内容如INotifyDataErrorInfo和模拟 API 的异步验证示例。本次示例将展示一个不同场景的异步验证例如验证密码强度通过异步 API 调用包括代码、测试代码、适用场景和使用方法。如果您有特定需求如与导航/区域的集成、更复杂的验证逻辑或特定测试场景请进一步说明我会定制答案。一、异步验证概述Prism 通过 WPF 的INotifyDataErrorInfo接口支持异步验证结合BindableBase和异步方法async/await实现动态输入验证。异步验证适用于需要远程或复杂逻辑的场景如 API 调用检查密码强度并通过错误通知机制更新 UI。主要特性异步处理支持耗时验证如 API 调用。错误通知通过INotifyDataErrorInfo提供动态错误反馈。MVVM 集成与 Prism 的 MVVM 模式无缝结合。模块化支持验证逻辑可定义在模块中。二、适用场景异步验证适用于远程验证如通过 API 检查密码强度或唯一性。复杂规则如验证密码是否符合安全策略长度、字符类型。实时反馈输入时异步验证并显示错误或状态。模块化应用模块中的视图模型需要独立异步验证。表单提交确保提交前所有字段通过异步验证。三、异步验证示例以下是一个异步验证密码强度的示例假设通过 API 检查密码是否满足要求。1. 项目配置安装 Prism NuGet 包如Prism.DryIoc。创建 Prism 应用程序继承PrismApplication.确保视图模型继承BindableBase。2. 定义模拟 API 服务模拟异步 API 调用以验证密码强度IPasswordValidationService.csusingSystem.Threading.Tasks;namespaceWpfApp.Services{publicinterfaceIPasswordValidationService{Task(boolIsValid,stringMessage)ValidatePasswordAsync(stringpassword);}}PasswordValidationService.csusingSystem.Text.RegularExpressions;usingSystem.Threading.Tasks;namespaceWpfApp.Services{publicclassPasswordValidationService:IPasswordValidationService{publicasyncTask(boolIsValid,stringMessage)ValidatePasswordAsync(stringpassword){// 模拟 API 延迟awaitTask.Delay(1000);if(string.IsNullOrEmpty(password))return(false,Password cannot be empty.);if(password.Length8)return(false,Password must be at least 8 characters.);if(!Regex.IsMatch(password,[A-Z]))return(false,Password must contain at least one uppercase letter.);if(!Regex.IsMatch(password,[0-9]))return(false,Password must contain at least one number.);return(true,Password is strong.);}}}3. 定义视图模型实现INotifyDataErrorInfo和异步验证逻辑MainWindowViewModel.csusingPrism.Commands;usingPrism.Mvvm;usingSystem.Collections;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Linq;usingSystem.Threading.Tasks;usingWpfApp.Services;namespaceWpfApp.ViewModels{publicclassMainWindowViewModel:BindableBase,INotifyDataErrorInfo{privatereadonlyIPasswordValidationService_validationService;privatestring_password;privatebool_isValidating;privatestring_validationMessage;privatereadonlyDictionarystring,Liststring_errorsnewDictionarystring,Liststring();publicstringPassword{get_password;set{if(SetProperty(ref_password,value)){ValidatePasswordAsync();}}}publicboolIsValidating{get_isValidating;setSetProperty(ref_isValidating,value);}publicstringValidationMessage{get_validationMessage;setSetProperty(ref_validationMessage,value);}publicDelegateCommandSubmitCommand{get;}publicMainWindowViewModel(IPasswordValidationServicevalidationService){_validationServicevalidationService;SubmitCommandnewDelegateCommand(OnSubmit,CanSubmit);}privateasyncvoidValidatePasswordAsync(){_errors.Remove(nameof(Password));IsValidatingtrue;ValidationMessageValidating...;try{var(isValid,message)await_validationService.ValidatePasswordAsync(_password);if(!isValid)AddError(nameof(Password),message);ValidationMessagemessage;}finally{IsValidatingfalse;RaiseErrorsChanged(nameof(Password));SubmitCommand.RaiseCanExecuteChanged();}}privatevoidOnSubmit(){ValidationMessageForm submitted successfully!;}privateboolCanSubmit(){return!HasErrors!IsValidating;}privatevoidAddError(stringpropertyName,stringerror){if(!_errors.ContainsKey(propertyName))_errors[propertyName]newListstring();_errors[propertyName].Add(error);}privatevoidRaiseErrorsChanged(stringpropertyName){ErrorsChanged?.Invoke(this,newDataErrorsChangedEventArgs(propertyName));}publicboolHasErrors_errors.Any();publiceventEventHandlerDataErrorsChangedEventArgsErrorsChanged;publicIEnumerableGetErrors(stringpropertyName){return_errors.ContainsKey(propertyName)?_errors[propertyName]:null;}}}4. 定义视图在MainWindow.xaml中应用异步验证并显示状态Window x:ClassWpfApp.MainWindow xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml xmlns:localclr-namespace:WpfApp.Converters TitleMainWindow Height450 Width800 Window.Resources local:ErrorConverter x:KeyErrorConverter/ local:BooleanToVisibilityConverter x:KeyBoolToVisibilityConverter/ Style TargetTypeTextBox Style.Triggers Trigger PropertyValidation.HasError ValueTrue Setter PropertyToolTip Value{Binding RelativeSource{RelativeSource Self}, Path(Validation.Errors)[0].ErrorContent}/ Setter PropertyBorderBrush ValueRed/ /Trigger /Style /Style /Window.Resources Grid StackPanel Margin10 TextBox Width200 Margin5 TextBox.Text Binding PathPassword UpdateSourceTriggerPropertyChanged ValidatesOnNotifyDataErrorsTrue/ /TextBox.Text TextBox.ToolTip Binding Path(Validation.Errors) RelativeSource{RelativeSource Self} Converter{StaticResource ErrorConverter}/ /TextBox.ToolTip /TextBox TextBlock Text{Binding ValidationMessage} FontSize14 Margin5/ TextBlock TextValidating... Visibility{Binding IsValidating, Converter{StaticResource BoolToVisibilityConverter}} Margin5/ Button ContentSubmit Command{Binding SubmitCommand} Width100 Margin5/ /StackPanel /Grid /WindowErrorConverter.csusingSystem;usingSystem.Globalization;usingSystem.Windows.Controls;usingSystem.Windows.Data;namespaceWpfApp.Converters{publicclassErrorConverter:IValueConverter{publicobjectConvert(objectvalue,TypetargetType,objectparameter,CultureInfoculture){if(valueisReadOnlyObservableCollectionValidationErrorerrorserrors.Any())returnstring.Join(\n,errors.Select(ee.ErrorContent));returnnull;}publicobjectConvertBack(objectvalue,TypetargetType,objectparameter,CultureInfoculture){thrownewNotImplementedException();}}}BooleanToVisibilityConverter.csusingSystem;usingSystem.Globalization;usingSystem.Windows;usingSystem.Windows.Data;namespaceWpfApp.Converters{publicclassBooleanToVisibilityConverter:IValueConverter{publicobjectConvert(objectvalue,TypetargetType,objectparameter,CultureInfoculture){return(valueisboolisVisibleisVisible)?Visibility.Visible:Visibility.Collapsed;}publicobjectConvertBack(objectvalue,TypetargetType,objectparameter,CultureInfoculture){returnvalueisVisibilityvisibilityvisibilityVisibility.Visible;}}}5. 配置应用程序在App.xaml.cs中注册服务usingPrism.Ioc;usingSystem.Windows;usingWpfApp.Services;namespaceWpfApp{publicpartialclassApp:PrismApplication{protectedoverrideWindowCreateShell(){returnContainer.ResolveMainWindow();}protectedoverridevoidRegisterTypes(IContainerRegistrycontainerRegistry){containerRegistry.RegisterIPasswordValidationService,PasswordValidationService();}}}四、测试代码以下是使用 MSTest 和 Moq 的单元测试示例测试异步验证逻辑1. 测试依赖安装 NuGet 包Microsoft.NET.Test.SdkMSTest.TestFrameworkMSTest.TestAdapterMoqPrism.DryIoc2. 测试代码测试 PasswordValidationServiceusingMicrosoft.VisualStudio.TestTools.UnitTesting;usingSystem.Threading.Tasks;usingWpfApp.Services;[TestClass]publicclassPasswordValidationServiceTests{privatePasswordValidationService_service;[TestInitialize]publicvoidSetup(){_servicenewPasswordValidationService();}[TestMethod]publicasyncTaskValidatePasswordAsync_ValidPassword_ReturnsValid(){var(isValid,message)await_service.ValidatePasswordAsync(Password123);Assert.IsTrue(isValid);Assert.AreEqual(Password is strong.,message);}[TestMethod]publicasyncTaskValidatePasswordAsync_ShortPassword_ReturnsInvalid(){var(isValid,message)await_service.ValidatePasswordAsync(Pass123);Assert.IsFalse(isValid);Assert.AreEqual(Password must be at least 8 characters.,message);}[TestMethod]publicasyncTaskValidatePasswordAsync_NoUppercase_ReturnsInvalid(){var(isValid,message)await_service.ValidatePasswordAsync(password123);Assert.IsFalse(isValid);Assert.AreEqual(Password must contain at least one uppercase letter.,message);}}测试 MainWindowViewModelusingMicrosoft.VisualStudio.TestTools.UnitTesting;usingMoq;usingSystem.Linq;usingSystem.Threading.Tasks;usingWpfApp.Services;usingWpfApp.ViewModels;[TestClass]publicclassMainWindowViewModelTests{privateMockIPasswordValidationService_validationServiceMock;privateMainWindowViewModel_viewModel;[TestInitialize]publicvoidSetup(){_validationServiceMocknewMockIPasswordValidationService();_viewModelnewMainWindowViewModel(_validationServiceMock.Object);}[TestMethod]publicvoidPassword_Empty_AddsError(){_viewModel.Password;Assert.IsTrue(_viewModel.HasErrors);varerrors_viewModel.GetErrors(nameof(_viewModel.Password))asListstring;Assert.IsTrue(errors.Contains(Password cannot be empty.));}[TestMethod]publicasyncTaskPassword_Invalid_AddsError(){_validationServiceMock.Setup(ss.ValidatePasswordAsync(weak)).ReturnsAsync((false,Password must be at least 8 characters.));_viewModel.Passwordweak;awaitTask.Delay(1500);// 等待异步验证完成Assert.IsTrue(_viewModel.HasErrors);varerrors_viewModel.GetErrors(nameof(_viewModel.Password))asListstring;Assert.IsTrue(errors.Contains(Password must be at least 8 characters.));Assert.AreEqual(Password must be at least 8 characters.,_viewModel.ValidationMessage);}[TestMethod]publicasyncTaskPassword_Valid_NoErrors(){_validationServiceMock.Setup(ss.ValidatePasswordAsync(Password123)).ReturnsAsync((true,Password is strong.));_viewModel.PasswordPassword123;awaitTask.Delay(1500);// 等待异步验证完成Assert.IsFalse(_viewModel.HasErrors);Assert.AreEqual(Password is strong.,_viewModel.ValidationMessage);Assert.IsTrue(_viewModel.SubmitCommand.CanExecute(null));}[TestMethod]publicasyncTaskIsValidating_SetDuringValidation(){_validationServiceMock.Setup(ss.ValidatePasswordAsync(Password123)).ReturnsAsync((true,Password is strong.));boolisValidatingChangedfalse;_viewModel.PropertyChanged(s,e){if(e.PropertyNamenameof(_viewModel.IsValidating))isValidatingChangedtrue;};_viewModel.PasswordPassword123;awaitTask.Delay(1500);// 等待异步验证完成Assert.IsTrue(isValidatingChanged);Assert.IsFalse(_viewModel.IsValidating);}}3. 测试说明PasswordValidationService 测试验证有效密码返回正确结果。验证短密码和无大写字母的密码返回正确错误。MainWindowViewModel 测试验证空密码触发错误。验证无效密码触发异步错误。验证有效密码无错误且命令可执行。验证异步验证期间IsValidating属性变化。五、注意事项异步处理使用async void在属性设置中触发异步验证但需谨慎处理异常。考虑使用防抖debounce技术避免频繁触发异步调用。UI 反馈使用IsValidating和BooleanToVisibilityConverter显示验证进度。使用ErrorConverter显示错误消息。模块化集成异步验证逻辑可定义在模块中与区域或导航结合。性能优化避免短时间内多次触发异步验证。使用缓存或延迟机制优化 API 调用。测试注意使用Task.Delay模拟异步等待确保测试覆盖异步逻辑。使用 Moq 模拟异步服务。六、总结Prism 异步验证通过INotifyDataErrorInfo和async/await实现动态输入验证适合远程验证如密码强度检查和复杂业务规则。结合 Prism 的 MVVM 支持异步验证可集成到模块化应用中。上述代码示例展示了密码强度的异步验证测试代码验证了核心功能。如果您需要更具体的内容例如与区域/导航/事件聚合器的集成、其他异步验证场景或特定测试用例请提供细节我会进一步优化答案

相关新闻

Oversecured Vulnerable Android App的Insecure Logger Service:敏感信息泄露漏洞实战

Oversecured Vulnerable Android App的Insecure Logger Service:敏感信息泄露漏洞实战

Oversecured Vulnerable Android App的Insecure Logger Service:敏感信息泄露漏洞实战 【免费下载链接】ovaa Oversecured Vulnerable Android App 项目地址: https://gitcode.com/gh_mirrors/ov/ovaa Oversecured Vulnerable Android App(简称ov…

2026/7/29 3:44:59 阅读更多 →
CANN/asc-devkit:矩阵乘输出的Channel拆分

CANN/asc-devkit:矩阵乘输出的Channel拆分

矩阵乘输出的Channel拆分 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。 项目地址: https:…

2026/7/30 2:53:06 阅读更多 →
结合之前对 Prism 导航服务、模块化开发、模块间通信、对话服务、事件聚合器、区域和数据绑定的提问,我将提供一个精简且聚焦的回答,详细介绍 Prism 中绑定转换器的功能、代码示例、测试代码

结合之前对 Prism 导航服务、模块化开发、模块间通信、对话服务、事件聚合器、区域和数据绑定的提问,我将提供一个精简且聚焦的回答,详细介绍 Prism 中绑定转换器的功能、代码示例、测试代码

结合之前对 Prism 导航服务、模块化开发、模块间通信、对话服务、事件聚合器、区域和数据绑定的提问,我将提供一个精简且聚焦的回答,详细介绍 Prism 中绑定转换器的功能、代码示例、测试代码、适用场景和使用方法,基于 WPF 环境,避…

2026/7/29 23:47:22 阅读更多 →

最新新闻

上市公司都在使用的开源视频剪辑工具:低成本、高安全、可定制

上市公司都在使用的开源视频剪辑工具:低成本、高安全、可定制

上市公司都在使用的开源视频剪辑工具:低成本、高安全、可定制 对于有大量视频生产需求的企业来说,视频剪辑工具一直是个痛点: 采购商用剪辑工具:每年几万到几十万的授权费,数据上传到第三方服务器,合规风…

2026/7/30 12:49:06 阅读更多 →
致原生家庭中的你

致原生家庭中的你

致原生家庭中的你: 接受父母的局限, 不再背负他们的命运, 从“忠诚于父母”转向“忠诚于自己”。 注: 过好自己的生活, 就是让伤害的链条在我们这一代停止的方法。

2026/7/30 12:49:06 阅读更多 →
使用LLM语义模型智能对比服装吊牌字段:告别“型号”与“款式”的混乱

使用LLM语义模型智能对比服装吊牌字段:告别“型号”与“款式”的混乱

在服装行业供应链管理中,一个长期存在的痛点是:不同厂家对服装吊牌上的字段命名五花八门。同一件衣服,A厂家标注为“型号”,B厂家可能标注为“款式”,C厂家又可能使用“款号”。这种命名不一致给数据整合、库存管理和销…

2026/7/30 12:48:06 阅读更多 →
四向车选哪家好?2026国内主流四向穿梭车品牌盘点

四向车选哪家好?2026国内主流四向穿梭车品牌盘点

随着智能仓储和自动化立体库快速发展,越来越多企业开始关注四向穿梭车系统。但对于采购负责人来说,一个常见问题是:四向车选哪家好?实际上,不同厂商在技术路线、行业经验和服务能力方面各有优势。选择适合自身业务需求…

2026/7/30 12:48:06 阅读更多 →
OCR预处理关键一步:文本方向(正/倒)判断的原理与实践

OCR预处理关键一步:文本方向(正/倒)判断的原理与实践

在光学字符识别(OCR)的实际应用中,我们处理的文档图像来源复杂,其文本方向并非总是规整的“正向”。有时,由于扫描仪设置、相机拍摄角度或原始文档排版等问题,图像中的文本可能是倒置的(旋转180…

2026/7/30 12:48:06 阅读更多 →
AI视觉检测系统:终结FA光纤阵列外观不良困扰

AI视觉检测系统:终结FA光纤阵列外观不良困扰

在光通信器件、数据中心互联等高端制造领域,FA(Fiber Array)光纤阵列作为光信号传输与耦合的核心元件,其质量直接决定了整个光模块的性能与可靠性。然而,在生产过程中,FA光纤阵列总被各类外观不良所困扰&am…

2026/7/30 12:48:06 阅读更多 →

日新闻

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 您是否曾因Windows系统盘空间不足而烦恼?是否遇到过设…

2026/7/30 0:00:13 阅读更多 →
如何3步掌握Video Download Helper:网页视频下载的完整实战指南

如何3步掌握Video Download Helper:网页视频下载的完整实战指南

如何3步掌握Video Download Helper:网页视频下载的完整实战指南 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 你是否曾经在浏览…

2026/7/30 0:00:13 阅读更多 →
“双减”后首个AI备课压力测试报告:覆盖32所中小学的176节AI辅助课,暴露4大隐性增负节点

“双减”后首个AI备课压力测试报告:覆盖32所中小学的176节AI辅助课,暴露4大隐性增负节点

更多请点击: https://intelliparadigm.com 第一章:AI 教师备课辅助 AI 教师备课辅助系统正逐步成为教育数字化转型的核心支撑工具,它并非替代教师,而是通过语义理解、知识图谱与多模态生成能力,将教师从重复性劳动中解…

2026/7/30 0:00:13 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/29 22:18:20 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/29 14:34:28 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/29 15:00:03 阅读更多 →

月新闻