I have a DashboardPage in Xamarin Forms where I "inject" another 3 views with the following method:
<StackLayout IsVisible="{Binding IsDashboardItemVisible}">
<views:FirstView/>
<views:SecondView/>
<views:ThirdView/>
</StackLayout>
All of these views have their viewmodels (FirstViewModel, SecondViewModel, ThirdViewModel).
Every view have an Init method binded to the OnAppearing() event with the following appearance (xct is the Community Toolkit what I use):
<ContentPage.Behaviors>
<xct:EventToCommandBehavior EventName="Appearing" Command="{Binding RefreshCommand}" />
</ContentPage.Behaviors>
So in my xaml.cs the OnAppearing() is not overridden, but the FirstViewModel, SecondViewModel, ThirdViewModel has an ICommand what is connected with the RefreshAsync method.
public IAsyncCommand RefreshCommand { get; set; }
RefreshCommand = new AsyncCommand(RefreshAsync);
public async Task RefreshAsync()
{
...do the refresh logic...
}
So here are my questions:
In this scenario the 3 "injected" view will be loaded parallel or FirstView first, SecondView second, etc?
What is the best practice to communicate between this seperated views? For example when an user triggers a method on the FirstViewModel I would like to change something on the ThirdView (or ThirdViewModel). I read about the MessagingCenter, but I don't know if that is the best opportunity.
Related
I have a page for playing songs in my project. When I go back to the previous page after playing a song (without pausing it), it will continue to play in the background, and users can pause it at any time from the notification bar. I am using Plugin.MediaManager (Version: 1.1.1) for the integration of songs.
Current song screens on my App
But we have a new suggestion, like playing the songs in the app itself on top or bottom on all the other pages (like WhatsApp). Our application has more than 100 pages, so adding the audio player on all these pages is a tedious task. So any other tricky way to implement it on all the pages by reusing it or any other better solution for this feature?
The expected feature is like the below one, like WhatsApp
If you have a common TabbedPage such as the screenshot you attached of Whatsapp, you could add at the beginning of its xaml file before the definition of the views:
<NavigationPage.TitleView>
<StackLayout>
...
</StackLayout>
</NavigationPage.TitleView>
That way you will have a common Navigation view on top of all of them with custom data that you could modify in the associated xaml.cs file of that TabbedPage.
If you have a different structure for your views you could check the documentation for Control Templates in Xamarin Forms, and include it in your App.xaml.
Good luck!
We implemented this using a pop-up page.
XAML:
<StackLayout
HorizontalOptions="Center"
VerticalOptions="End">
<mm:VideoView
Grid.Column="0"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
AutoPlay="True"
IsVisible="True"
x:Name="audioplayer"
ShowControls="True">
<mm:VideoView.HeightRequest>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Phone>80</OnIdiom.Phone>
<OnIdiom.Tablet>120</OnIdiom.Tablet>
<OnIdiom.Desktop>80</OnIdiom.Desktop>
</OnIdiom>
</mm:VideoView.HeightRequest>
</mm:VideoView>
</StackLayout>
XAML.CS
public partial class AudioPopupPage : PopupPage
{
public AudioPopupPage(object source)
{
InitializeComponent();
if (source != null)
{
audioplayer.Source = source;
}
}
protected override bool OnBackgroundClicked()
{
BackgroundInputTransparent = true;
return false;
}
}
We call the pop-up page when we leave the song page.
protected override bool OnBackButtonPressed()
{
PopupNavigation.Instance.PushAsync(new Views.AudioPopupPage(CrossMediaManager.Current.State), true);
return base.OnBackButtonPressed();
}
With this approach, this audio player is showing on all pages, and it is working fine on all platforms.
I have an ICommand in my PageViewModel and want it to be call in my CheckedChanged of RadioButton. However, this RadioButton is inside:
<views:RoundedPage>
<Carousel ItemSource="...">
<DataTemplate DataType="...">
<CollectionView ItemSource="...">
<DataTemplate DataType="...">
<RadioButton CheckedChanged="" />
</DataTemplate>
</CollectionView>
</DataTemplate>
</Carousel>
</views:RoundedPage>
So how am I gonna call this command outside those sources.
Thank you
At first, I don't recommend you to deal with the UI event in your view model. The view model is used to resolve the logic behavior behand the view.
So you can set the CheckedChanged event by the following method:
1.create a void method in the page.cs, such as
private void RadioButton_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
//do something
}
2.binding in the xaml
<RadioButton CheckedChanged="RadioButton_CheckedChanged"/>
If you still want to deal with the event in the viewmodel, you need to use the behavior to covert the event to a command.
There is a simple in the official document and you can check it:
https://learn.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/behaviors-eventtocommandbehavior/
I am trying to pass ObservableCollection from the XAML Page to the UserControl.
In a normal Visual Studio WPF project .NET Framework 4.8, within the UserControl the below XAML code works fine and the data can be seen within the Page.
<DataGrid Grid.Row="0" x:Name="dgAuthors" ItemsSource="{Binding Authors, RelativeSource= RelativeSource Mode=FindAncestor, AncestorType=local:UserControl1}}
Code behind of User Control as below:
public UserControl1()
{
InitializeComponent();
dgAuthors.DataContext = this;
}
public ObservableCollection<Author> Authors
{
get { return (ObservableCollection<Author>)GetValue(AuthorsProperty); }
set { SetValue(AuthorsProperty, value); }
}
// Using a DependencyProperty as the backing store for Authors. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AuthorsProperty =
DependencyProperty.Register("Authors", typeof(ObservableCollection<Author>), typeof(UserControl1), null);
But in UNO for .NET 5.0 framework, it is unable to find the Mode=FindAncestor and AncestorType when Binding is used within the ItemSource of the DataGrid.
Any help would be highly appreciated.
Many thanks
Neeraj
With the WinUI flavour of XAML used by Uno Platform, you can use x:Bind syntax to bind to a property in code-behind:
<DataGrid Grid.Row="0" x:Name="dgAuthors" ItemsSource="{x:Bind Authors, Mode=OneWay}} />
When I use -
string result = await DisplayPromptAsync("Question 1", "What's your name?");
It shows only one textbox in the pop-up. But how to display two or more textboxes in the pop-up?
Any help would be greatly appreciated.
As IvanIčin said that you can use Rg.Plugins.Popup to create custom popup.
Firstly, install Rg.Plugins.Popup bu nuget package..., then creating popup page
<pages:PopupPage
x:Class="FormsSample.popup.popup2"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup">
<pages:PopupPage.Content>
<StackLayout
Padding="20,0"
BackgroundColor="CadetBlue"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center">
<Label Text="Question 1" />
<Label Text="this is one question!" />
<Entry />
<Entry />
<Button
x:Name="btnsub"
Clicked="btnsub_Clicked"
Text="subit" />
</StackLayout>
</pages:PopupPage.Content>
</pages:PopupPage>
public partial class popup2 : PopupPage
{
public popup2()
{
InitializeComponent();
}
private void btnsub_Clicked(object sender, EventArgs e)
{
}
}
To call this Popup Page from contentpage button.click event.
private async void btnPopupButton_Clicked(object sender, EventArgs e)
{
await PopupNavigation.Instance.PushAsync(new popup2());
}
You can see the screenshot:
You can't as it is not intended to. You can create a custom pop-up either by using some pop-up plug-in or by creating your custom code based on the native prompts (similar to what Xamarin.Forms do).
Just for the record having one input field is very generous from Xamarin as the native Android or iOS developers don't have such a prompt with the input field out of the box (though it isn't too hard to create it but still it goes much beyond one line of code).
In my app there is a certain listview that I use over and over in my app, only with different elements in it. Therefore, I put everything inside a contentview and inflated it in my xaml like so:
<ContentPage Title="Newbies" BackgroundColor="#fafafa">
<views:CV_AllAdsRes />
</ContentPage>
The class looks like this:
public partial class CV_AllAdsRes : ContentView
{
public CV_AllAdsRes(int id)
{
InitializeComponent();
SetAds();
}
}
Now, this doenst work, because I am not using a "default constructor". If I remove the "int id" from the constructor, it works no problem. But I need to be able to inflate this content view with different parameters inside the xaml.
Am I understanding this concept wrong?
How can I inflate my content view and give it parameters via xaml?
Thank you
I solved it by using a second constructor next to the default one and giving it arguments from xaml like so:
<views:CV_AllAdsRes >
<x:Arguments >
<x:Int32>5</x:Int32>
</x:Arguments>
</views:CV_AllAdsRes>
this will give ID=5.