Out of my ControlTemplate laying in App.xaml I try to get a boolean property from the used ViewModel to make elements (in this case an activityIndicator) visible in the Content xaml.
Property:
Private bool isLoading;
public bool IsLoading
{
get => this.isLoading;
set => this.SetProperty(ref this.isLoading, value);
}
Contentpage:
ControlTemplate="{StaticResource Template__Page_Scrollable}"
ControlTemplate (I will integrate the ActivityIndicator in the StackLayout, but first I only want to show the StackLayout itself by setting the backgroundcolour to Aqua):
<ControlTemplate x:Key="Template__Page_Scrollable">
<AbsoluteLayout x:Name="ActivityIndicator">
<ScrollView Style="{StaticResource Page_Scrollable__ScrollContainer}" AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All">
<ContentPresenter AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All"/>
</ScrollView>
<StackLayout AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All"
IsEnabled="{TemplateBinding Parent.BindingContext.IsLoading}"
IsVisible="{TemplateBinding Parent.BindingContext.IsLoading}" BackgroundColor="Aqua">
</StackLayout>
</AbsoluteLayout>
</ControlTemplate>
Due to my research this should work by i get the message "Connot resolve symbol 'Parent'"
Without 'Parent' I always get true as a result.
I've tried for example:
setting aditionaly the BindingContext
IsEnabled="{TemplateBinding BindingContext.IsLoading}"
IsEnabled="{TemplateBinding IsLoading}"
IsEnabled="{Binding IsLoading}"
If you really have your ControlTemplate set on your ContentPage, e.g.:
<ContentPage
...
ControlTemplate="{StaticResource Template__Page_Scrollable}">
this is incorrect. Parent in the ControlTemplate refers to the parent view of the view that is hosting the control template. A ContentPage has no parent view.
Instead, you need to set the control template on the ContentView in your ContentPage , e.g.:
<ContentPage ...>
<ContentView ControlTemplate="{StaticResource Template__Page_Scrollable}" >
...
</ContentView>
</ContentPage>
Related
I'm trying to bind string path in XAML using prism navigateto extension method from a button in ListView.
Apparently the BindingContext isn't recognized to be the same as in the ListView
Here's the sample code of what i'm trying to achieve.
<ListView
x:Name="MainMenu"
CachingStrategy="RetainElement"
HasUnevenRows="True"
ItemsSource="{Binding MenuItems}"
Margin="20,0,0,0"
SeparatorVisibility="Default">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<buttons:SfButton
Style="{StaticResource BaseButtonStyle}"
HeightRequest="70"
TextColor="{StaticResource MenuTextColor}"
Text="{Binding Title}"
HorizontalTextAlignment="Start"
VerticalOptions="CenterAndExpand"
HorizontalOptions="FillAndExpand"
ImageSource="{Binding MenuItemType, Converter={StaticResource MenuItemTypeConverter}}"
ShowIcon="True"
Command="{prism:NavigateTo Name={Binding Item.View}}"
/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Any ideas how to set the binding in this situations?
Regards.
Within any sort of ListView, CollectionView, etc where you are binding an ItemsSource and then have some sort of DataTemplate to display an individual item in that collection, the Binding Context within that DataTemplate is the individual item in the collection not the ViewModel that that provides the Binding Context of both your Page and the ListView.
There are technically a couple parts to this that you will want to understand. Let's say that your model looks like:
public class FooModel
{
public string Text { get; set; }
public string NavigationPath { get; set; }
}
And let's say that you have a collection of FooModel like:
public ObservableCollection<FooModel> FooItems { get; }
In XAML you might have something like:
<ListView ItemsSource="{Binding FooItems}">
However when you go to reference properties of FooItem you will just reference them like:
<ListView.DataTemplate>
<DataTemplate>
<ViewCell>
<Button Text="{Binding Text}"
Command="{prism:NavigateTo Name={Binding NavigationPath}" />
</ViewCell>
</DataTemplate>
</ListView.DataTemplate>
Now assuming that the issue isn't that you're just adding Item erroneously, let's look at some other possible issues/solutions. To start let's look at the start of our page.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="http://prismlibrary.com"
x:Name="page"
x:Class="HelloWorld.Views.ViewA">
The big thing to notice here is that I've added the x:Name attribute so that I can reference the page itself later. In general within the context of something like a ListView if I need to access say the FooCommand property within my ViewModel I might would change my XAML markup from:
<Button Command="{Binding FooCommand}" />
To instead look at the Page's BindingContext like this:
<Button Command="{Binding BindingContext.FooCommand, Source={x:Reference page}}" />
While this will help you in general within your ListView it still doesn't necessarily help you with the issue of using Prism's Navigation Extensions. For this you may need to pass in the SourcePage like the following:
<Button Command="{prism:NavigateTo 'Foo', SourcePage={x:Reference page}}" />
In the event this doesn't work for some reason then you may be possible that the BindingContext isn't getting set properly on the Navigation Extension itself. To work around this you would want to update your command as follows:
<Button x:Name="cellButton"
Command="{prism:NavigateTo Name={Binding View},
BindingContext={x:Reference cellButton}}" />
Note that if you need to reference the SourcePage or add the BindingContext to resolve your issue, please provide a sample that reproduces the issue and open an issue on GitHub.
I have a ContentView that uses a static resource in the App.xaml. The app resource is a custom DataTemplateSelector
<c:ControlTemplateSelector x:Key="controlTemplateSelector"
PickerWorkflowItemTemplate="{StaticResource pickerWorkflowItemTemplate}"
DatePickerWorkflowItemTemplate="{StaticResource datePickerWorkflowItemTemplate}"
TimePickerWorkflowItemTemplate="{StaticResource timePickerWorkflowItemTemplate}"
MultiPickerWorkflowItemTemplate ="{StaticResource multiPickerWorkflowItemTemplate}"
NumberPickerWorkflowItemTemplate ="{StaticResource numberPickerWorkflowItemTemplate}"
MultiPickerWithOptionWorkflowItemTemplate ="{StaticResource multiPickerWithOptionWorkflowItemTemplate}"
SwitchWorkflowItemTemplate ="{StaticResource switchWorkflowItemTemplate}"
GridWorkflowItemTemplate="{StaticResource gridWorkflowItemTemplate}"
TextBoxWorkflowItemTemplate="{StaticResource textBoxWorkflowItemTemplate}">
</c:ControlTemplateSelector>
As soon as I add
<DataTemplate x:Key="horizontalStackContainerWorkflowItem">
<c:HorizontalStackContainerWorkflowItem />
</DataTemplate>
to the ResourceDictionary in App.xaml I get a runtime exception:
Xamarin.Forms.Xaml.XamlParseException: Timeout exceeded gettingexception details
The consuming view:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView 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"
x:Class="Positron.Mobile.Controls.HorizontalStackContainerWorkflowItem"
xmlns:vmc="clr-namespace:Positron.Mobile.ViewModel.Controls;assembly=Positron.Mobile"
x:Name="ContentView"
xmlns:c="clr-namespace:Positron.Mobile.Controls;assembly=Positron.Mobile"
>
<ContentView.Content>
<ListView ItemTemplate="{StaticResource controlTemplateSelector}" ItemsSource="{Binding ControlViewModels}" >
...
</ListView>
</ContentView.Content>
</ContentView>
EDIT:
This seems to be the actual exception that is thrown. I just don't know why I cannot use the Resource in my data template.
StaticResource not found for key controlTemplateSelector
It seems to be very similar to the following issue Circular referenced IValueConverter in Application.Resources
EDIT
The below works but is obviously not that great since you would not want to define all your ContentViews in the App.xaml resource dictionary. So would still like someone to tell me how to accomplish it without this work around.
<DataTemplate x:Key="horizontalStackContainerWorkflowItemTemplate">
<ContentView>
<ContentView.Content>
<ListView ItemTemplate="{StaticResource controlTemplateSelector}" ItemsSource="{Binding ControlViewModels}" >
...
</ListView>
</ContentView.Content>
</ContentView>
</DataTemplate>
<c:ControlTemplateSelector x:Key="controlTemplateSelector"
PickerWorkflowItemTemplate="{StaticResource pickerWorkflowItemTemplate}"
DatePickerWorkflowItemTemplate="{StaticResource datePickerWorkflowItemTemplate}"
TimePickerWorkflowItemTemplate="{StaticResource timePickerWorkflowItemTemplate}"
MultiPickerWorkflowItemTemplate ="{StaticResource multiPickerWorkflowItemTemplate}"
NumberPickerWorkflowItemTemplate ="{StaticResource numberPickerWorkflowItemTemplate}"
MultiPickerWithOptionWorkflowItemTemplate ="{StaticResource multiPickerWithOptionWorkflowItemTemplate}"
SwitchWorkflowItemTemplate ="{StaticResource switchWorkflowItemTemplate}"
GridWorkflowItemTemplate="{StaticResource gridWorkflowItemTemplate}"
TextBoxWorkflowItemTemplate="{StaticResource textBoxWorkflowItemTemplate}"
HorizontalStackContainerWorkflowItemTemplate ="{StaticResource horizontalStackContainerWorkflowItemTemplate}">
</c:ControlTemplateSelector>
View to View data binding between a ContentPage and ContentView
I'm using the PlaneRotationDemoPage sample from the Xamarin Forms Book https://download.xamarin.com/developer/xamarin-forms-book/XamarinFormsBook-Ch21-Apr2016.pdf
I have a ContentPage and want to move a Slider control from the ContentPage into a ContentView that is in a different XAML/CS file. The content view itself seems to be referenced correctly, however the Slider control binding doesn't seem to be wired correctly. I get an error "Can't resolve name on Element"
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:PlaneRotationDemo;assembly=PlaneRotationDemo"
x:Class="PlaneRotationDemo.PlaneRotationDemoPage" >
...
<local:RoundedBoxView x:Name="handA"
StrokeThickness="2"
CornerRadius = "40"
Stroke = "White"
Color = "Gray"
AbsoluteLayout.LayoutBounds = "152.0,248.0,15.0,15.0"
/>
...
<local:SliderTest /> //new ContentView
//Moving just the slider below into a ContentView
<!--
<Slider x:Name="rotationSlider"
AbsoluteLayout.LayoutBounds = "0,0,200,50"
Maximum="360"
Value="{Binding Source={x:Reference Name=handA},
Path=Rotation}"
/>-->
//the label below on the ContentPage should bind with the slider that was moved to the ContentView
<Label Text="{Binding Source={x:Reference rotationSlider},
Path=Value,
StringFormat='Rotation = {0:F0}'}"
HorizontalTextAlignment="Center"
/>
In the ContentView file...
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PlaneRotationDemo.SliderTest">
<ContentView.Content>
//slider moved here
<Slider x:Name="rotationSlider"
Maximum="360"
Value="{Binding Source={x:Reference Name=handA}, //should bind with handA in the ContentPage
Path=Rotation}"
/>
</ContentView.Content>
The label in the ContentPage needs to reference the slider that is now in the ContentView
The Slider that is now in the ContentView needs to reference the handA RoundedBoxView that is in the ContentPage
Is this possible in XAML?
Expose a BindableProperty in User Control (Content View). Bind BindableProperty to Value property in Slider Control.
And XAML looks like this.
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PlaneRotationDemo.SliderTest" x:Name=UC>
<ContentView.Content>
//slider moved here
<Slider x:Name="rotationSlider"
Maximum="360"
Value="{Binding MyBindableProperty, Source={x:Reference Name=UC},
Path=Rotation}"/>
</ContentView.Content>
And usage will be like this.
<local:RoundedBoxView x:Name="handA"
StrokeThickness="2"
CornerRadius = "40"
Stroke = "White"
Color = "Gray"
AbsoluteLayout.LayoutBounds = "152.0,248.0,15.0,15.0"
/>
<local:SliderTest MyBindableProperty={Binding Source={x:Reference handA}}/>
Hope this helps.
When you create a Xaml it creates a cs and an autogenerated cs(xaml.g.cs) file that your x:Name references defined there. Since handA is not defined your SliderTest.xaml file you're getting this error.
I am new to Xamarin Form Application development and Want to try a simple app that will get string from textfield and place it in label by data binding.
Text field with 20 px margin from both side and vertically center.
Label will be below text field.
When typing in textField, the label will update (MVVM)
UI design will be from XAML.
Thank you.
If you are using Xamarin Forms to achieve this and using DataBinding (MVVM), first in your ViewModel (We will call it MainPageViewModel.cs) you need something like this:
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace SandboxForms.ViewModels
{
public class MainPageViewModel : INotifyPropertyChanged
{
private string _myTextField;
public string MyTextField
{
get { return _myTextField; }
set
{
_myTextField = value;
OnPropertyChanged(nameof(MyTextField));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var handler = PropertyChanged;
if (handler != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then in our ContentPage (We will call this one MainPage.xaml):
<?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="SandboxForms.Pages.MainPage"
xmlns:viewmodels="clr-namespace:SandboxForms.ViewModels;SandboxForms">
<ContentPage.BindingContext>
<viewmodels:MainPageViewModel />
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout Padding="20">
<!-- I am applying EndAndExpand to the entry and
StartAndExpand to the label to center them each other -->
<Entry
HorizontalOptions="FillAndExpand"
VerticalOptions="EndAndExpand"
Placeholder="Write here and see the magic!!!"
Text="{Binding MyTextField}"/>
<Label
HorizontalTextAlignment="End"
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand"
Text="{Binding MyTextField}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Here is a few screenshots of the results:
Application starting,
Entering text on your Entry
Hope this works for you, my best regards!
There are two approaches for data binding each of which has merits depending on the situation. The first is MVVM as mentioned previously. This works well for fields that your ViewModel should know about, such as the text in an entry field but this isn't always the case and it's important to have a complete understanding before choosing the right method for your needs.
MVVM Approach
ViewModel
public class MyPageViewModel : INotifyPropertyChanged
{
private string myTextField;
public string MyTextField
{
get { return myTextField; }
set
{
if( !myTextField.Equals( value ) )
{
myTextField = value;
OnPropertyChanged("MyTextField");
}
}
}
}
View
<?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="SandboxForms.Pages.MainPage"
xmlns:viewmodels="clr-namespace:SandboxForms.ViewModels;SandboxForms">
<ContentPage.BindingContext>
<viewmodels:MainPageViewModel />
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout Padding="20">
<!-- I am applying EndAndExpand to the entry and
StartAndExpand to the label to center them each other -->
<Entry
HorizontalOptions="FillAndExpand"
VerticalOptions="EndAndExpand"
Placeholder="Write here and see the magic!!!"
Text="{Binding MyTextField}"/>
<Label
HorizontalTextAlignment="End"
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand"
Text="{Binding MyTextField}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
This is generally a preferred approach by most developers as opposed to mixing business logic directly in the code behind of your UI.
There are a number of helpers, and frameworks out there that you can look at if you aren't familiar with this. The following are some of the more popular ones.
MvvmHelpers - James Montemagno
Prism Library (my personal favorite)
Mvvm Cross
Mvvm Light
View Centric Approach
Sometimes it actually would violate the MVVM pattern to directly bind to a property of our ViewModel, and other times we may want to display something in our View without the need of updating a backing field in the ViewModel. As an example we can look at Xamarin's guide to data binding.
<?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="XamlSamples.SliderBindingsPage"
Title="Slider Bindings Page">
<StackLayout>
<Label Text="ROTATION"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
<Label BindingContext="{x:Reference slider}"
Text="{Binding Value,
StringFormat='The angle is {0:F0} degrees'}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
I should note that one of the most common times I would recommend using this approach is with Context Actions in a ListView, since our ViewModel may contain the Command that we want to execute on the individual cell, however the cell in which we are executing the context action actually is bound to the object from our IEnumerable<T> and not our ViewModel. In this particular case we would do something like the following:
<?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:Name="someListPage"
x:Class="MyApp.Views.SomeListPage">
<ListView ItemsSource="{Binding Gear}"
CachingStrategy="RecycleElement"
IsRefreshing="{Binding IsRefreshing}"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Description}" Detail="{Binding Detail}">
<TextCell.ContextActions>
<MenuItem Text="Remove"
Command="{Binding BindingContext.RemoveItemCommand,Source={x:Reference someListPage}}"
CommandParameter="{Binding .}"
IsDestructive="True" />
</TextCell.ContextActions>
</TextCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
You'll notice that for this to work we first give the page itself a name that we can then reference for our binding for the ContextAction Command property. This is only changing where we are looking for this single property. We then resume using the normal binding context for the CommandParameter property and pass in the actual object the cell is bound to with {Binding .}
Hope this helps you better understand your options for binding with Xaml. Happy Coding!
I have a ListView in my XAML in which I show some data from my database, the problem is that in the meantime the ActivityIndicator show up as excpected, but when I set it to False, the content that is suppose to show up, doesn't. I don't know if I'm using the ActivityIndicator wrong, how I suppose to use it then?
XAML:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage...">
<ActivityIndicator x:Name="load1" Color="Red" IsRunning="true" />
<ContentPage.Content>
<ListView x:Name="XPS" ItemTapped="OnItemSelected"
...
</ListView>
</ContentPage.Content>
</ContentPage>
CS:
load1.IsRunning=false;
It looks like you're using ContentPage incorrectly. That page only supports having 1 child element (named Content). You're trying to define 2 different Content on 1 ContentPage. Xamarin.Forms just throws away your ListView so it will never show up.
So now you might wonder... How is that thing even useful? Good question! When you need to put multiple Views in 1 ContentPage you need to use a Layout. Xamarin.Forms has a bunch of layouts available that all behave differently - see https://developer.xamarin.com/guides/cross-platform/xamarin-forms/controls/layouts/ for some more details there.
Let's check out some code.... (I haven't actually tested this, I'm typing it directly into here, so you might need to fix some things...)
An updated ContentPage XAML:
<ActivityIndicator x:Name="load1" Color="Red" IsRunning="true" />
<ContentPage.Content>
<StackLayout x:Name="Layout">
<ActivityIndicator x:Name="load1" Color="Read" IsRunning="true"/>
<ListView x:Name="XPS" ItemTapped="OnItemSelected" Opacity="0"
...
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Now for some Code Behind...
public void LoadYourStuff()
{
LoadSomeTotallyAwesomeData();
WriteSomeTotallyAwesomeDataIntoAFancyListView();
PerhapsDoMoreFancyThings();
Layout.Children.Remove(load1);
XPS.Opacity = 1.0;
}
in your xmal file put :
<ActivityIndicator x:Name="popupView" VerticalOptions="Center" HorizontalOptions="Center" Color="DarkBlue" IsRunning="True" IsVisible="false" IsEnabled="True" />
when need this in C# code :
popupView.IsVisible = true;
.
.
.
.
.
.
popupView.IsVisible = false;