Global markup extensions in Xamarin Forms - xaml

Is it possible to create a global reference for a markup extension in Xamarin Forms?
I'm using a markup extension to provide localization, and would like to register the namespace once, rather than in every view.
For example, here is a simple page:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Views.Home"
xmlns:i18n="clr-namespace:App.Globalization">
<ContentPage.Content>
<StackLayout HorizontalOptions="Fill" VerticalOptions="Center">
<Label Text="{i18n:Translate Welcome}"
HorizontalOptions="Center"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
What I want to do is not require every page to include the xmlns:i18n namespace, but include it globally.

Short answer: No. It's not possible, unless you switch your xmlns definitions. And also please note this is a XML limitation, not just XAML.
How this works:
The only way to do this is through use of XmlnsDefinitionAttribute. XAML parsers (both compile-time, and run-time) look for these attributes on assemblies to glean the default global namespace declarations much like following line in AssemblyInfo in Xamarin.Forms.Core.
[assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms", "Xamarin.Forms")]
You can find some of these parsing methods here.
The above line coupled with this attribute
xmlns="http://xamarin.com/schemas/2014/forms"
that is included by default in your custom XAML pages/views, allow you to directly use controls like ContentPage, StackLayout, Grid etc. without having to specify the Xamarin.Forms namespace
Now, you can see both XmlnsDefinitionAttribute, and XmlTypeExtensions are marked as internal. So there is no easy way to get around it.
What you can try is switching your xmlns namespace definitions as following (please note I am sharing this just for illustration purpose only). This will allow you to not have to specify prefix for TranslateExtension.
<f:ContentPage xmlns="clr-namespace:App.Globalization"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:SampleApp"
xmlns:f="http://xamarin.com/schemas/2014/forms"
x:Class="SampleApp.MainPage">
<f:ContentPage.Content>
<f:StackLayout HorizontalOptions="Fill" VerticalOptions="Center">
<f:Label Text="{Translate Welcome}"
HorizontalOptions="Center"/>
</f:StackLayout>
</f:ContentPage.Content>
</f:ContentPage>

No. The same applies for C# code - can you declare using of some namespace globally? Of course not.

Related

.NET MAUI Communitytoolkit.Mvvm: How to bind an object instead of a string

i already the project from the official tutorial of .NET MAUI until step 5 using Communitytoolkit.Mvvm:
text
Now, instead of binding only a Text (which is a standard type that can be accessed from everywhere) i would like to bind a simple object (called ItemGroup) with two members (bool isChecked and string name).
How to do that?
For a global access i made this class in the MainView folder called ItemGroup. This class is not accessable and i don't know how to do that it is.
I changed the code in the MainPage.xaml like this:
<CollectionView ItemsSource="{Binding Items}"
Grid.Row="1">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="{x:Type x:ViewModel.ItemGroup}">
<Grid >
<CheckBox IsChecked="{Binding ItemGroup.IsChecked}" Grid.Column="0"/>
<Label Text="{Binding ItemGroup.name}" Padding="10" Grid.Column="1"
BackgroundColor="LightGray"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
See also the project structure with the ItemGroup class in the ViewModel folder as well as the error message:
where the content page is declared as this:
Remark: The MainViewModel looks like this:
Should i declare some uses, or namespace?
where in the project should i place the Class of the objects i would bind?
Thanks in advance, Thomas
Also tryed to implement the class ItemGroup in the MainViewModel.cs but then i had any more problems with access to this class.
Try this
<Label Text="{Binding name}" …
Note that name must be a public property
You have a number of issues here.
The community mvvm toolkit includes code generators.
A variable:
[ObservableProperty]
string text;
Is examined by the code generator at compile time and in a partial class it will add a public property Text.
Binding is case sensitive and you need to bind to public properties so you need to use upper case on that first letter. Binding Text rather than Binding text.
You might have other instances where you did the same sort of thing.
I don't see where you use it but that add [Relaycommand] will generate AddCommand as a public property which you bind to.
Additionally you have misunderstood how an itemscontrol gets an item out a bound collection per row. As DevenCC points out, once you bind ItemsSource to Items then each row will get an instance of whatever is in that collection so you should bind IsChecked rather than ParentProperty.IsChecked.
As to where to put classes. In large apps it is a nuisance to flip between a folder contains views and another contains viewmodels. You might want to consider a folder contains each pair of view and viewmodel. Hence a foo folder containing fooView and fooViewModel
I believe your problem lies with you Binding declaration inside you ItemTemplate. Given that you bound your CollectionView's ItemSource to "items", the ItemTemplate's data context is now a single itemGroup from your list. Therefore, you should not be writing
<CheckBox IsChecked="{Binding ItemGroup.IsChecked}"[...]
But instead
<CheckBox IsChecked="{Binding isChecked}"[...]
Since you are already "within" a single itemgroup object. Same goes for your Label. Furthermore, I don't think you actually need to declare the Datatype for your item's DataTemplate.
p.s. Watch out for your item declaration, it seems like you have both items and Items declared in your ViewModel; and both seem public.

Can we define resource for xamarin forms control template elsewhere other than app.xaml

I am trying to build pages with a base template. I've used control template in app.xaml and it works great.
Here is what I have done
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App3.App">
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="baseTemplate">
But can I define this control template resource anywhere other than app.xaml because the app.xaml is getting cramped. Can I have separate folder for templating. How can I achieve this?
Any guide or tutorial will also help.
You can define a ResourceDictionary in any XAML file. See the Xamarin documentation here:
There's also a good Xamarin University class on this:
https://university.xamarin.com/classes/track/xamarin-forms#xam140-resources-and-styles
If you're new to Xamarin, I suggest you hit Xamarin University. The self-guided courses are free.

How to set Page Wide BindingContext in a XAML Page Header

What is the correct syntax for setting the bindingContext of a XAML page, in it's header (Where the namespaces and x:class is defined)?
I know it can be set by
<ContentView.ContextBinding>
<vm:RedViewModel/>
</ContentView.ContextBinding>
but something like the following For Example, would look neater
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView x:Class="MVVMFramework.VVMs.Red.RedView"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:MVVMFramework.VVMs.Red"
BackgroundColor="Red"
BindingContext="{Binding Source = {vm:RedViewModel}}"> //Something like this
There used to be a bug with the second approach that lead to create the ViewModel twice, not sure if it is there anymore, you could easily check it.
Beside that, there is no silver bullet solution that will work for all cases. What if you have to pass some data to ViewModel constructor? That will be tricky with XAML. Most probably it will make sense to have an IOC container in place, to inject those properties to the ViewModel, so any how it will happen in code and not in XAML.
I would say evaluate yourself what is suitable for your solution and stick to it, so it will be consistent.
P.S.: I am not saying that you should not do it in XAML, do it if it make sense in you specific case.

Default XAML page and New XAML page in Xamarin Forms is not identical

I am new to Xamarin development. I created new Xamarin XAML App(Xamarin.Forms Portable). In Portable Project there where MainPage.Xaml by default. To create MVVM Model I created three new Folders- Views, ViewModels, and Models. Now I added new MainPage.Xaml in Views folder and was going to delete the default MainPage.Xaml page. But here I see some difference in both pages. The default MainPage.Xaml have xmlns:local="clr-namespace:Test" but the new MainPage.Xaml does not. Again the new MainPage.Xaml have <Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" /> but the default one does not. The screenshots are:
What does these MarkUp mean.Why there is a difference. Does something needs to be changed. Can I delete the default MainPage.Xaml or should i copy it in Views.Does I need to copy the Markup from the default Page to the new one. If so why?
Thanks in advance
Both pages are identical, and will display in the same way.
On the second, there's an additional Xml namespace declaration:
xmlns:local="clr-namespace:Test"
It's only a declaration. You could remove it, or add it to the other page without effect. It's purpose is to be able to reference custom views declared in the current assembly and in the namespace (c# namespace, this time) Test, like this:
<ContentPage
...
xmlns:local="clr-namespace:Test"
x:Class="Test.MainPage">
<local:MyAwesomeView />
</ContentPage>
Awesome that you have decided to start with Xamarin and Xamarin.Forms!
While I understand you might be having these questions, this is some very basic XAML knowledge. The short answer is: you don't need to worry about it.
The long answer:
The reason that there is a difference in these pages is simply because it's just a template and whoever at Xamarin created the template for the project can be a different person than who created the template for a new XAML page. So they solved it different ways. Or maybe he had a good/bad day, who knows.
The Label in the first page is simply there to show you how to get started and so you won't start with an empty screen.
The extra namespace xmlns:local="clr-namespace:Test" is actually redundant in this new page but is already there so you can use the classes in your project.
It is actually the equivalent of the using list at the top of your classes. So whenever you need something from a different namespace you have to declare it there. So if you create a folder 'Controls' you can add a attribute xmlns:controls="clr-namespace:Test.Controls".
Note how I changed local to controls, this is the prefix you will use to define your instance. Also I have added the right namespace Test.Controls. Now if you want te show something on screen, in your XAML from the controls namespace, go like this:
<ContentPage xmlns:controls="clr-namespace:Test.Controls" x:Class="Test.MainPage">
<!-- some stuff here -->
<controls:ReusableControlHere />
</ContentPage>
Where ReusableControl can be your own version of a Label, Button or virtually anything.

Xamarin Forms Picker Item source binding in Xaml

I need to create states picker in my Xamarin Forms. I am using Xaml file for creating views.
Can any one help me to bind Picker in Xaml with item source?
The XLabs has an excellent example of a bindable picker that I have used in several projects to great affect:
https://github.com/XLabs/Xamarin-Forms-Labs
This will allow you to replicate the 'ItemsSource' functionality of the Listview.
You won't be able to do this in XAML, as you can see here.
You'll have to load the data up in the code behind, using either their regular API, or something like this.
You can also serialize your list as a JSON or preferred format, and deserialize that and pass it to the Picker.
This functionality did not previous exist, but it was recently added to the regular Xamarin.Forms Picker via the new ItemsSource and SelectedItem properties. It is currently in the pre-release NuGet package for version 2.3.4-pre1, but should be in the stable 2.3.4+ versions once it is released.
As JordanMazurke commented, XLabs has it.
Here is an example:
<ContentPage x:Class="XLabs.Samples.Pages.Controls.ExtendedPickerPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:XLabs.Forms.Controls;assembly=XLabs.Forms"
Title="Picker">
<ContentPage.Content>
<StackLayout x:Name="myStackLayout">
<Label Text="Xaml:" />
<controls:ExtendedPicker x:Name="myPicker"
DisplayProperty="FirstName"
ItemsSource="{Binding MyDataList}"
SelectedItem="{Binding TheChosenOne}" />
</StackLayout>
</ContentPage.Content>