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;
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.
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 have a stepper and i want to add new entry field when the value increment or delete entry on value decrement , i manged to do that but the UI won't refresh directly after the value of the stepper change (i need to click on other UI element first) then the fields will appear , and after clicking in other UI element the stepper will work properly (adding and deleting functionality) which i don't know why it's happening ?!! .
EDIT :
It's look like the problem is with having scroll view .. if i remove it the new fields will added or deleted directly .. but still don't know why .
The xaml page
<ScrollView>
<StackLayout x:Name="StackLayout">
<Label Text="عدد العناصر المراد اضافتها (اقصى عدد في المرة الواحدة 30)"></Label>
<Stepper Maximum="30"
Minimum="2"
Increment="1"
ValueChanged="Stepper_OnValueChanged"
Value="2"></Stepper>
<StackLayout x:Name="EntryStackLayout">
<Entry></Entry>
<Entry ></Entry>
</StackLayout>
</StackLayout>
</ScrollView>
Code Behind
public partial class AddNewListOfItemsPage : ContentPage
{
public AddNewListOfItemsPage ()
{
InitializeComponent();
}
private void Stepper_OnValueChanged(object sender, ValueChangedEventArgs e)
{
if (e.NewValue > e.OldValue)
{
EntryStackLayout.Children.Add(new Entry());
}
else
{
var childCount = EntryStackLayout.Children.Count;
EntryStackLayout.Children.RemoveAt(childCount - 1);
}
}
}
Ok i found that adding a stackLayout before the scrollView fix the problem
<StackLayout>
<ScrollView>
<StackLayout x:Name="StackLayout">
<Label Text="عدد العناصر المراد اضافتها (اقصى عدد في المرة الواحدة 30)"></Label>
<Stepper Maximum="30"
Minimum="2"
Increment="1"
ValueChanged="Stepper_OnValueChanged"
Value="2"></Stepper>
<StackLayout x:Name="EntryStackLayout">
<Entry></Entry>
<Entry ></Entry>
</StackLayout>
</StackLayout>
</ScrollView>
</StackLayout>
I had a similar problem. Size of elements deep inside ScrollView was not refreshed after layout change (on Android < 4.3).
Specifying height of ScrollView helped (specifying either one of the following for ScrollView in XAML helped):
VerticalOptions="FillAndExpand"
HeightRequest="100"
I would like to switch many pages between in single xaml page on click on segment control.
I want make a page like upper part of page is with segment control and below this control having simple layout that is using for replace or switch a other pages in same that below position change but upper part is still remains for next page switching.
So, i would like to code for switching page with using segment control in xaml in xamarin.forms.
There is a nuget package FreshEssentials. It has cross-platform implementation of segmented control button. Find this Github repository to understand the implementation.
Hope this help !
Refer bellow link to implement custom segment control using XAML code and Cs Code
https://github.com/sam-ss/Custom-Segmented-Control-Xamarin-Forms
Hope This Help you!
you can install from nuget this library "Plugin.Segmented.Control"
from this tutorial https://www.c-sharpcorner.com/article/segment-control-in-xamarin-forms/
and your 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" xmlns:control="clr-namespace:Plugin.Segmented.Control;assembly=Plugin.Segmented" xmlns:iOSForms="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core" iOSForms:Page.UseSafeArea="true" xmlns:local="clr-namespace:XFSegmentControlDemo" x:Class="XFSegmentControlDemo.Views.HomePage">
<StackLayout VerticalOptions="FillAndExpand" Padding="30" Spacing="20">
<Label Text="Segmented Control" FontSize="30" TextColor="White" HorizontalOptions="CenterAndExpand" />
<control:SegmentedControl x:Name="SegmentedControl" SelectedSegment="{Binding SegmentSelection}" TintColor="White" SelectedTextColor="BlueViolet" DisabledColor="Gray" Margin="8,8,8,8">
<control:SegmentedControl.Children>
<control:SegmentedControlOption Text="Item 1" />
<control:SegmentedControlOption Text="Item 2" />
</control:SegmentedControl.Children>
</control:SegmentedControl>
<Label Text="{Binding SelectedSegment}" FontSize="40" TextColor="White" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
put this code in your viewModel
int _selectedSegement;
public int SelectedSegment {
get {
return _selectedSegement;
}
set {
_selectedSegement = value;
switch (SelectedSegment) {
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
}
OnPropertyChanged("SelectedSegment");
}
}
and the last step put this in your appDelegate
global::Xamarin.Forms.Forms.Init();
SegementedControlRenderer.Initialize();
LoadApplication(new App());
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!