.netmauiorientation-changesmaui-community-toolkit

How do I get OnPropertyChanged to trigger on Orientation change by user?


I can get the device orientation and set a value for it in the constructor. It works as expected. But when user changes orientation of device OnChanged event does not trigger. I am probably wrong about how this all works. But I kind of expected the OnChanged event to trigger and update the displayed information when orientation changes?

TabletPodcastViewModel.cs

namespace NerdNewsNavigator2.ViewModel.Tablet;

public partial class TabletPodcastViewModel : ObservableObject
{
    #region Properties
    readonly TwitService _twitService;
    [ObservableProperty]
    int _orientation;
    public ObservableCollection<Podcast> Podcasts { get; set; } = new();
    #endregion
    public TabletPodcastViewModel(TwitService twit)
    {
        this._twitService = twit;
        _ = GetPodcasts();
        this._orientation = OnDeviceOrientationChange();
        System.Diagnostics.Debug.WriteLine("Device orientation is: " + Orientation);
        OnPropertyChanged(nameof(Orientation));
    }

    #region Get the Podcast and set the Podcast List
    async Task GetPodcasts()
    {
        var podcastList = await TwitService.GetListOfPodcasts();
        foreach (var item in podcastList)
        {
            var temp = await Task.FromResult(FeedService.GetFeed(item));
            Podcasts.Add(temp);
        }
    }
    #endregion
    public int OnDeviceOrientationChange()
    {
        if (DeviceDisplay.Current.MainDisplayInfo.Orientation == DisplayOrientation.Portrait) { return 2; }
        else return 3;
    }

    [RelayCommand]
    async Task Tap(string url)
    {
        var encodedUrl = HttpUtility.UrlEncode(url);
        await Shell.Current.GoToAsync($"{nameof(TabletShowPage)}?Url={encodedUrl}");
    }
}

Here is TAbletPodcastPage.xaml.cs

namespace NerdNewsNavigator2.View.Tablet;

public partial class TabletPodcastPage : ContentPage
{
   public TabletPodcastPage(TabletPodcastViewModel viewModel)
    {
        InitializeComponent();
        BindingContext = viewModel;
    }
}

Here is TabletPodcastPage.xaml:

<?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"
             xmlns:model="clr-namespace:NerdNewsNavigator2.Model"
             xmlns:viewmodel="clr-namespace:NerdNewsNavigator2.ViewModel.Tablet"
             x:Class="NerdNewsNavigator2.View.Tablet.TabletPodcastPage"
             x:DataType="viewmodel:TabletPodcastViewModel"
               Shell.NavBarIsVisible="True"
             Title="{Binding Orientation}">
    <Shell.BackButtonBehavior>
        <BackButtonBehavior IsEnabled="True" IsVisible="False"></BackButtonBehavior>
    </Shell.BackButtonBehavior>
    <CollectionView ItemsSource="{Binding Podcasts}" Margin="5" BackgroundColor="White" SelectionMode="None">
        <CollectionView.ItemsLayout>
            <GridItemsLayout Orientation="Vertical" Span="{Binding Orientation}"/>
        </CollectionView.ItemsLayout>
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="model:Podcast">
                <Grid RowDefinitions="30,400,*" ColumnDefinitions="400">
                    <Grid.GestureRecognizers>
                        <TapGestureRecognizer 
                            Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:TabletPodcastViewModel}}, Path=TapCommand}"
                            CommandParameter="{Binding Url}"/>
                    </Grid.GestureRecognizers>
                    <Label  Grid.Row="0"
                        Text="{Binding Title}" 
                        TextColor="Black" 
                            HorizontalTextAlignment="Center"
                        FontSize="16" 
                            FontAttributes="Bold"
                        LineBreakMode="WordWrap"/>
                    <Image Grid.Row="1"
                    Aspect="AspectFit" 
                    MaximumHeightRequest="400" 
                    MaximumWidthRequest="400" 
                    Source="{Binding Image}">
                    </Image>
                    <Label Grid.Row="2"
                           Margin="5"
                           Text="{Binding Description}" 
                           FontSize="12" 
                           TextColor="Black" 
                           LineBreakMode="WordWrap"/>
                </Grid>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

