This is a very broad topic. You can actually always dynamically create controls in code behind, by just adding them to the UI during runtime. This is very easy, but it’s not generic at all, you need to code everything you would actually do in Xaml.
Another solution (which I actually prefer) is to use a ListLayout (maybe a Bindable StackLayout) and use a TemplateSelector to switch between pre defined DataTemplates based on the ViewModel, that is being used. But this will actually not give you more flexibility, but it’s definitely a better solution than the first shot.
We actually want something really flexible, we try to achieve instanciating an unknown Xaml from whatever source we have (Text, Internet, UserInput,.. ), and even provide binding to further use the UserInput in ViewModel. So there are 2 parts to this:
1. load xaml during runtime,
2. somehow achieve binding.
When you have a look in your obj-folder of a compiled Xamarin app, you will find a file called something like “MainPage.xaml.g.cs”
[global::Xamarin.Forms.Xaml.XamlFilePathAttribute("MainPage.xaml")] public partial class MainPage : global::Xamarin.Forms.ContentPage { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "2.0.0.0")] private void InitializeComponent() { global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(MainPage)); } }
There is another overload of the global extension function Xamarin.Forms.Xaml.Extensions.LoadFromXaml(..) which takes a string representation of your xaml to create a control.
We can use this, to create a ContentControl with a BindableProperty, which creates the given Xaml at runtime.
public class XamlView : ContentView { public static readonly BindableProperty XamlProperty = BindableProperty.Create(nameof(Xaml), typeof(string), typeof(XamlView), propertyChanged: OnXamlChanged); private static void OnXamlChanged(BindableObject bindable, object oldValue, object newValue) { try { var xamlView = (XamlView)bindable; ContentView view = new ContentView(); // we add the default xaml namespace to our surrounding ContentView, // so it doesn't need to be defined in xaml view = view.LoadFromXaml("" + (xamlView.Xaml ?? string.Empty) + ""); xamlView.Content = view; } catch (Exception ex) { // we should actually handle that exception, maybe put it on the screen as label } } public string Xaml { get => (string)GetValue(XamlProperty); set => SetValue(XamlProperty, value); } }
usage:
<Grid BackgroundColor="Red"> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Entry x:Name="XamlEditor" Text="{Binding ContentXaml}" /> <dynamiccontrol:XamlView Grid.Row="1" Xaml="{Binding ContentXaml}" /> </Grid>
You could also bind the XamlView.Xaml directly to an Entry.Text using ReferenceBinding, but I prefer using a ViewModel instead.
And this is how it looks like:
In my next post, I will talk about binding the Data from the XamlView to a ViewModel.
1 Comment on “Dynamically create controls in Xamarin Forms”