search bar in shell behavior

Eduardo Gomez Romero 945 Reputation points
2024-11-22T10:58:06.6833333+00:00

So, I need to modify, my behavior on desktop

I have the shell, with the Seach bar

<Window
    x:Class="METROWIND.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">

    <Window.TitleBar>
        <TitleBar
            Title="METROWIND"
            BackgroundColor="{x:AppThemeBinding Dark={x:StaticResource Black}, Light={x:StaticResource Primary}}"
            HeightRequest="60">
            <TitleBar.Content>
                <Border>
                    <SearchBar/>
                </Border>
            </TitleBar.Content>
            <TitleBar.TrailingContent>
                <ImageButton
                    Background="Transparent"
                    BorderWidth="0"
                    HeightRequest="36"
                    WidthRequest="36">
                    <ImageButton.Source>
                        <FontImageSource
                            FontFamily="SegoeMDL2"
                            Glyph="&#xE713;"
                            Size="16" />
                    </ImageButton.Source>
                </ImageButton>
            </TitleBar.TrailingContent>
        </TitleBar>
    </Window.TitleBar>

    public partial class App : Application
    {
        AppShell shell;

        public App(AppShell appShell)
        {

            SyncfusionLicenseProvider.RegisterLicense(AppConstants.SYNCFUSION_KEY);

            InitializeComponent();

            shell = appShell;
        }

        protected override Window CreateWindow(IActivationState? activationState)
        {
            Window window = new MainWindow(shell);

            return window;

        }


everything works fantastic, but what I want to do for desktop, is to make my collection of turbines globally available for you to search in the shell to open a new window WITH THE DETAIL

Also, I have a cahrgeStationPage, that display a combo box with the turbines to search, and mke the map go to that pin

    public partial class ChargingStationsMapPageViewModel(
        HttpService service, DeviceLanguageService deviceLanguage, TurbinesService turbinesService) :
        HomePageViewModel(service, deviceLanguage, turbinesService)
    {

        private Map? MapView;

        [ObservableProperty]
        bool isOptionsOpen;

        [ObservableProperty]
        bool isExpanded;

        [RelayCommand]
        private void Appearing(Map map)
        {

            MapView = map;
        }

        [RelayCommand]
        void ItemSelected(Turbine Turbine)
        {

            var mapSpan = MapSpan.FromCenterAndRadius(Turbine.Location,
                Distance.FromKilometers(0.4));

            MapView!.MoveToRegion(mapSpan);
            IsExpanded = false;
        }

        [RelayCommand]
        void OpenMenu()
        {

            IsOptionsOpen = true;
        }

        [RelayCommand]
        void ChangeMapType(int mapType)
        {
            MapView!.MapType = mapType switch
            {
                0 => MapType.Street,
                1 => MapType.Satellite,
                2 => MapType.Hybrid, // Example: Handle mapType 2
                _ => throw new ArgumentOutOfRangeException(nameof(mapType), mapType, "Invalid map type"),
            };
            IsOptionsOpen = false;
        }
    }
}

