How to set Page Wide BindingContext in a XAML Page Header - xaml

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.

Related

Global markup extensions in Xamarin Forms

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.

UWP xaml logic:

can someone explain to me what this code in a App.xaml does, especially the logic:AppDataModel part. AppDataModel is Class in the Project.
<Application.Resources>
<logic:AppDataModel
x:Key="TheViewModel" />
<x:String
x:Key="AppName">Master app</x:String>
</Application.Resources>
This markup, when parsed, creates two entries in the Application.Resources dictionary. They key "TheViewModel" is tied to a new instance of AppDataModel and the key "AppName" is tied to a string initialized to "Mater app".
To go beyond your question, the reason you do this in XAML is to co-locate (keep together) your UI code and some instance data, loosely speaking. The biggest example is wanting your UI to always have a particular view model that it binds to. This can be achieved, as I assume from the markup you posted, like you're doing. Creating a view model object in the resources for a given control, window, or app and then assigning it using {StaticResource TheViewModel} will keep you from having to muddy up your code-behind or your view model with binding code.
Hope this helps!
These xaml lines add items to the Resources dictionary of the current application:
Application.Current.Resources["TheViewModel"] = new logic.AppDataModel();
Application.Current.Resources["AppName"] = "Master app";

UWP MVVM XAML Dynamic UserControl Manager

I need help with a change of perspective.
I got stuck trying to approach UWP in a way I used to do in WPF regarding a MVVM pattern for managing UserControls dynamically.
I naturally tried to perform the same pattern in UWP but got stuck on various things like UWP not supporting 'x:Type' ...
Situation is; time to rethink this approach and look for a new direction. Seems I'm forced to abandon to use implicit binding in a similar fashion to the WPF pattern, using the Content property of a ContentPresenter and a VM property 'of type Object', which maintain a selected ViewModel. It was a simple and clean approach for matching up the correct View automagically with the VM set in ActiveViewModel.
the below was such a simple way of managing many views all over the place, odd MS not fixing this? But, back to the big Q: what now in UWP!?
<ContentPresenter Content="{Binding ActiveViewModel}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:OneViewModel}">
<local:OneView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:TwoViewModel}">
<local:TwoView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
What Shall I do instead of this!? Anyone found a new efficient way of doing it? I got stuck in my stubborn mind and need someone to kick my butt so I go forward. Getting to old to change, but due to this profession it seems I constantly have to. :)
Looking at the DataTemplate documentation, there's a paragraph explaining the situation which you are trying to figure out.
For advanced data binding scenarios, you might want to have properties
of the data determine which template should produce their UI
representations. For this scenario, you can use a DataTemplateSelector
and set properties such as ItemTemplateSelector to assign it to a data
view. A DataTemplateSelector is a logic class you write yourself,
which has a method that returns exactly one DataTemplate to the
binding engine based on your own logic interacting with your data. For
more info, see Data binding in depth.
Here, you have an example on how you can select distinct DataTemplate for items in a control such as a ListView based on defined conditions.
Your situation is a bit different from the one described above, but the solution should be within what is explained above.
Create a class which derives from DataTemplateSelector, and override the SelectTemplateCore methods exposed by it, where you define the logic of what DataTemplate should be selected for the specific presented object.
This Derived class should expose properties of type DataTemplate, which identify each single DataTemplate template object, you pretend to be able to choose from.
Just as in the example, you are probably better of by defining the DataTemplate resources on an higher level object, such as the Page itself.
Instantiate your DataTemplateSelector Derived class in XAML as a resource and set each of the properties exposed above of type DataTemplate to the analogous DataTemplate static resource.
Utilize the ContentTemplateSelector dependency property, by setting it your custom DataTemplateSelector.
With this logic, it should be possible to have your ContentPresenter decide correctly between which DataTemplate it should choose from, based on your required UI logic.

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.

Windows 10 XAML 'Theming' a Style

