Xamarin.Android读取本地XML并绑定XAML遇文件不存在异常求助
Xamarin.Android读取本地XML文件异常修复与数据绑定实现方案
一、「There is no store file.」异常排查与修复
核心问题
- 文件路径错误:Xamarin.Android中,项目根目录的文件不会直接映射到应用运行目录,直接用
Path.Combine("store.xml")无法找到文件 - 文件属性未配置:未正确设置XML文件的生成操作,导致文件未被打包到APK中
修复步骤
1. 配置文件属性
- 在Visual Studio中选中
Store.xml文件,右键打开「属性」面板 - 将「生成操作」设置为
AndroidAsset,「复制到输出目录」设置为「始终复制」
2. 修改文件读取逻辑
Xamarin.Android读取Assets目录文件需使用AssetManager,替换原有的FileStream读取方式:
修改后的ViewModel代码:
public static void StoreLoad() { Dictionary<int, StoreData> newlist = new Dictionary<int, StoreData>(); XmlTextReader reader; try { // 通过AssetManager获取Assets目录下的文件流 var assets = Android.App.Application.Context.Assets; using (var stream = assets.Open("store.xml")) { reader = new XmlTextReader(stream); } } catch (FileNotFoundException ex) { throw new Exception("There is no store file."); } catch { throw new Exception("Unable to load store file."); } try { reader.Read(); reader.MoveToContent(); if (reader.LocalName != "StoreList") throw new Exception("Store file is corrupt."); reader.Read(); reader.MoveToContent(); while (!reader.EOF) { if (reader.LocalName == "Store") { int code; string name; string number; int dept = 0; code = int.Parse(reader.GetAttribute("Code")); number = reader.GetAttribute("Number"); name = reader.GetAttribute("ShortName"); string deptStr = reader.GetAttribute("Dept"); if (deptStr != null && deptStr.Length > 0) dept = int.Parse(deptStr); else dept = 0; newlist.Add(code, new StoreData(code, number, name, dept)); } reader.Read(); reader.MoveToContent(); } StoreData = newlist; } finally { reader.Close(); } }
3. 补充Model构造函数
原StoreData类缺少匹配的带参构造函数,补充后才能正常实例化:
public class StoreData { // 补充带参构造函数 public StoreData(int code, string number, string shortName, int dept) { Code = code; Number = number; ShortName = shortName; Dept = dept; } public int Code { get; set; } public string Number { get; set; } public int Dept { get; set; } public string ShortName { get; set; } }
二、XML数据绑定到XAML实现步骤
1. 改造ViewModel实现数据通知
ViewModel需实现INotifyPropertyChanged接口,确保数据变化能同步到UI:
public class StoreViewModel : INotifyPropertyChanged { private Dictionary<int, StoreData> _storeData; public Dictionary<int, StoreData> StoreData { get => _storeData; set { _storeData = value; OnPropertyChanged(nameof(StoreData)); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } // 将原静态方法改为实例方法,便于绑定上下文调用 public void StoreLoad() { Dictionary<int, StoreData> newlist = new Dictionary<int, StoreData>(); XmlTextReader reader; try { var assets = Android.App.Application.Context.Assets; using (var stream = assets.Open("store.xml")) { reader = new XmlTextReader(stream); } } catch (FileNotFoundException ex) { throw new Exception("There is no store file."); } catch { throw new Exception("Unable to load store file."); } try { reader.Read(); reader.MoveToContent(); if (reader.LocalName != "StoreList") throw new Exception("Store file is corrupt."); reader.Read(); reader.MoveToContent(); while (!reader.EOF) { if (reader.LocalName == "Store") { int code; string name; string number; int dept = 0; code = int.Parse(reader.GetAttribute("Code")); number = reader.GetAttribute("Number"); name = reader.GetAttribute("ShortName"); string deptStr = reader.GetAttribute("Dept"); if (deptStr != null && deptStr.Length > 0) dept = int.Parse(deptStr); else dept = 0; newlist.Add(code, new StoreData(code, number, name, dept)); } reader.Read(); reader.MoveToContent(); } StoreData = newlist; } finally { reader.Close(); } } }
2. 在XAML中配置绑定上下文与UI展示
以MainPage.xaml为例,设置绑定上下文并使用ListView展示数据:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:你的应用命名空间" x:Class="你的应用命名空间.MainPage"> <ContentPage.BindingContext> <local:StoreViewModel /> </ContentPage.BindingContext> <!-- 绑定Dictionary的Values集合作为ListView数据源 --> <ListView ItemsSource="{Binding StoreData.Values}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout Orientation="Horizontal" Padding="10"> <Label Text="{Binding Code}" WidthRequest="50"/> <Label Text="{Binding ShortName}" WidthRequest="150"/> <Label Text="{Binding Number}" WidthRequest="100"/> <Label Text="{Binding Dept}" WidthRequest="50"/> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage>
3. 在页面代码中触发数据加载
在MainPage.xaml.cs中调用ViewModel的加载方法:
public MainPage() { InitializeComponent(); var viewModel = (StoreViewModel)BindingContext; viewModel.StoreLoad(); }
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

