C# LINQ查询中替代FirstOrDefault获取对应章节JSON文本的方法
功能故障问题描述
我开发的程序需要实现如下功能:用户点击ListView内协议对应的章节条目时,从JSON数据中拉取该选中章节的关联文本,目前功能运行异常,特此寻求解决方案。
选中章节的触发代码
//for chosen step inside protocol public void Handle_ItemTapped(object sender, ItemTappedEventArgs e) { //change title based on clicked step var tappedStep = (Content)MyListView.SelectedItem; var nextTitle = Title + " - " + tappedStep.ChapterTitle; Navigation.PushAsync(new StepView(_protocol, Title, tappedStep.ChapterTitle)); //Deselect item ((ListView)sender).SelectedItem = null; }
故障表现
StepView页面的标签文本始终返回首个章节的第一条文本,经排查是StepView.cs中使用了FirstOrDefault查询导致的,需要调整逻辑来获取选中章节的对应文本,而非协议内的第一条文本。
StepView页面核心代码
public partial class StepView : ContentPage { //get step private Protocol _protocol; //go to selected step public StepView(Protocol protocol, string title, string chapterTitle) { _protocol = protocol; InitializeComponent(); Title = title + " - " + chapterTitle; // get label text lblText.Text = protocol.Contents.FirstOrDefault(x => x.ChapterTitle == chapterTitle).Text; } private int index; public void BtnBack_Clicked(object sender, EventArgs e) { index--; var firstId = _protocol.Contents.FirstOrDefault(x => x.Contentid != null).Contentid; BtnNext.IsEnabled = true; if (index == firstId - 1) { BtnBack.IsEnabled = false; } var content = _protocol.Contents.ElementAtOrDefault(index); lblText.Text = content?.Text; //get current navTitle on button click getNewNavTitle(content); } public void BtnNext_Clicked(object sender, EventArgs e) { index++; BtnBack.IsEnabled = true; if (index == _protocol.Contents.Count - 1) { BtnNext.IsEnabled = false; } var content = _protocol.Contents.ElementAtOrDefault(index); lblText.Text = content?.Text; //get current navTitle on button click getNewNavTitle(content); } //get new protocol + chapter based on btnBack and btnNext private void getNewNavTitle(Content content) { Title = null; string nextTitile = _protocol.Name + " - " + content.NavTitle; Title = nextTitile; } //go back to home public void btnHome_Clicked(object sender, EventArgs e) { //go to mainpage Navigation.PushAsync(new MainPage()); } }
用到的JSON数据结构
{ "protocols": [ { "id": "1", "name": "Pols meten", "contents": [ { "contentid": "1", "chapterTitle": "Voorzorg", "text": "voor blabla" }, { "contentid": "2", "text": "voor blabla2" }, { "contentid": "3", "text": "voor blablabla3" }, { "contentid": "4", "chapterTitle": "Handeling", "text": "handeling text" } ] } ] }
领域类定义
public partial class RootObject { [JsonProperty("protocols")] public List<Protocol> Protocols { get; set; } } public partial class Protocol { [JsonProperty("id")] public long Id { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("contents")] public List<Content> Contents { get; set; } } public partial class Content { [JsonProperty("contentid")] public long Contentid { get; set; } [JsonProperty("chapterTitle", NullValueHandling = NullValueHandling.Ignore)] public string ChapterTitle { get; set; } [JsonProperty("text")] public string Text { get; set; } }
核心疑问
如何调整代码,无需使用FirstOrDefault即可获取选中章节起始位置对应的文本?
解决方案
你可以通过直接传递选中内容的索引和对象的方式,完全避免FirstOrDefault查询,同时修复上下翻页的逻辑错误,调整步骤如下:
1. 修改列表点击事件的传参逻辑
无需只传递章节标题,直接把选中的Content对象和它在列表中的索引传给StepView:
public void Handle_ItemTapped(object sender, ItemTappedEventArgs e) { var tappedStep = (Content)MyListView.SelectedItem; // 直接获取选中项在协议内容列表中的索引 int selectedIndex = _protocol.Contents.IndexOf(tappedStep); Navigation.PushAsync(new StepView(_protocol, Title, tappedStep, selectedIndex)); ((ListView)sender).SelectedItem = null; }
2. 重写StepView的构造函数,移除FirstOrDefault查询
直接用传入的选中对象赋值文本,同时初始化全局索引保证翻页逻辑正确:
public StepView(Protocol protocol, string title, Content selectedContent, int selectedIndex) { _protocol = protocol; InitializeComponent(); Title = title + " - " + selectedContent.ChapterTitle; // 直接用传入的选中对象赋值,无需查询 lblText.Text = selectedContent.Text; // 初始化全局索引,修复翻页起始位置错误 index = selectedIndex; // 初始化翻页按钮状态 BtnBack.IsEnabled = index > 0; BtnNext.IsEnabled = index < _protocol.Contents.Count - 1; }
3. 修复翻页逻辑的边界判断错误
你原有代码用contentid判断边界是错误的,contentid从1开始,列表索引从0开始,直接用索引判断即可:
public void BtnBack_Clicked(object sender, EventArgs e) { index--; BtnNext.IsEnabled = true; if (index == 0) { BtnBack.IsEnabled = false; } var content = _protocol.Contents.ElementAtOrDefault(index); lblText.Text = content?.Text; getNewNavTitle(content); }
额外注意点
你现有getNewNavTitle方法中用到了content.NavTitle,但你的Content类没有定义该属性,建议修改为content.ChapterTitle避免运行报错。
内容的提问来源于stack exchange,提问作者Teun
相关产品推荐
相关产品推荐

