MAUI中ViewModel内修改IsLoading绑定未正常生效求助
问题:加载动画绑定的IsLoading变量未正常生效
在ViewModel中调用异步方法时,通过布尔变量IsLoading控制UI加载动画,但设置IsLoading = true后加载动画不显示,方法执行完成后IsLoading = false也未正常更新UI状态。
相关代码片段
LoadFileNames方法
public async Task LoadFileNames(string engineIdentifier, int displayMode) { try { ImageList.Clear(); IsLoading = true; await MergeFiles(engineIdentifier); IsLoading = false; ... }
ViewModel中IsLoading的实现
private bool _isLoading; public bool IsLoading { get { return _isLoading; } set { _isLoading = value; OnPropertyChanged(); } } public void OnPropertyChanged([CallerMemberName] string name = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
视图绑定代码
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" Shell.BackgroundColor="#696969" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:converters="clr-namespace:EngineCheck.Converters" x:Class="EngineCheck.Views.EngineView" xmlns:vm="clr-namespace:EngineCheck.ViewModels"> <ContentPage.BindingContext> <vm:EngineViewModel x:Name="viewmodel"/> </ContentPage.BindingContext>
加载动画控件
<ActivityIndicator IsRunning="{Binding IsLoading}" IsVisible="{Binding IsLoading}"/>
更新:MergeFiles及MergeBmpAndSvg方法
private async Task MergeFiles(string engineIdentifier) { try { string folderPath = prefs.Get("images_save_location", ""); string searchString = engineIdentifier; if(Directory.Exists(folderPath)) { string[] files = Directory.GetFiles(folderPath); foreach(string filePath in files) { string fileName = Path.GetFileName(filePath); if(fileName.EndsWith("bmp") && fileName.Contains(searchString)) { Utilities.Utilities.MergeBmpAndSvg(folderPath, fileName[..^4]); } } } else { //TODO } } catch(Exception ex) { logger.Error(ex.Message); } }
public static void MergeBmpAndSvg(string path, string filename) { try { Bitmap bmpImage = new Bitmap(path + "/" + filename + ".bmp"); SvgDocument svgDocument = SvgDocument.Open(path + "/" + filename + ".svg"); Bitmap svgBitmap = svgDocument.Draw(); Bitmap resultImage = new Bitmap(bmpImage.Width, bmpImage.Height); using(Graphics graphics = Graphics.FromImage(resultImage)) { graphics.DrawImage(bmpImage, 0, 0); graphics.DrawImage(svgBitmap, new System.Drawing.Point(0, 0)); } resultImage.Save(path + "/" + filename + ".png"); bmpImage.Dispose(); svgBitmap.Dispose(); resultImage.Dispose(); } catch(Exception ex) { logger.Error(ex.Message); } }
问题根源
MergeFiles方法虽标记为async,但内部无任何await异步操作,本质是同步阻塞UI线程。设置IsLoading = true后,UI线程立刻被文件IO、图片处理等同步操作卡住,没时间更新UI显示加载动画;同步操作完成后IsLoading又被立即设为false,导致用户看不到加载动画的状态变化。
此外,MergeBmpAndSvg是纯同步的图片处理方法,进一步加剧了UI线程的阻塞。
解决方案
方案1:将同步操作移至后台线程
修改MergeFiles,把耗时的同步逻辑包装到Task.Run中,让其在后台线程执行,释放UI线程更新加载状态:
private async Task MergeFiles(string engineIdentifier) { try { string folderPath = prefs.Get("images_save_location", ""); string searchString = engineIdentifier; if(Directory.Exists(folderPath)) { // 将文件遍历和图片处理放到后台线程 await Task.Run(() => { string[] files = Directory.GetFiles(folderPath); foreach(string filePath in files) { string fileName = Path.GetFileName(filePath); if(fileName.EndsWith("bmp") && fileName.Contains(searchString)) { Utilities.Utilities.MergeBmpAndSvg(folderPath, fileName[..^4]); } } }); } else { //TODO } } catch(Exception ex) { logger.Error(ex.Message); } }
方案2:优先使用异步API(更推荐)
替换同步方法为异步版本,比如文件IO用Directory.GetFilesAsync,减少手动线程包装的开销:
private async Task MergeFiles(string engineIdentifier) { try { string folderPath = prefs.Get("images_save_location", ""); string searchString = engineIdentifier; if(Directory.Exists(folderPath)) { // 使用异步文件遍历API string[] files = await Directory.GetFilesAsync(folderPath); foreach(string filePath in files) { string fileName = Path.GetFileName(filePath); if(fileName.EndsWith("bmp") && fileName.Contains(searchString)) { // 图片处理仍需后台执行,避免阻塞UI await Task.Run(() => Utilities.Utilities.MergeBmpAndSvg(folderPath, fileName[..^4])); } } } else { //TODO } } catch(Exception ex) { logger.Error(ex.Message); } }
额外注意事项
- 确认
ViewModel已正确实现INotifyPropertyChanged接口(代码中已实现,XAML绑定通常会自动订阅PropertyChanged事件)。 MergeBmpAndSvg涉及大量内存操作,在后台线程执行时需注意资源释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者DaveR
相关产品推荐
相关产品推荐

