I know the mvvm pattern is equal to no code behind, but sometimes is impossible to avoid code behind, especially, when you need access to a UI component in your vm
My app has several pages
- ChargeStationPage
- TurbinesCollectionPage
- NewPage
- SuppertPage
I have a title bar in the chargeStatiopPage, and this title bar is accessible by any page
and this page executes a command when select a turbine
namespace METROWIND.Views
{
public partial class ChargingStationsMapPage: ContentPage
{
public ChargingStationsMapPageViewModel PageViewModel { get; }
public ChargingStationsMapPage(ChargingStationsMapPageViewModel stationsMapPageViewModel)
{
InitializeComponent();
PageViewModel = stationsMapPageViewModel;
BindingContext = PageViewModel;
InitializeMap();
InitializeTitleBar();
DeviceHelper.AddOrRemoveContentBasedOnDevice(MobileContent);
}
private void InitializeMap()
{
PageViewModel.MapView = ChargingStationMap;
PageViewModel.MapDialogPopUp = MapChangeTypuPopUp;
}
private void InitializeTitleBar()
{
var comboBox = CreateComboBox();
comboBox.SelectionChanged += ComboBox_SelectionChanged;
App.WindowInstance!.TitleBar = new TitleBar
{
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,
ItemsSource = PageViewModel.TurbinePins,
DisplayMemberPath = "Turbine.Name",
TextMemberPath = "Turbine.Name",
IsClearButtonVisible = false,
HighlightedTextColor = Colors.Red,
HighlightedTextFontAttributes = FontAttributes.Bold,
IsFilteringEnabled = true
};
}
private async void ComboBox_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (sender is SfComboBox comboBox && comboBox.SelectedValue is TurbinePin selectedPin)
{
// Zoom into the selected turbine's location
PageViewModel.ItemSelectedCommand.Execute(selectedPin.Turbine);
// Wait for a short duration before navigation
await Task.Delay(1000);
// Navigate to the turbine detail page
await PageViewModel.PinMarkerClicked(selectedPin);
}
}
}
This command comes from the AppShell, because this page inherits from the shell
namespace METROWIND.ViewModel
{
public partial class ChargingStationsMapPageViewModel: AppShellViewModel
{
public SfPopup? MapDialogPopUp;
public Map? MapView;
public bool LoadedPins;
[ObservableProperty]
bool isExpanded;
public ChargingStationsMapPageViewModel(ITurbineService turbineService, IAppService appService,
IServiceProvider serviceProvider, ICommandHandler commandHandler)
: base(turbineService, appService, serviceProvider, commandHandler)
{
MapDialogButtons();
}
public ObservableCollection<MapTypeButton> MapTypeButtons { get; set; } = [];
private void MapDialogButtons()
{
MapTypeButtons.Add(new MapTypeButton
{
Caption = "Default",
ImageName = FontAwesome.Road,
Selected = true,
MapNumber = 1
});
MapTypeButtons.Add(new MapTypeButton
{
Caption = "Satellite",
MapNumber = 2,
ImageName = FontAwesome.StreetView,
});
}
[RelayCommand]
void ItemSelected(Turbine Turbine)
{
if (Turbine == null || MapView == null)
{
return;
}
var mapSpan = MapSpan.FromCenterAndRadius(Turbine.Location,
Distance.FromKilometers(2));
MapView!.MoveToRegion(mapSpan);
}
Now
I have a collctionPage, that gets all the turbine from the shell and display them in a collection view
using Map = Microsoft.Maui.ApplicationModel.Map;
namespace METROWIND.ViewModel
{
public partial class TurbinesCollectionPageViewModel(ITurbineService turbineService,
IAppService appService,
IServiceProvider serviceProvider,
ICommandHandler commandHandler): AppShellViewModel(turbineService, appService, serviceProvider, commandHandler)
{
public CollectionView? TurbinesCollection;
public SfComboBox? ColletionComboBox;
[ObservableProperty]
Turbine? turbine;
[RelayCommand]
async Task SelectedItemChange()
{
if (ColletionComboBox!.SelectedIndex < 0)
{
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
}
I want to tell the title bar to execute this method
if (ColletionComboBox!.SelectedIndex < 0)
{
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
}
when I am in the turbines colletion PageAlso, I don't know I can implement a little view that says
with the two turbines and says the name of the page and if I select one of them, it will go to that page