combine the titlebaar behavior with code behind

Eduardo Gomez Romero 1,355 Reputation points
2024-12-08T20:56:44.65+00:00

I made a title bar class, that inherits from title bar, which is a new control introduced, in .net 9

namespace METROWIND
{
    public class AppTitleBar: TitleBar
    {
        public SfComboBox ComboBox { get; set; }

        public AppTitleBar()
        {
            ComboBox = CreateComboBox()!;

            Icon = "icon_win.png";
            Title = "METROWIND";
            BackgroundColor = Color.FromArgb("#FF3C155F");
            HeightRequest = 48;
            Content = ComboBox;
        }

        private SfComboBox? CreateComboBox()
        {
            return new SfComboBox
            {
                Margin = new Thickness(5),
                IsEditable = true,
                IsClearButtonVisible = false,
                HighlightedTextColor = Colors.Red,
                HighlightedTextFontAttributes = FontAttributes.Bold,
                IsFilteringEnabled = true,
                TextHighlightMode = OccurrenceMode.MultipleOccurrence
            };
        }

        public void UpdateItemSource(
            IEnumerable<object> itemSouce,
            string displayMemberPath,
            string textMemberPath)
        {
            ComboBox!.ItemsSource = itemSouce;
            ComboBox!.DisplayMemberPath = displayMemberPath;
            ComboBox.TextMemberPath = textMemberPath;
        }
    }
}


I also created a method for update the itemsouce and the bindigns

Explanation

As you can see, every page has their own title bar

public partial class TurbinesCollectionPage: ContentPage
{
    public TurbinesCollectionPageViewModel PageViewModel { get; }

    public TurbinesCollectionPage(TurbinesCollectionPageViewModel
        turbinesCollectionPageViewModel)
    {
        InitializeComponent();

        PageViewModel = turbinesCollectionPageViewModel;

        PageViewModel.ColletionComboBox = combobox;
        PageViewModel.TurbinesCollection = TurbineCollection;

        BindingContext = turbinesCollectionPageViewModel;

        var tb = new AppTitleBar();
        tb.UpdateItemSource(PageViewModel.TurbinePins,
            "Turbine.Name", "Turbine.Name");
        App.WindowInstance!.TitleBar = tb;
        PageViewModel.ColletionComboBox = tb.ComboBox;
        tb.ComboBox.SelectionChanged += ComboBox_SelectionChanged;


        DeviceHelper.AddOrRemoveContentBasedOnDevice(MobileContent);

    }

    private void ComboBox_SelectionChanged(object? sender,
        Syncfusion.Maui.Inputs.SelectionChangedEventArgs e)
    {
        PageViewModel.SelectedItemChangeCommand.Execute(null);

        combobox.SelectedValue = string.Empty;
    }
}


This page has a combobox, that is used by mobile, to pick the turbine

<ContentPage
    x:Class="METROWIND.Views.TurbinesCollectionPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:editors="clr-namespace:Syncfusion.Maui.Inputs;assembly=Syncfusion.Maui.Inputs"
    xmlns:fonts="clr-namespace:METROWIND.Constants"
    xmlns:inputLayout="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core"
    xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    xmlns:model="clr-namespace:METROWIND.Models"
    xmlns:rex="clr-namespace:METROWIND.Resources"
    xmlns:vm="clr-namespace:METROWIND.ViewModel"
    x:Name="CollectionPage"
    x:DataType="vm:TurbinesCollectionPageViewModel"
    HideSoftInputOnTapped="True">

    <VerticalStackLayout Spacing="-20">
        <inputLayout:SfTextInputLayout
            x:Name="MobileContent"
            Style="{x:StaticResource TurbineCollectionComboBoxStyle}">
            <editors:SfComboBox
                x:Name="combobox"
                DisplayMemberPath="Turbine.Name"
                ItemsSource="{x:Binding TurbinePins}"
                Style="{x:DynamicResource TurbinesCollectionComboBoxStyle}">
                <editors:SfComboBox.Behaviors>
                    <mct:EventToCommandBehavior
                        Command="{x:Binding SelectedItemChangeCommand}"
                        EventName="SelectionChanged" />
                </editors:SfComboBox.Behaviors>
            </editors:SfComboBox>
        </inputLayout:SfTextInputLayout>

