I'm quite a noob in MAUI and I'm developing an app for android and iOS. I have a simple ContentView which is just a banner with a switch that I'm including in several of my app's pages. My xaml looks like this:
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyApp.Partials"
x:Class="MyApp.Partials.Banner"
x:DataType="local:Banner"
x:Name="BannerView">
<Grid BackgroundColor="Yellow">
<HorizontalStackLayout
HorizontalOptions="CenterAndExpand"
VerticalOptions="Center">
<Image Source="smartphone.png" HeightRequest="40" Aspect="AspectFit" />
<Switch IsToggled="{Binding Source={x:Reference BannerView}, Path=IsSwitchToggled}" />
<Image Source="lightning.png" HeightRequest="40" Aspect="AspectFit" />
</HorizontalStackLayout>
</Grid>
</ContentView>
And the code behind:
public partial class Banner : ContentView
{
public Banner()
{
InitializeComponent();
}
public bool IsSwitchToggled
{
get => (bool)GetValue(IsSwitchToggledProperty);
set => SetValue(IsSwitchToggledProperty, value);
}
public static readonly BindableProperty IsSwitchToggledProperty = BindableProperty.Create(
nameof(IsSwitchToggled),
typeof(bool),
typeof(Banner),
false,
propertyChanged: OnIsSwitchToggled);
static void OnIsSwitchToggled(BindableObject bindable, object oldValue, object newValue)
{
Console.WriteLine("Toggle value: " + newValue);
}
}
Then I include it in my other xaml pages:
<StackLayout>
<partials:Banner />
<Label Text="Mainpage" />
</StackLayout>
Later I want this switch to control the color of the app (one specific color if the switch is set to false and another one if set to true). My issue is that I would like the value of the switch to be maintained across different pages, but I am not sure if a Bindable Property is the right way to approach the problem to begin with.
My first approach was a bit different. I had a class with my boolean in it:
public class SharedData : INotifyPropertyChanged
{
private bool _isSwitchToggled;
public bool IsSwitchToggled
{
get { return _isSwitchToggled; }
set
{
if (_isSwitchToggled != value)
{
_isSwitchToggled = value;
OnPropertyChanged(nameof(IsSwitchToggled));
}
}
}
// Other stuff
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
But I hit a wall when I realized ContentView constructors could not be passed parameters.
I have more of a React background so I guess what I'm asking is a bit like a React context to pass data around. Thanks!
Your question is worded to be about Sharing data from a ContentView across pages but what I'm really picking up on is when you mention this objective:
I want this switch to control the color of the app.
So, I'm choosing to go straight for the "Y Problem" which will also provide one way to deal with the more general case. In terms of the app colors, the default Maui project template comes with dynamic themes for Light and Dark which can be customized to your liking in the Styles.xaml file. So in the first approximation, we just tap into that mechanism and get to go home early:
public partial class Banner : ContentView
{
public Banner() => InitializeComponent();
public bool IsSwitchToggled
{
get => _isSwitchToggled;
set
{
if (!Equals(_isSwitchToggled, value))
{
_isSwitchToggled = value;
if (App.Current is App app)
{
app.UserAppTheme =
_isSwitchToggled ?
AppTheme.Dark :
AppTheme.Light;
}
OnPropertyChanged();
}
}
}
bool _isSwitchToggled = default;
}
Custom Theme Intercept
Another option you have is to intercept that property to inject your own theme.
enum CustomAppTheme
{
Light,
Dark,
Warm,
}
public partial class Banner : ContentView
{
public Banner() => InitializeComponent();
public bool IsSwitchToggled
{
get => _isSwitchToggled;
set
{
if (!Equals(_isSwitchToggled, value))
{
_isSwitchToggled = value;
if (App.Current is App app)
{
app.UserAppTheme =
_isSwitchToggled ?
CustomAppTheme.Warm :
CustomAppTheme.Light;
}
OnPropertyChanged();
}
}
}
bool _isSwitchToggled = default;
}
In the general sense of sharing the data switch toggle, that action will come here. One of several options at this point would be to bind to UserAppTheme
property that's being notified here at the App
level, and have the various child pages respond perhaps by reassigning the Style
properties of the page's views to accomodate the change.
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
public new Enum UserAppTheme
{
get => _userAppTheme;
set
{
if (!Equals(_userAppTheme, value))
{
_userAppTheme = value;
switch (value)
{
case AppTheme.Light:
case CustomAppTheme.Light:
base.UserAppTheme = AppTheme.Light;
break;
case AppTheme.Dark:
case CustomAppTheme.Dark:
base.UserAppTheme = AppTheme.Dark;
break;
default:
_ = MainPage?.DisplayAlert("ThemeChange", $"{value}", "OK");
break;
}
OnPropertyChanged();
}
}
}
Enum _userAppTheme = AppTheme.Light;
}
I should mention the fact that the OS already provides a way for user to switch between Light and Dark modes of course. And so, if the main goal is to set unique color palettes for your app with some accomodation for "two settings", it sometimes suffices to just go through Styles.xaml file and adjust your static resources accordingly.