<ContentPage
    x:Class="METROWIND.Views.ChargingStationsMapPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:constant="clr-namespace:METROWIND.Constants"
    xmlns:controls="clr-namespace:METROWIND.Controls"
    xmlns:expander="clr-namespace:Syncfusion.Maui.Expander;assembly=Syncfusion.Maui.Expander"
    xmlns:maps="clr-namespace:Microsoft.Maui.Controls.Maps;assembly=Microsoft.Maui.Controls.Maps"
    xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    xmlns:model="clr-namespace:METROWIND.Models"
    xmlns:popup="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup"
    xmlns:rex="clr-namespace:METROWIND.Resources"
    xmlns:vm="clr-namespace:METROWIND.ViewModel"
    x:Name="stationsMapPage"
    x:DataType="vm:ChargingStationsMapPageViewModel">

    <ContentPage.Behaviors>
        <mct:EventToCommandBehavior
            Command="{x:Binding AppearingCommand}"
            CommandParameter="{x:Reference ChargingStationMap}"
            EventName="Appearing" />

    </ContentPage.Behaviors>

    <Grid>
        <Border Style="{x:StaticResource ChargeStationBorderStyle}">
            <expander:SfExpander
                AnimationDuration="200"
                IsExpanded="{x:Binding IsExpanded}">
                <expander:SfExpander.Header>
                    <Grid RowDefinitions="48">
                        <Label Style="{x:StaticResource ChooseStationLabelStyle}" />
                    </Grid>
                </expander:SfExpander.Header>
                <expander:SfExpander.Content>
                    <Grid
                        Padding="10,0,0,0"
                        RowDefinitions="Auto">
                        <CollectionView ItemsSource="{x:Binding Turbines}">
                            <CollectionView.ItemTemplate>
                                <DataTemplate x:DataType="model:TurbinePin">
                                    <Border Stroke="Transparent">
                                        <HorizontalStackLayout Spacing="10">
                                            <Label Style="{x:StaticResource ElectricBoltLabelStyle}" />
                                            <Label
                                                Style="{x:StaticResource AddressLabelStyle}"
                                                Text="{x:Binding Turbine.Name}" />
                                        </HorizontalStackLayout>
                                        <Border.Behaviors>
                                            <mct:TouchBehavior
                                                DefaultBackgroundColor="White"
                                                PressedBackgroundColor="CornflowerBlue" />
                                        </Border.Behaviors>
                                        <Border.GestureRecognizers>
                                            <TapGestureRecognizer
                                                Command="{x:Binding Source={x:Reference stationsMapPage},
                                                                    Path=BindingContext.ItemSelectedCommand}"
                                                CommandParameter="{x:Binding Turbine}" />
                                        </Border.GestureRecognizers>

                                    </Border>
                                </DataTemplate>
                            </CollectionView.ItemTemplate>
                        </CollectionView>
                    </Grid>
                </expander:SfExpander.Content>
            </expander:SfExpander>
        </Border>

        <maps:Map
            x:Name="ChargingStationMap"
            ItemsSource="{x:Binding Turbines}"
            VerticalOptions="FillAndExpand">
            <maps:Map.ItemTemplate>
                <DataTemplate x:DataType="model:TurbinePin">
                    <controls:CustomMapPin
                        Address="{x:Binding Turbine.Address}"
                        Images="{x:Binding Turbine.ImagesURLs}"
                        Label="{x:Binding Turbine.Name}"
                        Location="{x:Binding Turbine.Location}"
                        MarkerClickedCommand="{x:Binding PinClickedCommand}"
                        MarkerClickedCommandParameter="{x:Binding Turbine}" />
                </DataTemplate>
            </maps:Map.ItemTemplate>
        </maps:Map>

        <Button
            x:Name="mapLayers"
            Command="{x:Binding OpenMenuCommand}"
            Style="{x:StaticResource MapButtonStyle}">
            <Button.ImageSource>
                <FontImageSource
                    FontFamily="ma"
                    Glyph="{x:Static constant:MaterialFonts.Layers}" />
            </Button.ImageSource>
        </Button>

        <popup:SfPopup
            IsOpen="{x:Binding IsOptionsOpen}"
            RelativeView="{x:Binding Source={x:Reference mapLayers}}"
            Style="{x:StaticResource ChargeStationPopupStyle}">
            <popup:SfPopup.PopupStyle>
                <popup:PopupStyle CornerRadius="8" />
            </popup:SfPopup.PopupStyle>
            <popup:SfPopup.ContentTemplate>
                <DataTemplate>
                    <VerticalStackLayout Spacing="10">
                        <controls:CustomImageButton
                            Caption="{x:Static rex:AppResource.Default}"
                            ClickCommand="{x:Binding ChangeMapTypeCommand}"
                            ImageName="default_layer.png"
                            Parameters="0" />
                        <controls:CustomImageButton
                            Caption="{x:Static rex:AppResource.Satelite}"
                            ClickCommand="{x:Binding ChangeMapTypeCommand}"
                            ImageName="satelite_layer.png"
                            Parameters="2" />
                    </VerticalStackLayout>
                </DataTemplate>
            </popup:SfPopup.ContentTemplate>
        </popup:SfPopup>
    </Grid>
</ContentPage>


On this particular page, the search box, should take care of this

How is working right now

I have a homePage

