I've got an app that I am porting over to Maui from XF. I have a toolbaritem in my navigationbar. Here is the basic definition:
<ContentPage.ToolbarItems>
<ToolbarItem Text="New Game" Clicked="NewGame_Clicked" x:Name="NewGame" />
</ContentPage.ToolbarItems>
<VerticalStackLayout><ListView........./></VerticalStackLayout>
Here is my NewGame_Clicked Event:
private void NewGame_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new EventSetupPage());
}
Here is the content of the EventSetupPage() overly simplified:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ScanAndScoringMauiApp.Pages.EventSetupPage"
Title="EventSetupPage">
<VerticalStackLayout>
<Label
Text="Welcome to .NET MAUI!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
When the EventSetupPage() comes up, it is blank in an android 12 emulator. The constructor is called, so I know that something is happening. It's like the page is being loaded in the wrong thread. I'm doing something wrong. Any thoughts on what I should do to get my page to load? TIA
********** update 1 ************
As an fyi, I am loading the parent page via a messagecenter message. I do this in my xamarin forms app.
MessagingCenter.Subscribe<string>(this, "UpdateMainPage", (sender) =>
{
MainThread.BeginInvokeOnMainThread(() =>
{
MainPage = new NavigationPage(new GameList());
});
});
Related
How do I pass data to a CommunityToolkit Popup in a .Net MAUI app?
Documentation shows how to send a result from Popup back to the page but doesn’t show how to pass data to the Popup.
I made the following Based on Gerald Versluis video:
toolkit popup Xaml:
<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:model="modelnamespace"
x:Class="namespace.PopUpSelectService">
<VerticalStackLayout>
<CollectionView x:Name="selectService"
HorizontalOptions="Center"
VerticalOptions="Center">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:sal_ServiceResponse">
<Grid RowDefinitions="auto,auto,auto,auto,auto">
<Button Text="{Binding nombre_servicio}"
Grid.Row="0"
Clicked="Button_Clicked" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
</toolkit:Popup>
PopupSelectService .cs
public partial class PopUpSelectService
{
public PopUpSelectService(List<salServiceDTO> sal_Service)
{
InitializeComponent();
selectService.ItemsSource = sal_Service;
}
private void Button_Clicked(object sender, EventArgs e)
{
this.Close(((Button)sender).Text);
}
}
How i call the popup In my viewmodel:
var popup = new PopUpSelectService(response.sal_Service);
var result = await Shell.Current.ShowPopupAsync(popup);
and also in var result you get the value you select on the popup!
I am having trouble getting data binding to work with custom components.
I have created an IncrementValue property that gets incremented with every button click.
The changes are reflected when binded to a Label.
However they do not work when I bind it to a Bindable property in a custom component.
In the example, I have built a custom component called Card which has two bindable properties CardTitle and CardIncrement
Is there something I'm missing as I'm new to MAUI and even Xamarin.
Github link of code snippets below: https://github.com/814k31/DataBindingExample
Card.xaml.cs
namespace DataBindingExample;
public partial class Card : VerticalStackLayout
{
public static readonly BindableProperty CardTitleProperty = BindableProperty.Create(nameof(CardTitle), typeof(string), typeof(Card), string.Empty);
public static readonly BindableProperty CardIncrementProperty = BindableProperty.Create(nameof(CardIncrement), typeof(int), typeof(Card), 0);
public string CardTitle
{
get => (string)GetValue(CardTitleProperty);
set => SetValue(CardTitleProperty, value);
}
public int CardIncrement
{
get => (int)GetValue(CardIncrementProperty);
set => SetValue(CardIncrementProperty, value);
}
public Card()
{
InitializeComponent();
BindingContext = this;
}
}
Card.xaml
<?xml version="1.0" encoding="utf-8" ?>
<VerticalStackLayout
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:databindingexample="clr-namespace:DataBindingExample"
x:DataType="databindingexample:Card"
x:Class="DataBindingExample.Card"
Spacing="25"
Padding="30,0"
VerticalOptions="Center"
BackgroundColor="red"
>
<Label
Text="{Binding CardTitle}"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center"
/>
<Label
Text="{Binding CardIncrement}"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center"
/>
</VerticalStackLayout>
MainPage.xml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DataBindingExample.MainPage"
xmlns:DataBindingExample="clr-namespace:DataBindingExample"
xmlns:ViewModels="clr-namespace:DataBindingExample.ViewModels"
x:DataType="ViewModels:MainPageViewModel"
>
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center"
>
<Label
Text="{Binding IncrementedValue}"
SemanticProperties.HeadingLevel="Level2"
FontSize="18"
HorizontalOptions="Center"
/>
<!-- Why doesnt this work? -->
<DataBindingExample:Card CardIncrement="{Binding IncrementedValue}" />
<Button
x:Name="CounterBtn"
Text="Click Me"
SemanticProperties.Hint="Counts the number of times you click"
Command="{Binding IncrementValueCommand}"
HorizontalOptions="Center"
/>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
When making a custom component (that includes XAML), DO NOT set BindingContext = this;.
REASON: You want the component to use the SAME BindingContext as the page it is placed in. This happens automatically, if you do NOT set a BindingContext in the custom component.
HOWEVER, removing this line breaks all your component's xaml Bindings; you'll need to add something to the xaml, to fix this.
Or to put it another way: How refer to the card's Properties from its XAML? See the next section.
ACCESS COMPONENT PROPERTIES VIA x:Name
Solution: Give the card an x:Name, and make that the "Source" of those bindings:
<VerticalStackLayout
...
x:Name="me" <-- IMPORTANT! Change name as desired.
x:Class="DataBindingExample.Card"
>
...
<Label Text={Binding CardIncrement, Source={x:Reference me}}"
...
Notice the two parts to this solution:
In component's xaml header, define x:Name="mynamehere".
In each Binding, say that the component is the source:
, Source={x:Reference mynamehere}.
OPTIONAL: If custom component has a "ViewModel":
To have a custom component be "data-driven", pass in a parameter that controls its behavior.
This parameter could be considered a "ViewModel", but above I have specified:
DO NOT set a BindingContext (so that component has easy access to the page's BindingContext).
So unlike other uses of ViewModel, in this technique, we don't set the ViewModel as the BindingContext.
How access this ViewModel?
By saving it as a property of the component; e.g.:
public partial class MyComponent : ContentView
{
private MyViewModel VM;
public void MyComponent(MyViewModel vm)
{
InitializeComponent();
VM = vm;
}
public class MyViewModel : ObservableObject
{
[ObservableProperty]
SomeType someProperty; // This is field. Property "SomeProperty" is generated.
}
Then in xaml, we access properties of VM, using . notation:
<Label Text={Binding VM.SomeProperty, Source={x:Reference me}}"
I have used a litle XamarinForms before and then i did a
naming to be able to point the c# code to it.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiTest.MainPage"
BackgroundColor="{DynamicResource SecondaryColor}">
<StackLayout x:name="_stacklayoutname">
<Label Text="" x:Name="_Lable"/>
</StackLayout>
</ContentPage>
And then i did like this in the MainPage.xaml.cs
public MainPage()
{
InitializeComponent();
_stacklayoutname.Children.Add(new Label { Text = "TEST" });
_Lable.Text = "TEST";
}
now it get this, but i can change the _Lable to "Text".
how can i point to a stacklayout.
Severity Code Description Project File Line Suppression State
Error CS0103 The name '_stacklayoutname' does not exist in the current context MauiTest (net6.0-android), MauiTest (net6.0-ios), MauiTest (net6.0-maccatalyst), MauiTest (net6.0-windows10.0.19041) *** 11 Active
this is wrong
<StackLayout x:name="_stacklayoutname">
it should be
<StackLayout x:Name="_stacklayoutname">
I want to use compiled bindings in my Xamarin Forms app in combination with Prism.
I created a small xamarin forms app with a simple view, viewmodel and prism (prism:ViewModelLocator.AutowireViewModel="True"). Classic binding works as expected.
How should I implemented compiled binding without creating the binding context twice?
Classic binding with prism: HomePage.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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="CompiledBinding.Views.HomePage">
<StackLayout>
<!-- Place new controls here -->
<Label Text="{Binding Name}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
HomePageViewModel.cs:
using Prism.Mvvm;
using Prism.Navigation;
using System;
using Xamarin.Forms;
namespace CompiledBinding.ViewModels
{
public class HomePageViewModel : BindableBase
{
string _name = "Compiled binding test";
public HomePageViewModel(INavigationService navigationService)
{
var nav = navigationService;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
// Do something
Name = DateTime.Now.ToString("yyyy MMMM dd hh:mm:ss");
return true; // True = Repeat again, False = Stop the timer
});
}
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
}
}
Adding the binding context to the xaml page again, is not an option:
<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
xmlns:viewModels="clr-namespace:CompiledBinding.ViewModels"
x:Class="CompiledBinding.Views.HomePage"
x:DataType="viewModels:HomePageViewModel">
<ContentPage.BindingContext>
<viewModels:HomePageViewModel />
</ContentPage.BindingContext>
<StackLayout>
<!-- Place new controls here -->
<Label Text="{Binding Name}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
Besides of defining the binding context again, it also results in the error: no public parameterless constructor.
Do I oversee something? Does anyone know how to work with compiled bindings together with prism?
I have four tabbed pages (Amazon, Google, and eBay), while the last one is my HomePage. The HomePage has a user entry with a search button below. I want to have the users input be searched on all three web pages(tabbed pages) at the same time. Is there anyway to pass the "entry/input" into the other three pages url? Ex. "(-) + (user entry)" . If someone wants to purchase a new laptop for instance... The first page would take the input and add it to the URL of each page. .... Essentially, webview=("https://www.google.com/" + laptops) and so on for the other two tabbed pages. Hope I explained my question well enough! Thank you all way in advance!!!!
====This is my HomePage.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="App2.HomePage"
Title="Home">
<ContentPage.Content>
<StackLayout>
<Label Text="Home Page"
VerticalOptions="StartAndExpand"
HorizontalOptions="CenterAndExpand"/>
<Entry x:Name="search1" VerticalOptions="Fill"
HorizontalOptions="Fill"/>
<Button Clicked="Button_Clicked_1" Text="Search"
VerticalOptions="Fill" HorizontalOptions="Center"/>
<Entry x:Name="sms" VerticalOptions="FillAndExpand"
HorizontalOptions="Fill"/>
<Button Clicked="Button_Clicked"
Text="Send Text" HorizontalOptions="Center"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
===This is my HomePage.Xaml.cs===
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace App2
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class HomePage : ContentPage
{
public HomePage()
{
InitializeComponent();
}
public void Button_Clicked(object sender, EventArgs e)
{
string text = sms.Text;
}
public void Button_Clicked_1(object sender, EventArgs e)
{
string text = search1.Text;
}
}
}
===This is my Google.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="App2.Views.Google"
xmlns:Content="clr-namespace:App2.Views.HomePage"
Title="Google">
<StackLayout>
<StackLayout Orientation="Horizontal">
<Button Text="<" HeightRequest="40" WidthRequest="45"
Clicked="Back_Clicked"/>
<Button Text=">" HeightRequest="40" WidthRequest="45"
Clicked="Forward_Clicked"/>
<Entry x:Name="URL" WidthRequest="197"/>
<Button Text="Go" HeightRequest="40" WidthRequest="55"
Clicked="Go_Clicked"/>
</StackLayout>
<Label x:Name="LoadingLabel" IsVisible="False"/>
<WebView x:Name="Googlepage" HeightRequest="1000"
WidthRequest="1000"/>
</StackLayout>
</ContentPage>
===This is my Google.xaml.cs===
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using App2.Views;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace App2.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Google : ContentPage
{
public Google()
{
InitializeComponent();
URL.Text = ("https://www.google.com/");
Googlepage.Source = "URL.Text";
}
private void Back_Clicked(object sender, EventArgs e)
{
if (Googlepage.CanGoBack)
Googlepage.GoBack();
}
private void Forward_Clicked(object sender, EventArgs e)
{
if (Googlepage.CanGoForward)
Googlepage.GoForward();
}
private void Go_Clicked(object sender, EventArgs e)
{
Googlepage.Source = URL.Text;
}
}
}
There are definitely other ways to do it but one way that comes to mind is a static variable which contains the search text. Then when your user clicks on each tabbed page, when that page loads, just perform the specific search URL including the search text from the static variable.