I have a page with a list of items and when some is selected, the ActivityIndicator turns on and goes to another page, turning off. When i am in this new page and i click the BackButton on NavigationPage, i return to the page with the List of items, but the problem is that the ActivityIndicator is on (persists). How can i fix it ?
[List Page]
public partial class ResultadosBuscados : ContentPage
{
public ResultadosBuscados(IEnumerable dadosPesquisados)
{
IsBusy = false;
InitializeComponent();
BindingContext = this;
ListaBuscados.ItemsSource = dadosPesquisados;
}
public void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
IsBusy = true;
stackActivity.IsVisible = true;
Envolvido envolvSelec = (Envolvido)e.SelectedItem;
if (envolvSelec == null)
return;
IsBusy = false;
stackActivity.IsVisible = false;
this.Navigation.PushAsync(new EnvolvidoDetalhe(envolvSelec));
this.ListaBuscados.SelectedItem = null;
}
}
[part of XAML code]
<StackLayout x:Name="stackActivity" IsVisible="False" Padding="12"
AbsoluteLayout.LayoutFlags="PositionProportional"
AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1">
<Frame Padding="50" OutlineColor="Black" HasShadow="true" AbsoluteLayout.LayoutFlags="PositionProportional" Opacity="0.8" BackgroundColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<StackLayout>
<ActivityIndicator IsRunning="{Binding IsBusy}" Color ="#F4B400"/>
<Label Text="Aguarde..." TextColor="#F4B400"/>
</StackLayout>
</Frame>
</StackLayout>
Like I said in the comment, check for anywhere that IsBusy is being set to true and not being set back to false. The bindings do not go away when the page changes and is brought back up.
Also, I found this awesome code that has worked well for me most of the time and which makes it so that you do not need to worry about setting IsBusy to false (though be warned that they are doing some fancy stuff so that it can be set in the ViewModel, you could instead add the code to a base ContentPage that all your pages derive from if you do not want to get it working in your ViewModel).
Code to make it work:
https://github.com/xamarin/Sport/blob/4abddfab1e1cb0e7d14925aa27cae7685dbd5f38/Sport.Mobile.Shared/ViewModels/BaseViewModel.cs#L138
Example of it being used:
https://github.com/xamarin/Sport/blob/04f6b99cec752a106d51566ed96231beacfd2568/Sport.Mobile.Shared/ViewModels/AvailableLeaguesViewModel.cs#L41
*Edit:
OnAppearing override example:
public partial class ResultadosBuscados : ContentPage {
public ResultadosBuscados(IEnumerable dadosPesquisados) {
IsBusy = false;
InitializeComponent();
BindingContext = this;
ListaBuscados.ItemsSource = dadosPesquisados;
}
protected override void OnAppearing() {
base.OnAppearing();
IsBusy = false;
}
}
Related
I found that DatePicker is missing a Placeholder. It was decided in cases where the date is not specified - to display Label instead of DatePicker. However, when clicking on Label I need to open DatePicker, but it doesn't work
.xaml:
<controls:DatePickerWithoutBottomLine
x:Name="datePicker"
IsVisible="{Binding DisplayWeddingDate, Mode=TwoWay}"
Date="{Binding WeddingDate, Mode=TwoWay}" />
<Label
IsVisible="{Binding NotDisplayWeddingDate}"
Text="some text">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />
</Label.GestureRecognizers>
</Label>
.xaml.cs:
private void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
{
var label = (Label)sender;
var datePicker = this.FindByName<DatePicker>("datePicker");
label.IsVisible = false;
datePicker.IsVisible = true;
datePicker.Focus();
}
viewmodel.cs:
public partial class HomePageViewModel : BaseViewModel
{
[ObservableProperty]
private DateTime? weddingDate;
[ObservableProperty]
private bool displayWeddingDate;
[ObservableProperty]
private bool notDisplayWeddingDate;
private readonly PlanningService planningService;
[ObservableProperty]
private bool isRefreshing;
public HomePageViewModel(PlanningService planningService)
{
this.planningService = planningService;
InitAsync();
}
public override async void InitAsync()
{
await RefreshAsync();
}
[RelayCommand]
private async Task RefreshAsync()
{
WeddingDate = await planningService.GetWeddingDateAsync();
DisplayWeddingDate = WeddingDate.HasValue;
NotDisplayWeddingDate = !DisplayWeddingDate;
IsRefreshing = false;
}
}
If the datepicker has IsVisible false, it's not part of the visual tree. There is no datePicker there to focus.
datePicker.IsVisible = true;
datePicker.Focus();
Try using this.Dispatcher.Dispatch to delay focus and give it a bit of time to be rendered.
datePicker.IsVisible = true;
this.Dispatcher.Dispatch(() =>
{
datePicker.Focus();
});
This is an issue on Github: Fix (or don't) the behavior of calling "Focus" on Android to open the picker . From the comment , Ghostbird said the code that opens the picker has been removed from the Focus() method. So we could not use Focus() method to open the datepicker any more.
I get data from another page with
var check = new check
{
Age = (int)Convert.ToInt64(Ageg)
};
var secondPage = new Sdeduction ();
secondPage.BindingContext = check;
await Navigation.PushAsync(secondPage);
and received on
public class check
{
public int Age { get; set; }
}
public Sdeduction()
{
InitializeComponent();
}
but I am unable to access Age for some calculation directly. lile tta.Text = Age.ToString();
So I use binding. Which work well.
<Label x:Name="Ages" Text="{Binding Age}"></Label>
but i want to check for Age which data get passed between page but I'm unable to figure it out I try
public Sdeduction()
{
InitializeComponent();
int aged = (int)Convert.ToInt64(Ages.Text);
if (aged == 0)
{
TTA.IsVisible = true;
}
if(aged > 0)
{
TTB.IsVisible = true;
//Ds.IsVisible = true;
}
}
But it is Ages.Text is null.
Main issue is how to get data from public class check
public class check
{
public int Age { get; set; }
}
How can able to get this public int in other part of c#. where get passed data by
I can able to bind but https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/ is all about the binding property and context on the xaml level. I like to get data from other page but only can able to bind with the x:names Ages but nothing much as when page load/InitializeComponent it don't have names of ages.
You set the BindingContext of the Sdeduction instance to the check instance, and then navigates to the Sdeduction. It's the right way to pass data when navigating.
But when you check for Age as page load in Sdeduction() method, it always get 0 before the Sdeduction page set the BindingContext. You nned to load in OnAppearing() method.
MainPage:
xaml:
<StackLayout>
<Label x:Name="label" Text="10" />
<Button Clicked="Button_Clicked" Text="Navigate" />
</StackLayout>
Code behind:
public partial class MainPage : ContentPage
{
string Ageg;
public MainPage()
{
InitializeComponent();
Ageg = label.Text;
}
async void Button_Clicked(object sender, EventArgs e)
{
var check = new check
{
Age = (int)Convert.ToInt64(Ageg)
};
var secondPage = new Sdeduction();
secondPage.BindingContext = check;
await Navigation.PushAsync(secondPage);
}
}
Sdeduction:
Xaml:
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to Sdeduction!"
VerticalOptions="CenterAndExpand" />
<Label x:Name="Ages" Text="{Binding Age}" />
<StackLayout Orientation="Horizontal">
<Button
x:Name="TTA"
IsVisible="false"
Text="TTA" />
<Button
x:Name="TTB"
IsVisible="false"
Text="TTB" />
</StackLayout>
</StackLayout>
Code behind:
protected override void OnAppearing()
{
base.OnAppearing();
int aged = (int)Convert.ToInt64(Ages.Text);
if (aged == 0)
{
TTA.IsVisible = true;
}
if (aged > 0)
{
TTB.IsVisible = true;
//Ds.IsVisible = true;
}
}
Please check the screenshot:
https://imgur.com/vx6GZFw
I have Some UI logic and I need to Add them in Code behind. In order to overcome the code duplication, I need to use a property and change it. Normal MVVM thing. But when I try to do it with Codebehind. Mean I bind XAML with my code behind in order to access the isvisible function in several places. Problem is it does not binding or any other problem visibility did not change when action is fired.
My ContentView Xaml
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:customRenderes="clr-namespace:DipsDemoXaml.CustomRenderes;assembly=DipsDemoXaml"
x:Class="DipsDemoXaml.Views.Page1"
x:Name="navi">
<StackLayout BindingContext="{x:Reference Name=navi}">
<customRenderes:NavigationImageButton Source="MenuSettings"
x:Name="Button1"
Margin="0"
IsVisible="{Binding Visibility}"
/>
In code behind
public partial class Page1 : ContentView
{
private bool _expand;
private bool _visibility;
public bool Visibility
{
get => _visibility;
set
{
_visibility = value;
OnPropertyChanged();
}
}
public Page1 ()
{
InitializeComponent ();
}
private void Button1_OnItemTapped(object sender, EventArgs e)
{
if (_expand)
{
this.Hide();
}
else
{
this.Expand();
}
}
private async void Expand()
{
_expand = true;
Button5.Opacity = 1;
_visibility = true;
await Button5.RotateTo(180, 200);
}
private async void Hide()
{
_expand = false;
Button5.Opacity = 0.4;
_visibility = false;
await Button5.RotateTo(360, 200);
}
}
How to bind this in xamarin forms. Is my binding is wrong or where is the problem
my onpropertychanged method
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
changed?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Call Visibility, not _visibility , or manually trigger OnPropertyChanged. But the 1st option is preferred. BTW, I don't know what is your OnPropertyChanged implementation, but typically it is called with your property name, as #Maniax mentioned, or using nameof operator, e.g. OnPropertyChanged(nameof(Visibility))
First of all, PropetyChanged takes an argument,
OnPropertyChanged("Visibility");
I guess this should work but it is odd to put your ViewModel code in the code behind.
The idea of MVVM is to move the logic from to page, to the ViewModel, allowing you to manage the state of several pages within the same ViewModel with almost, if not, 0 code in the page behind the XAML.
So you probably should create another file that you will call ViewModel, and put you're business logic in it.
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:customRenderes="clr-
namespace:DipsDemoXaml.CustomRenderes;assembly=DipsDemoXaml"
x:Class="DipsDemoXaml.Views.Page1"
xmlns:vm="clr-namespace:DipsDemoXaml.ViewModels;assembly=DipsDemoXaml"
x:Class="DipsDemoXaml.Views.Page1"
x:Name="navi">
<ContentView.BindingContext>
<vm:MyViewModel/>
</ContentView.BindingContext>
<StackLayout>
<customRenderes:NavigationImageButton Source="MenuSettings"
x:Name="Button1"
Margin="0"
IsVisible="{Binding Visibility}"/>
And in MyViewModel.cs:
private bool _visibility;
public bool Visibility
{
get => _visibility;
set
{
_visibility = value;
OnPropertyChanged("Visibility");
}
}
So you can deal with any binding you want and use them easily in different pages.
I hope this helps.
How would I reference the Master Detail Page (MenuNavigation) by a clickable button inside of Homepage.xaml.cs and Homepage.xaml?
I want the side menu to appear whenever I click the "menu" button. (see below)
I have tried MasterDetail.isPresentedProperty inside the clicked button event handler in Homepage.xaml.cs and cannot figure it out.
Please help!
MenuNavigation.xaml:
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App2.MenuNavigation"
xmlns:local="clr-namespace:App2">
<!--this is the Menu Hamburger sidebar -->
<MasterDetailPage.Master>
<ContentPage Title="Menu" Padding="20" BackgroundColor="#4B1388" >
<StackLayout Orientation="Vertical">
<Label Text="Menu" TextColor="White" FontSize="Large" FontAttributes="Bold" HorizontalOptions="Center"/>
<Button Text="Home"
TextColor="White" BackgroundColor="#4B1388"
Clicked="Button_Clicked_Home"/> <!-- event handler points to MenuNavigation C# file when button is clicked-->
<Button Text="About"
TextColor="White" BackgroundColor="#4B1388"
Clicked="Button_Clicked_About"/>
<Button Text="Help"
TextColor="White" BackgroundColor="#4B1388"
Clicked="Button_Clicked_Help"/>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
<!--links to the detail pages from the hamburger sidebar -->
<MasterDetailPage.Detail>
</MasterDetailPage.Detail>
MenuNavigation.xaml.cs:
namespace App2
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MenuNavigation : MasterDetailPage
{
public MenuNavigation()
{
InitializeComponent();
//this is for no nav bar at top
var Homepage = new Homepage();
NavigationPage.SetHasNavigationBar(Homepage, false);
Detail = new NavigationPage(Homepage);
IsPresented = false; //this will make the side menu disappear when you select a page
}
private void Button_Clicked_Home(object sender, EventArgs e)
{
var Homepage = new Homepage();
NavigationPage.SetHasNavigationBar(Homepage, false);
Detail = new NavigationPage(Homepage);
IsPresented = false; //this will make the side menu disappear when you select a page
}
private void Button_Clicked_About(object sender, EventArgs e)
{
Detail = new NavigationPage(new About());
IsPresented = false;
}
private void Button_Clicked_Help(object sender, EventArgs e)
{
Detail = new NavigationPage(new Help());
IsPresented = false;
}
}
}
Homepage.xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App2.Homepage"
Title="Homepage">
<Button Text="Menu" Clicked="MasterDetailButton_Pressed"/>
</ContentPage>
Hompage.xaml.cs:
namespace App2
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Homepage : ContentPage
{
public Homepage()
{
InitializeComponent();
VideoListView.ItemsSource = Videos; //allows for binding
}
private void MasterDetailButton_Pressed(object sender, EventArgs e)
{
MasterDetailPage.IsPresentedProperty.Equals(true);
//open the master detail page when button is clicked.
//MasterDetailPage.IsPresentedProperty.Equals(true);
//MenuNavigation.IsPresentedProperty.Equals(true);
}
}
}
You should get a reference of your MasterDetailPage and change the IsPresented property of the reference. As the MasterDetailPage has to be the root of the app, something like this should work: (App.Current.MainPage as MasterDetailPage).IsPresented = true;.
Hope it helps! :)
I am new to Xamarin and I am using ActivityIndicator to say users that app is downloading the data. Problem is that I am using MVVM pattern and I need to set the values IsRunning and IsVisible from ViewModel. I have simple view:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:HmtMobile"
x:Class="HmtMobile.MainPage"
Title="Přihlášení"
>
<ScrollView>
<StackLayout Margin="10" Spacing="15" VerticalOptions="Center">
<ActivityIndicator x:Name="ActivityIndicator" Color="Green" IsRunning="{Binding IsBusy, Mode=TwoWay}" IsVisible="{Binding IsBusy, Mode=TwoWay}"/>
<Entry Placeholder="Uživatelské jméno" Text="{Binding UserName}"></Entry>
<Entry Placeholder="Heslo" Text="{Binding Password}" IsPassword="True"></Entry>
<Button Text="Přihlášení" Command="{Binding LoginCommand}" BackgroundColor="#77D065" TextColor="White"></Button>
</StackLayout>
</ScrollView>
In the view constructor I am assigning the BindingContext
public MainPage()
{
InitializeComponent();
this.BindingContext = new CredentialViewModel(this);
}
Other properties works because when I want to login the properties returns the actual username and password but the twoway binding doesn´t. Properties are declared same so I do not understand why is this happening.
private string password;
public string Password
{
get { return password; }
set { password = value; OnPropertyChanged(); }
}
private bool isBusy;
public bool IsBusy
{
get { return isBusy; }
set { isBusy = value; OnPropertyChanged(); }
}
I am using the simple Login method.
private async Task Login()
{
IsBusy = true;
await Task.Delay(5000);
}
THe ActivityIndicator is not appearing. Does anyone know why? OnPropertyCHanged is coded this way:
public class Bindable
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I figure it out based on Felix message. The problem was that in Bindable class I forgot to add : INotifyPropertyChanged.