Reputation: 117
In my maui app I have this content view that I use as a custom control. In it I have a collectionview that I want to bind to a list of data.
I use DI for my services and have a BaseService with all the httpclient requests and I then inherit from that BaseService depending of model.
I then have a viewmodel where I inject the service and retreive data from an api.
private readonly LightCastArchiveService _lightCastArchiveService;
private readonly LightCastChannelService _lightCastChannelService;
public LatestViewModel(LightCastArchiveService lightCastArchiveService,
LightCastChannelService lightCastChannelService)
{
_lightCastArchiveService = lightCastArchiveService;
_lightCastChannelService = lightCastChannelService;
}
And in the viewmodel I then have a method to get the data:
public async Task LoadVideos()
{
if (IsLoading) return;
try
{
string url = EndPoints.ArchiveEndpoint + $"&count=50";
IsLoading = true;
if (Videos.Any()) Videos.Clear();
var videos = new List<LCVideo>();
videos = await _lightCastArchiveService.Get(url);
foreach (var video in videos)
{
Videos.Add(video);
}
}
catch (Exception ex)
{
Debug.WriteLine($"Unable to get the videos: {ex.Message}");
await Shell.Current.DisplayAlert("Error", "Failed to retrieve list of videos.", "Ok");
}
finally
{
IsLoading = false;
IsRefreshing = false;
}
}
In an content page I then can use the OnAppearing method to retrieve the videos:
protected override async void OnAppearing()
{
base.OnAppearing();
await _homeViewModel.GetCarouselItems(1025, 10);
await _homeViewModel.LoadLiveChannels();
await _homeViewModel.GetItems(1009, 20);
await _homeViewModel.LoadVideosForAllChannels();
}
but how can I do it in an content view (I tried the approach below but it didn't work)?
public partial class Latest : ContentView
{
private readonly LatestViewModel _latestViewModel;
private readonly LightCastArchiveService _lightCastArchiveService;
private readonly LightCastChannelService _lightCastChannelService;
private readonly HttpClient _client;
public Latest()
{
InitializeComponent();
.BindingContextChanged += OnBindingContextChanged;
_lightCastArchiveService = new LightCastArchiveService(_client);
_lightCastChannelService = new LightCastChannelService(_client);
this.BindingContextChanged += OnBindingContextChanged;
_latestViewModel = new LatestViewModel(_lightCastArchiveService, _lightCastChannelService);
BindingContext = _latestViewModel;
}
private async void OnBindingContextChanged(object sender, EventArgs e)
{
if (BindingContext is LatestViewModel viewModel)
{
await viewModel.LoadVideos();
}
}
// private async void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
// {
// if (e.PropertyName == nameof(_latestViewModel.Videos))
// {
// latestVideos.BindingContext = await _latestViewModel.LoadVideos();
// }
// }
}
```
Upvotes: 0
Views: 389
Reputation: 1807
ContentView
.Let me justify this. I'm not saying it's completely wrong, nor impossible, but as you've seen, many features you have in Page
s viewmodels are not there for ContentView
s ones (injected services, appearing events...).
Someone could actually say that you shouldn't use OnAppearing()
to call viewmodel methods, but I'm not such a purist.
If you think about MAUI controls, they don't have their own viewmodel, but they inherit the ancestor's BindingContext
(probably the one belonging to the Page
where they are used) and provide bindable properties you can bind to a viewmodel property. You should do that too.
Take a look at how BindableProperties
work, if you don't know what I'm talking about.
If you really want to keep your viewmodel, you could instantiate it inside the ContentPage
code-behind and set the BindingContext
of LatestView
there. This way, you can call LatestViewModel
methods inside OnAppearing
. Dirty workaround though.
Upvotes: 2