I want to make ComboBoxes in my Windows 10 App to have theme colours (One have a green theme, one with an orange theme...etc). I can do it by making different styles for each different colour, but that adds a huge amount of markup and it's a mess to manage. Because they're also the styles, I read that bindings won't work because styles are sealed once they're initialized.
Has anyone figured out a way to just change colours of a style without having to make multiple separate styles?
WPF has some nice markup for this very problem. You can use DynamicResource to allow the style to refresh every time the resource gets changed. Here's an example:
<SolidColorBrush x:Key="ColourAccent">#448AFF</SolidColorBrush>
<Style TargetType="Button">
<Setter Property="Background" Value="{DynamicResource ColourAccent}"/>
</Style>
This of course is a very simple implementation of this method, but essentially the DynamicResource is a reference to ColourAccent that, if the resource was to change, will automatically reflect the change in the style.
Now, changing the resource is a slightly different problem, for theming your styles, you need somewhere to put all of your colours, the solution here is to use multiple ResourceDictionaries and using MergedDictionaries. Let me show you what I mean:
Firstly, add a folder to your project called Themes, it'll just make things easier. Also, add that Style I mentioned earlier to either the Window.Resources or App.Resources, it's pretty important.
You need to add a ResourceDictionary file to the folder (Call it Amber.xaml), it'll look something like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Amber -->
<SolidColorBrush x:Key="ColourAccent">#FFC107</SolidColorBrush>
</ResourceDictionary>
Here is a simple resource dictionary, it contains one resource called ColourAccent, now we need to create another one (Call it Blue.xaml), but with a different colour:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Blue -->
<SolidColorBrush x:Key="ColourAccent">#448AFF</SolidColorBrush>
</ResourceDictionary>
The magic here will become clear soon enough. Having multiple resource dictionaries with resources under the same name will allow you to create themes. The method of which is to swap the current resource dictionary for a new one, and by doing so, the DynamicResource will notice there has been a change and it'll refresh the control styles.
Now you have two resource dictionaries, you need to work out which dictionary to use. Firstly, we need to define the default resource dictionary that your application is going to use, you need to declare this in App.xaml.
<Application ...>
<Application.Resources>
<ResourceDictionary>
...
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/YourNamespace;component/Themes/Amber.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
So here you'll see the MergedDictionaries element, this is where the magic happens. If you run the app now, you should see that any buttons will have a background colour of Amber. Cool, huh?
Now it gets a little bit trickier, we will be removing the resource dictionary that is currently in the dictionary and replacing it with a different theme (a different resource dictionary).
Here is some C# to do that:
Disclaimer: I just threw this code together, there is almost certainly a better way, but you get the idea. Put the following code in a mouse click event, or somewhere where you can step it through to see what's happening.
Firstly, remove the current theme from the merged dictionaries.
//Find the current dictionary
ResourceDictionary oldDictionary = App.Current.Resources.MergedDictionaries.FirstOrDefault();
//If we found one, remove it.
if (dictionary != null)
App.Current.Resources.MergedDictionaries.Remove(oldDictionary);
Now we just need to add a different resource dictionary. I'm just going to add the Blue theme for the sake of an example:
//Declare some variables.
string folderPath = "/YourNamespace;component/Themes/";
string desiredTheme = "Blue";
//Create the new resource dictionary
ResourceDictionary newDictionary = new ResourceDictionary();
newDictionary.Source = new Uri(string.Format("{0}{1}.xaml", folderPath, desiredTheme), UriKind.RelativeOrAbsolute);
//Add the resource dictionary to the merged dictionaries.
App.Current.Resources.MergedDictionaries.Add(newDictionary);
Now if all goes well, the background for any buttons in your app should now be Blue. Hooray!
Using this method, which in essence is creating multiple resource dictionaries each with resources under the same name, you can create multiple themes for your application. This isn't restricted to colours, you can have entire styles which are theme specific, where one theme might display a button in a completely different way as another style. Experiment and see what you can come up with. Good luck!