Solution

  • After reading ToolkitmakerSteve's comment I went and found the doc for Orientation changes, I then figured out how to get it working!

    Here is fixed TabletPodcastViewModel.cs:

    // Licensed to the .NET Foundation under one or more agreements.
    // The .NET Foundation licenses this file to you under the MIT license.
    // See the LICENSE file in the project root for more information.
    
    
    namespace NerdNewsNavigator2.ViewModel.Tablet;
    
    public partial class TabletPodcastViewModel : ObservableObject
    {
        #region Properties
        readonly TwitService _twitService;
        [ObservableProperty]
        int _orientation;
        private DisplayInfo MyMainDisplay { get; set; } = new();
    
        public ObservableCollection<Podcast> Podcasts { get; set; } = new();
        #endregion
        public TabletPodcastViewModel(TwitService twit)
        {
            this._twitService = twit;
            _ = GetPodcasts();
            DeviceDisplay.MainDisplayInfoChanged += DeviceDisplay_MainDisplayInfoChanged;
            this._orientation = OnDeviceOrientationChange();
          //  System.Diagnostics.Debug.WriteLine("Device orientation is: " + Orientation);
            OnPropertyChanged(nameof(Orientation));
        }
    
        #region Get the Podcast and set the Podcast List
        async Task GetPodcasts()
        {
            var podcastList = await TwitService.GetListOfPodcasts();
            foreach (var item in podcastList)
            {
                var temp = await Task.FromResult(FeedService.GetFeed(item));
                Podcasts.Add(temp);
            }
        }
        #endregion
        private void DeviceDisplay_MainDisplayInfoChanged(object? sender, DisplayInfoChangedEventArgs e)
        {
            MyMainDisplay = DeviceDisplay.Current.MainDisplayInfo;
            OnPropertyChanged(nameof(MyMainDisplay));
            Orientation = OnDeviceOrientationChange();
            OnPropertyChanged(nameof(Orientation));
            System.Diagnostics.Debug.WriteLine("Device orientation is: " + Orientation);
        }
        public int OnDeviceOrientationChange()
        {
            if (DeviceDisplay.Current.MainDisplayInfo.Orientation == DisplayOrientation.Portrait) { return 2; }
            else return 3;
        }
    
        [RelayCommand]
        async Task Tap(string url)
        {
            var encodedUrl = HttpUtility.UrlEncode(url);
            await Shell.Current.GoToAsync($"{nameof(TabletShowPage)}?Url={encodedUrl}");
        }
    }
    

    Here is TabletPodcastPage.xaml:

    <?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"
                 xmlns:model="clr-namespace:NerdNewsNavigator2.Model"
                 xmlns:viewmodel="clr-namespace:NerdNewsNavigator2.ViewModel.Tablet"
                 x:Class="NerdNewsNavigator2.View.Tablet.TabletPodcastPage"
                 x:DataType="viewmodel:TabletPodcastViewModel"
                   Shell.NavBarIsVisible="False"
                 Title="">
        <Shell.BackButtonBehavior>
            <BackButtonBehavior IsEnabled="True" IsVisible="False"></BackButtonBehavior>
        </Shell.BackButtonBehavior>
        <CollectionView ItemsSource="{Binding Podcasts}" Margin="5" BackgroundColor="White" SelectionMode="None">
            <CollectionView.ItemsLayout>
                <GridItemsLayout Orientation="Vertical" Span="{Binding Orientation}"/>
            </CollectionView.ItemsLayout>
            <CollectionView.ItemTemplate>
                <DataTemplate x:DataType="model:Podcast">
                    <Grid RowDefinitions="30,400,*" ColumnDefinitions="400">
                        <Grid.GestureRecognizers>
                            <TapGestureRecognizer 
                                Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:TabletPodcastViewModel}}, Path=TapCommand}"
                                CommandParameter="{Binding Url}"/>
                        </Grid.GestureRecognizers>
                        <Label  Grid.Row="0"
                            Text="{Binding Title}" 
                            TextColor="Black" 
                                HorizontalTextAlignment="Center"
                            FontSize="16" 
                                FontAttributes="Bold"
                            LineBreakMode="WordWrap"/>
                        <Image Grid.Row="1"
                        Aspect="AspectFit" 
                        MaximumHeightRequest="400" 
                        MaximumWidthRequest="400" 
                        Source="{Binding Image}">
                        </Image>
                        <Label Grid.Row="2"
                               Margin="5"
                               Text="{Binding Description}" 
                               FontSize="12" 
                               TextColor="Black" 
                               LineBreakMode="WordWrap"/>
                    </Grid>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </ContentPage>
    

    This is working for detecting device orientation changes and applying numerical changes to span in GridItemsLayout! TY so much for the suggestion. I have been banging my head against a virtual wall trying to figure this out. I was at a loss as to how to go about figuring out what I needed to do.