and a viewModel, to handle the logic

    public partial class TurbinesCollectionPageViewModel(
        ITurbineService turbineService,
        IAppService appService,
        IServiceProvider serviceProvider,
        ICommandHandler commandHandler,
        IConnectivity connectivity,
        NoInternetPopUp noInternetPopUp):
        AppShellViewModel(turbineService, appService, serviceProvider,
            commandHandler, connectivity, noInternetPopUp)
    {
        public CollectionView? TurbinesCollection;
        public SfComboBox? ColletionComboBox;

        [ObservableProperty]
        Turbine? turbine;

        [RelayCommand]
        async Task SelectedItemChange()
        {
            if (ColletionComboBox!.SelectedIndex == -1)
            {
                return;
            }

            var item = TurbinePins.ElementAt(
                ColletionComboBox.SelectedIndex);

            TurbinesCollection?.ScrollTo(ColletionComboBox.SelectedIndex,
                -1, ScrollToPosition.Center);

            var inputView = ColletionComboBox.Children[1] as Entry;

#if ANDROID || IOS
            if (KeyboardExtensions.IsSoftKeyboardShowing(inputView!))
            {
                await Task.Delay(200);
                await inputView!.HideKeyboardAsync(default);
            }
#else
            await Task.CompletedTask;
#endif
        }

The Question

As you can see, I have a title bar on this page, that does the exact as viewmodel. I need a way to remove the one from the code behind.

The potential problem that I face, is that I have 2 conboboxes, so I need to use the sae one for both

Developer technologies | .NET | .NET MAUI
{count} votes

Accepted answer
  1. Anonymous
    2024-12-10T03:04:54.5666667+00:00

    Hello,

    ============Update==============

    so what I want to do is to remove this,

    If you move the AppTitleBar from layout background code to the TurbinesCollectionPageViewModel. I create a TurbinesCollectionPageViewModel's constructor, and move the code in it. You can refer to the following code.

    public partial class TurbinesCollectionPageViewModel
         : ChargingStationsMapPageViewModel{
     
         public TurbinesCollectionPageViewModel(TurbinesService turbinesService) : base(turbinesService)
         {
             var tb = new AppTitleBar();
             tb.UpdateItemSource(TurbinePins,
                 "Turbine.Name", "Turbine.Name");
             App.WindowInstance!.TitleBar = tb;
             ColletionComboBox = tb.ComboBox;
             tb.ComboBox.SelectionChanged += ComboBox_SelectionChanged;
         }
         private async void ComboBox_SelectionChanged(object? sender,
       Syncfusion.Maui.Inputs.SelectionChangedEventArgs e)
         {
     
             if (sender is SfComboBox comboBox
    && comboBox.SelectedValue is TurbinePin selectedPin)
             {
                 // Zoom into the selected turbine's location
                 ItemSelectedCommand.Execute(selectedPin.Turbine);
     
                 // Wait for a short duration before navigation
                 await Task.Delay(1000);
     
                 // Navigate to the turbine detail page
                 PinMarkerClicked(selectedPin);
                 
                 comboBox.SelectedItem = string.Empty;
             }
         }
    

    Based on your description, The custom AppTitleBar and <inputLayout:SfTextInputLayout> will work for different platforms. You cannot remove them easily.

    However, you can use custom them for different platforms.

    You can control inputLayout:SfTextInputLayout.IsVisible by platforms, for Android and iOS, you can set IsVisible to true. For Windows platform, you can set IsVisible to false. You can refer to the following code.

    <inputLayout:SfTextInputLayout
    x:Name="MobileContent"
    Style="{x:StaticResource TurbineCollectionComboBoxStyle}">
    
     <inputLayout:SfTextInputLayout.IsVisible>
              <OnPlatform x:TypeArguments="x:Boolean">
                   <On Platform="iOS" Value="true" />
                   <On Platform="Android" Value="true" />
                   <On Platform="Windows" Value="false" />
               </OnPlatform>
    </inputLayout:SfTextInputLayout.IsVisible>
    
    ...
     
     
          
    </inputLayout:SfTextInputLayout>
    

    Best Regards,

    Leon Lu


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.