我在 Xamarin.forms 中遇到数据绑定问题
Posted
技术标签:
【中文标题】我在 Xamarin.forms 中遇到数据绑定问题【英文标题】:I'm having trouble with Data Binding in Xamarin.forms 【发布时间】:2020-11-09 07:24:46 【问题描述】:对于一些上下文,我正在尝试将我的视图链接到我的视图模型。我的模型中有一个 JSON 对象数组和另一个字符串。我想在我的视图中显示这些对象,但是我无法这样做。
我的模特:
namespace Timetabler.Models
public partial class Timetable
[JsonProperty("id")]
public long Id get; set;
[JsonProperty("nid")]
public long Nid get; set;
[JsonProperty("iid")]
public long Iid get; set;
[JsonProperty("lid")]
public long Lid get; set;
[JsonProperty("start")]
public double Start get; set;
[JsonProperty("dur")]
public double Dur get; set;
[JsonProperty("weeks")]
public string Weeks get; set;
[JsonProperty("day")]
public long Day get; set;
[JsonProperty("note", NullValueHandling = NullValueHandling.Ignore)]
public string Note get; set;
public partial struct TimetableElement
public long? Integer;
public string String;
public Timetable TimetableClass;
public static implicit operator TimetableElement(long Integer) => new TimetableElement Integer = Integer ;
public static implicit operator TimetableElement(string String) => new TimetableElement String = String ;
public static implicit operator TimetableElement(Timetable TimetableClass) => new TimetableElement TimetableClass = TimetableClass ;
public partial class Timetable
public static TimetableElement[][] FromJson(string json) => JsonConvert.DeserializeObject<TimetableElement[][]>(json, Converter.Settings);
public static class Serialize
public static string ToJson(this TimetableElement[][] self) => JsonConvert.SerializeObject(self, Converter.Settings);
internal static class Converter
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
TimetableElementConverter.Singleton,
new IsoDateTimeConverter DateTimeStyles = DateTimeStyles.AssumeUniversal
,
;
internal class TimetableElementConverter : JsonConverter
public override bool CanConvert(Type t) => t == typeof(TimetableElement) || t == typeof(TimetableElement?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
switch (reader.TokenType)
case JsonToken.Integer:
var integerValue = serializer.Deserialize<long>(reader);
return new TimetableElement Integer = integerValue ;
case JsonToken.String:
case JsonToken.Date:
var stringValue = serializer.Deserialize<string>(reader);
return new TimetableElement String = stringValue ;
case JsonToken.StartObject:
var objectValue = serializer.Deserialize<Timetable>(reader);
return new TimetableElement TimetableClass = objectValue ;
throw new Exception("Cannot unmarshal type TimetableElement");
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
var value = (TimetableElement)untypedValue;
if (value.Integer != null)
serializer.Serialize(writer, value.Integer.Value);
return;
if (value.String != null)
serializer.Serialize(writer, value.String);
return;
if (value.TimetableClass != null)
serializer.Serialize(writer, value.TimetableClass);
return;
throw new Exception("Cannot marshal type TimetableElement");
public static readonly TimetableElementConverter Singleton = new TimetableElementConverter();
我的视图模型:
namespace Timetabler.ViewModels
class TimetableViewModel : BaseViewModel
// First list in JSON data
public ObservableRangeCollection<TimetableElement> Names get;
// Second list in JSON data
public ObservableRangeCollection<TimetableElement> TypeOfClass get;
// Third list in JSON data
public ObservableRangeCollection<TimetableElement> Location get;
// Fourth list in JSON data
public ObservableRangeCollection<TimetableElement> Courses get;
public Command GetCoursesCommand get;
public Command GetNamesCommand get;
public TimetableViewModel()
Title = "Timetable";
// First list in JSON data
Names = new ObservableRangeCollection<TimetableElement>();
// Second list in JSON data
TypeOfClass = new ObservableRangeCollection<TimetableElement>();
// Third list in JSON data
Location = new ObservableRangeCollection<TimetableElement>();
// Fourth list in JSON data
Courses = new ObservableRangeCollection<TimetableElement>();
GetCoursesCommand = new Command(async () => await GetCoursesAsync());
GetNamesCommand = new Command(async () => await GetNamesAsync());
async Task GetNamesAsync()
if (IsBusy)
return;
try
IsBusy = true;
var timetableElements = await DataService.GetTimetablesAsync();
var names = timetableElements[0];
Names.ReplaceRange(names);
Title = $"Courses available(Names.Count";
catch (Exception ex)
Debug.WriteLine($"Unable to get Names: ex.Message");
await Application.Current.MainPage.DisplayAlert("Error!", ex.Message, "OK");
finally
IsBusy = false;
async Task GetTypeOfClassAsync()
if (IsBusy)
return;
try
IsBusy = true;
var timetableElements = await DataService.GetTimetablesAsync();
var typeOfClass = timetableElements[1];
TypeOfClass.ReplaceRange(typeOfClass);
Title = $"Courses available(TypeOfClass.Count";
catch (Exception ex)
Debug.WriteLine($"Unable to get TypeOfClass: ex.Message");
await Application.Current.MainPage.DisplayAlert("Error!", ex.Message, "OK");
finally
IsBusy = false;
async Task GetLocationsAsync()
if (IsBusy)
return;
try
IsBusy = true;
var timetableElements = await DataService.GetTimetablesAsync();
var location = timetableElements[2];
Location.ReplaceRange(location);
Title = $"Courses available(Courses.Count";
catch (Exception ex)
Debug.WriteLine($"Unable to get Location: ex.Message");
await Application.Current.MainPage.DisplayAlert("Error!", ex.Message, "OK");
finally
IsBusy = false;
async Task GetCoursesAsync()
if (IsBusy)
return;
try
IsBusy = true;
var timetableElements = await DataService.GetTimetablesAsync();
var courses = timetableElements[3];
Courses.ReplaceRange(courses);
Title = $"Courses available(Courses.Count";
catch (Exception ex)
Debug.WriteLine($"Unable to get courses: ex.Message");
await Application.Current.MainPage.DisplayAlert("Error!", ex.Message, "OK");
finally
IsBusy = false;
我的模型将 JSON 反序列化为 C# 对象,此时我的 ViewModel 将它们分解为数组。
我想在视图中显示这些对象。该视图是一个 Syncfusion 时间表。但在这一点上,我很高兴能够在列表视图中显示这些对象。我似乎也无法解决这个问题。我试过了:
我的观点
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:button="clr-namespace:Syncfusion.XForms.Buttons;assembly=Syncfusion.Buttons.XForms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:schedule="clr-namespace:Syncfusion.SfSchedule.XForms;assembly=Syncfusion.SfSchedule.XForms"
xmlns:viewmodel="clr-namespace:Timetabler.ViewModels"
mc:Ignorable="d"
Title="Binding Title"
x:Class="Timetabler.Views.TimetablePage">
<ContentPage.BindingContext>
<viewmodel:TimetableViewModel/>
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add Course" Clicked="AddItem_Clicked" />
</ContentPage.ToolbarItems>
<schedule:SfSchedule x:Name="schedule"
ScheduleView ="WorkWeekView"
TimeIntervalHeight="130"
ShowCurrentTimeIndicator="True"
DataSource="Binding Courses">
<schedule:SfSchedule.ViewHeaderStyle>
<schedule:ViewHeaderStyle
BackgroundColor="#FFFFFF"
CurrentDayTextColor="#d1d119"
CurrentDateTextColor="#d1d119"
DayTextColor="#44453e"
DateTextColor="#44453e"
DayFontFamily="Arial"
DateFontFamily="Arial">
</schedule:ViewHeaderStyle>
</schedule:SfSchedule.ViewHeaderStyle>
</schedule:SfSchedule>
如您所见,我正在尝试绑定到我的 ViewModel 中的 Courses 属性。难道我做错了什么?我添加了 ContentPage。 BindingContext 作为正确的 ViewModel。我如何能够从其中访问单个值?
【问题讨论】:
【参考方案1】:据我所知,绑定没问题,但您使用的是自定义对象。你不能指望SfScheduler
知道数据需要来自哪些字段。
正如here 所记录的那样,您需要告诉它要在对象中查找哪些字段以确定开始和结束日期和时间等属性。即
<syncfusion:SfSchedule x:Name="schedule">
<syncfusion:SfSchedule.AppointmentMapping>
<syncfusion:ScheduleAppointmentMapping
ColorMapping="color"
EndTimeMapping="To"
StartTimeMapping="From"
SubjectMapping="EventName"
IsAllDayMapping="AllDay"/>
</syncfusion:SfSchedule.AppointmentMapping>
</syncfusion:SfSchedule>
查看您的TimetableElement
对象,您需要在其中添加更多属性,因为我很确定StartTimeMapping
和EndTimeMapping
期望DateTime
。但我可能错了。
希望这能让你走上正确的道路。
【讨论】:
我尝试在我的 xaml 中实现一个条目,用户可以在自定义会议中键入该条目。但即使这样也不行??如何将输入到条目中的文本与 ViewModel 的逻辑绑定?Entry
是另一回事。如果你想在你的支持属性中捕获它的值,你需要将BindingMode=TwoWay
设置为它以上是关于我在 Xamarin.forms 中遇到数据绑定问题的主要内容,如果未能解决你的问题,请参考以下文章
将方法从后面的代码转换为 ICommand 数据绑定 Xamarin.Forms
从绑定 ListView Xamarin Forms 中检索 firebase 数据
Xamarin Forms 中数据模板视图单元格内的绑定上下文