that grabs all the turbines from the service and put it in a collection view

        protected readonly TurbinesService _turbinesService;
        public ObservableCollection<TurbinePin> Turbines => _turbinesService.TurbinePins;
        public HomePageViewModel(HttpService service, DeviceLanguageService deviceLanguage, TurbinesService turbinesService)
        {
            deviceLanguageService = deviceLanguage;
            httpService = service;
            LoadNews();
            _turbinesService = turbinesService;
            OnPinMarkerClickedCommand = new Command<object>(OnPinMarkerClicked);
            _turbinesService.GetTurbinePinsForUI(OnPinMarkerClickedCommand);
        }
        public ObservableCollection<Article>? NewsList { get; set; } =
            [];
        async void LoadNews()
        {
            var language = deviceLanguageService.GetDeviceCultureInfo();
            var newsUrl = AppConstants.GetNewsUrl(language.TwoLetterISOLanguageName);
            NewsList!.Clear();
            var newsObj = await httpService.GetAsync<News>(newsUrl);
            foreach (var item in newsObj!.Articles!)
            {
                NewsList.Add(item);
            }
        }
        [RelayCommand]
        protected void ShowNewsDetail(Article article)
        {
            if (article != null)
            {
                Shell.Current.GoToAsync($"{nameof(ArticleDetailsPage)}",
                    true,
                    new Dictionary<string, object> {
                        { "articleObj", article }
                    });
            }
        }
        void OnPinMarkerClicked(object turbine)
        {
            if (turbine != null)
            {
                Shell.Current.GoToAsync($"{nameof(TurbineDetailPage)}",
                     true,
                     new Dictionary<string, object> {
                    { "SelectedTurbine", turbine }
                });
            };
        }
    }
}

and in my turbines collection page, I inherit from this page, in order to get the turbines

    public partial class TurbinesCollectionPageViewModel(HttpService service, DeviceLanguageService deviceLanguage,
        TurbinesService turbinesService) : HomePageViewModel(service, deviceLanguage, turbinesService)
    {

        CollectionView? TurbinesCollection;

        [ObservableProperty]
        Turbine? turbine;

        [RelayCommand]
        void PageEnter(CollectionView collectionView)
        {

            if (collectionView != null)
            {

                TurbinesCollection = collectionView;
            }
        }

        [RelayCommand]
        async Task SelectedItemChange(SfComboBox combo)
        {

            if (combo.SelectedIndex < 0)
            {
                return;
            }

            var item = Turbines.ElementAt(combo.SelectedIndex);
            TurbinesCollection?.ScrollTo(combo.SelectedIndex, -1, ScrollToPosition.Center);
            var inputView = combo.Children[1] as Entry;

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

and for I have a search box that can use to search

   <Grid
       Padding="20"
       RowDefinitions="Auto,*"
       RowSpacing="-30">
       <inputLayout:SfTextInputLayout Style="{x:StaticResource TurbineCollectionComboBoxStyle}">
           <editors:SfComboBox
               x:Name="combobox"
               DisplayMemberPath="Turbine.Name"
               ItemsSource="{x:Binding Turbines}"
               Style="{x:DynamicResource TurbinesCollectionComboBoxStyle}">
               <editors:SfComboBox.Behaviors>
                   <mct:EventToCommandBehavior
                       Command="{x:Binding SelectedItemChangeCommand}"
                       CommandParameter="{x:Binding Source={x:Reference combobox}}"
                       EventName="SelectionChanged" />
               </editors:SfComboBox.Behaviors>
           </editors:SfComboBox>
       </inputLayout:SfTextInputLayout>

       <CollectionView
           x:Name="TurbineCollection"
           Grid.Row="1"
           ItemsSource="{x:Binding Turbines}"
           SelectionMode="None"
           Style="{x:StaticResource TurbineCollectionViewStyle}">
           <CollectionView.ItemTemplate>
               <DataTemplate x:DataType="model:TurbinePin">
                   <Border BackgroundColor="#578D57">
                       <Border.StrokeShape>
                           <RoundRectangle CornerRadius="8" />
                       </Border.StrokeShape>
                       <VerticalStackLayout>
                           <Label
                               Style="{x:StaticResource TurbineDataLabelStyleStyle}"
                               Text="{x:Binding Turbine.Name}" />
                           <Label
                               Style="{x:StaticResource TurbineDataLabelStyleStyle}"
                               Text="{x:Binding Turbine.Address}" />
                           <Label
                               Style="{x:StaticResource C02LabelStyle}"
                               Text="{x:Binding Turbine.FinalCo2Removed,
                                                StringFormat='{0:F5} kg CO₂'}" />
                       </VerticalStackLayout>
                       <Border.GestureRecognizers>
                           <TapGestureRecognizer
                               Command="{x:Binding OnPinMarkerClickedCommand,
                                                   Source={x:RelativeSource AncestorType={x:Type vm:TurbinesCollectionPageViewModel}}}"
                               CommandParameter="{x:Binding}" />
                       </Border.GestureRecognizers>
                   </Border>
               </DataTemplate>
           </CollectionView.ItemTemplate>
       </CollectionView>
.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
3,657 questions
0 comments No comments
{count} votes

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.