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.
Related
I created a sftabView, every SfTabItem have a ContentView so I created an other View to display it in this ContentView. so the question is how to make this happened?
This is the ContentView which I wanted to display in the ContentPage
<?xml version="1.0" encoding="utf-8" ?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
x:Class="App5.Views.Self_Trainig"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
NavigationPage.HasNavigationBar="False">
<ContentView.Resources>
<ResourceDictionary>
............
</ResourceDictionary>
</ContentView.Resources>
<ContentView.Content>
<AbsoluteLayout>
...............
</AbsoluteLayout>
</ContentView.Content>
</ContentView>
and this is my ContentPage:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:tabView="clr-namespace:Syncfusion.XForms.TabView;assembly=Syncfusion.SfTabView.XForms"
x:Class="App5.Views.Accueil">
<ContentPage.Content>
<tabView:SfTabView OverflowMode="DropDown" VisibleHeaderCount="3" BackgroundColor="White">
<tabView:SfTabItem Title="Self Training">
<tabView:SfTabItem.Content>
""the code to display it here""
</tabView:SfTabItem.Content>
</tabView:SfTabItem>
<tabView:SfTabItem Title="Contacts">
<tabView:SfTabItem.Content>
<Grid BackgroundColor="White" x:Name="ContactsGrid" />
</tabView:SfTabItem.Content>
</tabView:SfTabItem>
</tabView:SfTabView>
</ContentPage.Content>
</ContentPage>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:mynamespace=clr-namespace:App5.Views"
...>
...
<tabView:SfTabItem.Content>
<mynamespace:Self_Trainig ... />
</tabView:SfTabItem.Content>
Explanation:
Add an xmlns:... definition for the namespace your ContentView is in.
Add an element with that namespace and the class name of your ContentView. <mynamespace:Self_Trainig ... />
...: After the class name, you can add any needed attributes. Just like any other ContentView.
If you want your view to have "custom" attributes (as opposed to the standard attributes of ContentView such as BackgroundColor), that can be set in each page's XAML, then in your ContentView's code behind, you'll add BindablePropertys. Doing that correctly is beyond the scope of this answer; there are other Q&As on that topic.
is it possible to display the view form the C# code ?
i mean doing
ContentView x:Name="TheView"
and on the C# code doing something like
TheView = Self_Trainig;
i know that code doesn't work but i'm searching that kind of solution
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>
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'm used to Android development, and am having some difficulty accomplishing what I would think is a simple task.
I have a MasterDetailPage (called ContainerView.xaml).
The Master is my navigation bar (called NavbarView.xaml).
The Details is supposed to be a page with a fixed title bar, and a "view" I can can swap per user choices.
The Details page is called MainView.xaml.
The Title I'd like to display at the top and is called TitleBarView.xaml.
Then I have a number of content pages such as Page1View.xaml.
in my ContainerView.xaml:
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.ContainerView"
IsGestureEnabled="True"
MasterBehavior="Popover"
Title="MasterDetail Page">
<MasterDetailPage.Master>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
</MasterDetailPage.Detail>
</MasterDetailPage>
in my NavbarView.xaml - this is the Master
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.NavBarView"
Title="Nav Bar">
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<Label Text="{Binding Item1}"/>
<Button Text="Options" Command="{Binding Option1Command}"/>
</StackLayout >
</ContentPage.Content>
</ContentPage>
in my MainView.xaml - this is the details
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.MainView"
Title="Main View">
<ContentPage.Content>
// what to put here to show the TitleBarView.xaml?
// what to put here to show my content xaml pages?
</ContentPage.Content>
</ContentPage>
in my TitleBarView.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.TitleBarView">
<ContentView.Content>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Item1}"/>
<Button Text="Options" Command="{Binding OptionsCommand}"/>
</StackLayout>
</ContentView.Content>
</ContentView>
and a generic content view, of course there will be many others I want to switch between
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Page1View">
<ContentView.Content>
<StackLayout Orientation="Vertical">
<Label Text="{Binding Info}"/>
<Button Text="Log In" Command="{Binding GoToPage2Command}"/>
</StackLayout >
</ContentView.Content>
</ContentView>
I am using the MVVM model and have this code, but can't seem to get just the basics working.
The Master page displays fine.
If the Details page is just a simple page, it works, but I can't figure out how to insert the TitleBar and swap out the "Content".
ContainerView containerPage = new ContainerView();
ContainerViewModel containerVM = new ContainerViewModel();
containerPage.BindingContext = containerVM;
NavBarView navigationBar = new NavBarView();
navigationBar.Title = "Navigation Bar"; // required, otherwise I get an exception.
NavBarViewModel navigationBarVM = new NavBarViewModel();
navigationBar.BindingContext = navigationBarVM;
MainView mainView = new MainView();
mainView.Title = "MainView";
MainViewModel mainViewVM = new MainViewModel();
mainView.BindingContext = mainViewVM;
TitleBarView titleBar = new TitleBarView();
TitleBarViewModel titleBarVM = new TitleBarViewModel();
titleBar.BindingContext = titleBarVM;
Page1View page1 = new Page1View();
Page1ViewModel page1VM = new Page1ViewModel();
page1.BindingContext = page1VM;
mainView.Content = new StackLayout()
{
Orientation = StackOrientation.Vertical,
Children =
{
new Label { Text = "I'm Content!" },
new Label { Text = "I'm Content!" },
//titleBar.Content,
//loginView.Content
}
};
containerPage.MasterBehavior = MasterBehavior.Popover;
containerPage.Master = navigationBar;
containerPage.Detail = new NavigationPage(mainView);
I'm sure I'm missing a fundamental concept. Any help would be appreciated
Xaml can instantiate any control, defined in code or in Xaml, so in case of TitleBarView, you can instantiate it in any Xaml by
<xmlnsprefix:TitleBarView />
The problem is to set the right xmlnsprefix. Every xaml file define a few xmlns and you can add your own, like this:
xmlns:local="clr-namespace:MyApp"
and it'll mean that the Xml namespace 'local' will reference the clr namespace 'MyApp' in the current assembly.
So you MainView becomes:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyApp"
x:Class="MyApp.MainView"
Title="Main View">
<ContentPage.Content>
<local:TitleBarView />
</ContentPage.Content>
</ContentPage>
I have a test page in Xamarin.Forms and it gets me this error, how can I fix this ?
Property Content is null or is not IEnumerable
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="Project1.Page1">
<ContentPage.Content>
<Label Text="Page"></Label>
<Editor Text="I am an Editor" />
</ContentPage.Content>
</ContentPage>
The Content property is of type View. You cannot have two views into it. Replace it with
<StackLayout >
<Label Text="Page"></Label>
<Editor Text="I am an Editor" />
<StackLayout>
If anyone else lands here from google and the above wasn't the fix. For me it was because I had a view with a Grid.Row="0" property set even though I accidentally placed it outside the bounds of the actual grid.