如何使用 MVVM (Xamarin) 将数据从集合视图中的选取器发送到 API 端点
How to send data from a picker IN a collectionview to an API endpoint using MVVM (Xamarin)
对于我当前的项目,我正在开发跨平台应用程序。我们正在使用 Visual studio、跨平台应用程序构建它。
在这个项目中,我们使用我们在 SQL 数据库中设置的调查问卷。
使用 MVVM 我 可以 将其动态加载到移动应用程序中。 (我们这样做是因为有很多展示这个的平台,所以我们选择设置在后台,每道题都有答案的问卷)。
但是保存似乎有问题,
我似乎无法将数据发送回我的后端
-> 我想将选择器显示的值或字符串发送回后端(最好使用 MVVM)。如果我可以在视图模型中获取数据(如果 MVVM 不可能,则可以获取代码),我的问题会得到足够的帮助。
我使用 collectionview 构建我的问卷,其中包含一个带有选择器的 DataTemplate。
QuestionaireView.xaml:
<ContentPage.BindingContext>
<viewModels:Questionaire_viewmodel/>
</ContentPage.BindingContext>
<CollectionView
x:Name="CollectionQuestionsView"
SelectionMode="None"
Margin="0,0,0,0" RemainingItemsThreshold="5"
BackgroundColor="Transparent"
SelectedItems="{Binding selectedPickers}"
ItemsSource="{Binding Questionaire.Vraag,Mode=TwoWay}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Style="{StaticResource RegularLabelStyleSmallLogin}" Text="{Binding vraagstelling}" HorizontalTextAlignment="Start" VerticalTextAlignment="Start" LineBreakMode="WordWrap"/>
<Picker Style="{StaticResource PickRegularSmall}" SelectedItem="{Binding vraag_id}" x:Name="{Binding vraag_id}" ItemsSource="{Binding Antwoorden}" ItemDisplayBinding="{Binding antwoord_vraagstelling}"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Frame Margin="0,0,0,20" Style="{StaticResource OrangeLoginFrame}">
<Grid Margin="-15" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Style="{StaticResource SemiBoldLabelStyleMedium}" Grid.Row="0" Grid.Column="0" Text="Opslaan"/>
<Button Style="{StaticResource LoginButton}" Command="{Binding SaveVragenlijstCompetentiesCommand}" Grid.Row="0" Grid.Column="0" />
</Grid>
</Frame>
<Button x:Name="questionaireButton" Command="{Binding getQuestionaireLoopbaancompetenties}" IsVisible="False"/>
所以解释一下绑定(因为有些名字不是英文的):
- collectionview 的项目源:questionaire.vraag 从问卷对象中检索问题集合(请参阅下面的 model.cs)
- 标签文本绑定:显示问题
- picker selectedItem 绑定:vraag id 生成一个字符串(从后端检索),这里具体为 vraag_127、vraag_128(数字是问题的 id)
- itemsource picker: binding antwoorden, 这些是问题的答案
- 在集合视图下方的框架中,我制作了一个按钮(至少我尝试过)将数据发送到 ViewModel.cs
- 框架下方的(隐藏)按钮加载数据(我在后面的代码中执行它,不确定这是不是最好的选择)
问卷ViewModel.cs
public string vraag_127 { get; set; }
public string vraag_128 { get; set; }
... and so on
public string vraag_161 { get; set; }
public string categorie_vraag { get; set; }
public string SelectedAnswer { get; set; }
public string vraagstelling { get; set; }
public string vraag_id { get; set; }
public string score_antwoord { get; set; }
public string antwoord_vraagstelling { get; set; }
public string default_question { get; set; }
public string description { get; set; }
private Questionaire_model _questionaire;
public Questionaire_model Questionaire
{
get { return _questionaire; }
set
{
_questionaire = value;
OnPropertyChanged();
}
}
private List<Questionaire_model> _vraag;
public List<Questionaire_model> Vraag
{
get { return _vraag; }
set
{
_vraag = value;
OnPropertyChanged();
}
}
private List<Questionaire_model> _antwoorden;
public List<Questionaire_model> Antwoorden
{
get { return _antwoorden; }
set
{
_antwoorden = value;
OnPropertyChanged();
}
}
public ICommand getQuestionaireLoopbaancompetenties
{
get
{
return new Command(async (boolean) =>
{
Questionaire = await _apiServices.GetQuestionaireQuestions("Competenties");
});
}
}
private ObservableCollection<vragenModel> _selectedPicker;
public ObservableCollection<vragenModel> SelectedPicker
{
get
{
return _selectedPicker;
}
set
{
_selectedPicker = value;
OnPropertyChanged();
}
}
public ICommand SaveVragenlijstCompetentiesCommand
{
get
{
return new Command(async () =>
{
var responseBool = await _apiServices.SaveCultuur(vraag_127,vraag_128, ... vraag_161)});
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
还有我的QuestionaireModel.cs:
public class Questionaire_model
{
public int id { get; set; }
public string default_question { get; set; }
public string description { get; set; }
public IList<Vragen> Vraag{ get; set; }
public class Vragen
{
public string categorie_vraag { get; set; }
public string SelectedAnswer { get; set; }
public string vraagstelling { get; set; }
public string vraag_id { get; set; }
public IList<antwoorden> Antwoorden { get; set; }
}
public class antwoorden
{
public string score_antwoord { get; set; }
public string antwoord_vraagstelling { get; set; }
}
}
我们使用 collectionView 的原因是因为我们将模板用于具有各种问题和答案可能性的各种调查问卷。
所以此刻,当我执行我的保存操作时,它在我的 ViewModel - 操作中给出了“null”
我在 viewmodel
上方定义了 public class Questionaire_viewmodel : INotifyPropertyChanged
所以我希望有人可以帮助我处理我的代码,我在这里遗漏了一些东西
或者如果我必须改变一些东西,因为它根本不可能,那么我想知道去哪里。
据我了解,您希望 Picker.SelectedItem
实际上绑定到 QuestionaireViewModel.vrag_xxx
属性。这不会像这样工作 - 现在发生的是你的 Picker.SelectedItem
绑定到 Vragen.vraag_id
字段并且无法使用它,只要它期望在那里输入 antwoorden
即可。
但是,我看到您在 Vragen
中有 SelectedAnswer
属性,您可以将其更改为 antwoorden
类型,然后从该字段中获取用户选择.
因此,如果您的 Vragen
class 是:
public class Vragen
{
public string categorie_vraag { get; set; }
public antwoorden SelectedAnswer { get; set; }
public string vraagstelling { get; set; }
public string vraag_id { get; set; }
public IList<antwoorden> Antwoorden { get; set; }
}
然后,您可以将 Picker
的绑定更改为:
<Picker Style="{StaticResource PickRegularSmall}" SelectedItem="{Binding SelectedAnswer}" x:Name="{Binding vraag_id}" ItemsSource="{Binding Antwoorden}" ItemDisplayBinding="{Binding antwoord_vraagstelling}"/>
并且,最后在 SaveVragenlijstCompetentiesCommand
中,您将能够获得一系列答案(按问题 ID 排序):
Questionaire.Vraag.OrderBy(x => x.vraag_id).Select(x => x.SelectedAnswer.antwoord_vraagstelling)
这将为您提供一系列答案文本。它仍然不符合您的 apiServices.SaveCultuur
要求。我强烈建议更改该方法 - 包含大量参数的方法肯定是个问题。
如果你能把它改成接受string[]
,那么你就能把Questionaire.Vraag.OrderBy(x => x.vraag_id).Select(x => x.SelectedAnswer.antwoord_vraagstelling)
传给它。
如果不能改变apiServices
,也可以通过数组反射调用方法,但有点棘手。
对于我当前的项目,我正在开发跨平台应用程序。我们正在使用 Visual studio、跨平台应用程序构建它。 在这个项目中,我们使用我们在 SQL 数据库中设置的调查问卷。
使用 MVVM 我 可以 将其动态加载到移动应用程序中。 (我们这样做是因为有很多展示这个的平台,所以我们选择设置在后台,每道题都有答案的问卷)。
但是保存似乎有问题, 我似乎无法将数据发送回我的后端 -> 我想将选择器显示的值或字符串发送回后端(最好使用 MVVM)。如果我可以在视图模型中获取数据(如果 MVVM 不可能,则可以获取代码),我的问题会得到足够的帮助。
我使用 collectionview 构建我的问卷,其中包含一个带有选择器的 DataTemplate。
QuestionaireView.xaml:
<ContentPage.BindingContext>
<viewModels:Questionaire_viewmodel/>
</ContentPage.BindingContext>
<CollectionView
x:Name="CollectionQuestionsView"
SelectionMode="None"
Margin="0,0,0,0" RemainingItemsThreshold="5"
BackgroundColor="Transparent"
SelectedItems="{Binding selectedPickers}"
ItemsSource="{Binding Questionaire.Vraag,Mode=TwoWay}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Style="{StaticResource RegularLabelStyleSmallLogin}" Text="{Binding vraagstelling}" HorizontalTextAlignment="Start" VerticalTextAlignment="Start" LineBreakMode="WordWrap"/>
<Picker Style="{StaticResource PickRegularSmall}" SelectedItem="{Binding vraag_id}" x:Name="{Binding vraag_id}" ItemsSource="{Binding Antwoorden}" ItemDisplayBinding="{Binding antwoord_vraagstelling}"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Frame Margin="0,0,0,20" Style="{StaticResource OrangeLoginFrame}">
<Grid Margin="-15" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Style="{StaticResource SemiBoldLabelStyleMedium}" Grid.Row="0" Grid.Column="0" Text="Opslaan"/>
<Button Style="{StaticResource LoginButton}" Command="{Binding SaveVragenlijstCompetentiesCommand}" Grid.Row="0" Grid.Column="0" />
</Grid>
</Frame>
<Button x:Name="questionaireButton" Command="{Binding getQuestionaireLoopbaancompetenties}" IsVisible="False"/>
所以解释一下绑定(因为有些名字不是英文的):
- collectionview 的项目源:questionaire.vraag 从问卷对象中检索问题集合(请参阅下面的 model.cs)
- 标签文本绑定:显示问题
- picker selectedItem 绑定:vraag id 生成一个字符串(从后端检索),这里具体为 vraag_127、vraag_128(数字是问题的 id)
- itemsource picker: binding antwoorden, 这些是问题的答案
- 在集合视图下方的框架中,我制作了一个按钮(至少我尝试过)将数据发送到 ViewModel.cs
- 框架下方的(隐藏)按钮加载数据(我在后面的代码中执行它,不确定这是不是最好的选择)
问卷ViewModel.cs
public string vraag_127 { get; set; }
public string vraag_128 { get; set; }
... and so on
public string vraag_161 { get; set; }
public string categorie_vraag { get; set; }
public string SelectedAnswer { get; set; }
public string vraagstelling { get; set; }
public string vraag_id { get; set; }
public string score_antwoord { get; set; }
public string antwoord_vraagstelling { get; set; }
public string default_question { get; set; }
public string description { get; set; }
private Questionaire_model _questionaire;
public Questionaire_model Questionaire
{
get { return _questionaire; }
set
{
_questionaire = value;
OnPropertyChanged();
}
}
private List<Questionaire_model> _vraag;
public List<Questionaire_model> Vraag
{
get { return _vraag; }
set
{
_vraag = value;
OnPropertyChanged();
}
}
private List<Questionaire_model> _antwoorden;
public List<Questionaire_model> Antwoorden
{
get { return _antwoorden; }
set
{
_antwoorden = value;
OnPropertyChanged();
}
}
public ICommand getQuestionaireLoopbaancompetenties
{
get
{
return new Command(async (boolean) =>
{
Questionaire = await _apiServices.GetQuestionaireQuestions("Competenties");
});
}
}
private ObservableCollection<vragenModel> _selectedPicker;
public ObservableCollection<vragenModel> SelectedPicker
{
get
{
return _selectedPicker;
}
set
{
_selectedPicker = value;
OnPropertyChanged();
}
}
public ICommand SaveVragenlijstCompetentiesCommand
{
get
{
return new Command(async () =>
{
var responseBool = await _apiServices.SaveCultuur(vraag_127,vraag_128, ... vraag_161)});
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
还有我的QuestionaireModel.cs:
public class Questionaire_model
{
public int id { get; set; }
public string default_question { get; set; }
public string description { get; set; }
public IList<Vragen> Vraag{ get; set; }
public class Vragen
{
public string categorie_vraag { get; set; }
public string SelectedAnswer { get; set; }
public string vraagstelling { get; set; }
public string vraag_id { get; set; }
public IList<antwoorden> Antwoorden { get; set; }
}
public class antwoorden
{
public string score_antwoord { get; set; }
public string antwoord_vraagstelling { get; set; }
}
}
我们使用 collectionView 的原因是因为我们将模板用于具有各种问题和答案可能性的各种调查问卷。
所以此刻,当我执行我的保存操作时,它在我的 ViewModel - 操作中给出了“null” 我在 viewmodel
上方定义了public class Questionaire_viewmodel : INotifyPropertyChanged
所以我希望有人可以帮助我处理我的代码,我在这里遗漏了一些东西 或者如果我必须改变一些东西,因为它根本不可能,那么我想知道去哪里。
据我了解,您希望 Picker.SelectedItem
实际上绑定到 QuestionaireViewModel.vrag_xxx
属性。这不会像这样工作 - 现在发生的是你的 Picker.SelectedItem
绑定到 Vragen.vraag_id
字段并且无法使用它,只要它期望在那里输入 antwoorden
即可。
但是,我看到您在 Vragen
中有 SelectedAnswer
属性,您可以将其更改为 antwoorden
类型,然后从该字段中获取用户选择.
因此,如果您的 Vragen
class 是:
public class Vragen
{
public string categorie_vraag { get; set; }
public antwoorden SelectedAnswer { get; set; }
public string vraagstelling { get; set; }
public string vraag_id { get; set; }
public IList<antwoorden> Antwoorden { get; set; }
}
然后,您可以将 Picker
的绑定更改为:
<Picker Style="{StaticResource PickRegularSmall}" SelectedItem="{Binding SelectedAnswer}" x:Name="{Binding vraag_id}" ItemsSource="{Binding Antwoorden}" ItemDisplayBinding="{Binding antwoord_vraagstelling}"/>
并且,最后在 SaveVragenlijstCompetentiesCommand
中,您将能够获得一系列答案(按问题 ID 排序):
Questionaire.Vraag.OrderBy(x => x.vraag_id).Select(x => x.SelectedAnswer.antwoord_vraagstelling)
这将为您提供一系列答案文本。它仍然不符合您的 apiServices.SaveCultuur
要求。我强烈建议更改该方法 - 包含大量参数的方法肯定是个问题。
如果你能把它改成接受string[]
,那么你就能把Questionaire.Vraag.OrderBy(x => x.vraag_id).Select(x => x.SelectedAnswer.antwoord_vraagstelling)
传给它。
如果不能改变apiServices
,也可以通过数组反射调用方法,但有点棘手。