Вам очень повезло, потому что совсем недавно я реализовал очень похожую вещь:
private FormQuestion formModel {get;set;}
public Form()
{
InitializeComponent();
//Hook up events, set layout of main Stack
CreateViews(formModel);
mainStack.Orientation = StackOrientation.Vertical;
mainStack.VerticalOptions = LayoutOptions.FillAndExpand;
mainStack.HorizontalOptions = LayoutOptions.FillAndExpand;
}
#endregion
/// <summary>
/// Method that returns Stack layout that contains control required for filling up the form if QuestionType is Text.
/// This method creates StackLayout, Label and Entry then returns it.
/// </summary>
/// <param name="formQuestions"></param>
/// <returns></returns>
private StackLayout CreateQuestionStackText(FormQuestion formQuestions)
{
StackLayout stack = new StackLayout
{
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.FillAndExpand
};
Label label = new Label
{
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.CenterAndExpand
};
label.SetBinding(Label.TextProperty, "Text");
Entry entry = new Entry
{
HorizontalOptions = LayoutOptions.EndAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand,
WidthRequest = 200
};
entry.SetBinding(Entry.TextProperty, "Value");
stack.Children.Add(label);
stack.Children.Add(entry);
return stack;
}
/// <summary>
/// Method that returns Stack layout that contains control required for filling up the form if QuestionType is Number.
/// This method creates StackLayout, Label and Entry that enforces Numerical Keyboard then returns it.
/// </summary>
/// <param name="formQuestions"></param>
/// <returns></returns>
private StackLayout CreateQuestionStackNumber(FormQuestion formQuestions)
{
StackLayout stack = new StackLayout
{
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.FillAndExpand
};
Label label = new Label
{
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.CenterAndExpand
};
label.SetBinding(Label.TextProperty, "Text");
Entry entry = new Entry
{
HorizontalOptions = LayoutOptions.EndAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand,
Keyboard = Keyboard.Numeric,
WidthRequest = 200
};
entry.SetBinding(Entry.TextProperty, "Value");
stack.Children.Add(label);
stack.Children.Add(entry);
return stack;
}
/// <summary>
/// Method that returns Stack layout that contains control required for filling up the form if QuestionType is DropDown
/// This method creates StackLayout, Label and BindablePicker, which is custom Picker I've created to be able to get work with MVVM, then returns it.
/// </summary>
/// <param name="formQuestions"></param>
/// <returns></returns>
private StackLayout CreateQuestionStackDropDown(FormQuestion formQuestions)
{
StackLayout stack = new StackLayout
{
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.FillAndExpand
};
Label label = new Label
{
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.CenterAndExpand
};
label.SetBinding(Label.TextProperty, "Text");
BindablePicker picker = new BindablePicker();
picker.HorizontalOptions = LayoutOptions.EndAndExpand;
picker.BindingContext = this;
var bind = this.BindingContext;
var strings = formQuestions.DataSource.Values;
var listOfStrings = strings.Split(';');
List<string> result = new List<string>();
foreach (var item in listOfStrings)
{
result.Add(item);
}
picker.ItemsSource = result;
picker.SelectedIndexChanged += Picker_SelectedIndexChanged;
//picker.SetBinding(BindablePicker.DisplayMemberPathProperty, new Binding( "Values", BindingMode.TwoWay, new ValuesToListOfStringsConverter(), null));
picker.SetBinding(BindablePicker.SelectedItemProperty, "Value");
picker.WidthRequest = 200;
stack.Children.Add(label);
stack.Children.Add(picker);
return stack;
}
/// <summary>
/// Method that returns Stack layout that contains control required for filling up the form if QuestionType is Data
/// This method creates StackLayout, Label and DataPicker and returns it.
/// </summary>
/// <param name="formQuestions"></param>
/// <returns></returns>
private StackLayout CreateQuestionStackDate(FormQuestion formQuestions)
{
StackLayout stack = new StackLayout
{
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.FillAndExpand
};
Label label = new Label
{
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.CenterAndExpand
};
label.SetBinding(Label.TextProperty, "Text");
DatePicker datePicker = new DatePicker();
datePicker.HorizontalOptions = LayoutOptions.EndAndExpand;
datePicker.SetBinding(DatePicker.DateProperty, "Value");
stack.Children.Add(label);
stack.Children.Add(datePicker);
return stack;
}
/// <summary>
/// Little hack, that unfortunately I had to implement. Because DropDown contains list of DataSource Properties that is essentially array of objects, I had to work around with pulling data of selected item and only
/// get Values property value. This couldnt be bound correctly, because Values are expecting to be string, but SelectedItem property of picker is an actuall full Object of DataSource.
/// I Could probably work around it by Implementing Converter, but Converter will have more code, and I couldnt be bothered.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Picker_SelectedIndexChanged(object sender, EventArgs e)
{
//Cast sender object to BindablePicker (since sender is BindablePicker)
var picker = (BindablePicker)sender;
///Get SelectedItem Value and cast it to DataSource (since SelectedItem is DataSource)
var value = (string)picker.SelectedItem;
// Assign Values value back to My Collection
((FormQuestion)BindingContext).Value = value;
}
/// <summary>
/// Determine which stack should be created, depending on QuestionType
/// </summary>
/// <param name="formModel"></param>
private void CreateViews(FormQuestion formModel)
{
StackLayout newStack = new StackLayout();
switch (formModel.QuestionType.Name)
{
case "text":
newStack.Children.Add(CreateQuestionStackText(formModel));
break;
case "number":
newStack.Children.Add(CreateQuestionStackNumber(formModel));
break;
case "dropDown":
newStack.Children.Add(CreateQuestionStackDropDown(formModel));
break;
case "date":
newStack.Children.Add(CreateQuestionStackDate(formModel));
break;
default:
newStack.Children.Add(CreateQuestionStackText(formModel));
break;
}
this.mainStack.Children.Add(newStack);
}
#endregion
public class FormQuestion
{
public int FormQuestionId { get; set; }
public string Text { get; set; }
public string Value { get; set; }
public int QuestionTypeId { get; set; }
public virtual QuestionType QuestionType { get; set; }
public int FormId { get; set; }
public Form Form { get; set; }
public DataSource DataSource { get; set; }
}
public class QuestionType
{
public int QuestionTypeId { get; set; }
public string Name { get; set; }
}
Это будет ваш Xaml.
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Frame BorderColor="Gray" CornerRadius="2" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" >
<StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" x:Name="mainStack">
</StackLayout>
</Frame>
</StackLayout>
Вам нужно будет немного изменить, чтобы соответствовать ваша цель, но я предоставил вам мою реализацию, так что у вас есть базовые знания и понимание того, что вы должны делать. Также имейте в виду, что это было сделано для использования MVVM. Я также вычеркнул некоторые методы, которые не имеют отношения к делу. BindablePicker является расширенной версией средства выбора, поскольку стандартный инструмент выбора форм Xamarin не имеет привязываемых свойств. Основная цель моего кода состояла в том, чтобы динамически создавать различные типы записей, средств выбора, даты и т. Д. c в зависимости от типа формы, получаемого из серверной части, и связывать их с ViewModel внутри ListView.