ARTICLE AD BOX
I've been currently learning the Avalonia framework and getting back into software development after doing game development over the years. Anyways I'm trying to make my Images which is of type ObservableCollection<Bitmap> and I'm using the ReactiveUI. Everything seems to be working besides it populating my <ScrollViewer>. I've been trying to figure this out all day yesterday and a good amount of time today, so this is why I'm coming this this forum for help! Here's my code right now;
MainWindowViewModel.cs
using Avalonia.Controls; using Avalonia.Media.Imaging; using Avalonia.Platform.Storage; using ReactiveUI; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Reactive; using System.Threading.Tasks; using MemoryLane.ImageHelpers; using System; namespace MemoryLane.ViewModels { public partial class MainWindowViewModel : ReactiveObject { // Observable collection of Bitmaps private ObservableCollection<Bitmap> _images = new(); public ObservableCollection<Bitmap> Images { get => _images; set => this.RaiseAndSetIfChanged(ref _images, value); } // Commands public ReactiveCommand<Unit, Unit> HomeButtonCommand { get; } public ReactiveCommand<Unit, Unit> GalleryButtonCommand { get; } public ReactiveCommand<Unit, Unit> SettingsButtonCommand { get; } public ReactiveCommand<Unit, Unit> UploadImageCommand { get; } public MainWindowViewModel() { HomeButtonCommand = ReactiveCommand.Create(() => Debug.WriteLine("Home clicked")); GalleryButtonCommand = ReactiveCommand.Create(() => Debug.WriteLine("Gallery clicked")); SettingsButtonCommand = ReactiveCommand.Create(() => Debug.WriteLine("Settings clicked")); UploadImageCommand = ReactiveCommand.CreateFromTask(LoadSelectedImages); } // File picker + bitmap loader (memory-safe) public async Task LoadSelectedImages() { var topLevel = Avalonia.Controls.TopLevel.GetTopLevel(App.Current.ApplicationLifetime is Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime desktop ? desktop.MainWindow : null); if (topLevel == null) return; var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { Title = "Select Images", AllowMultiple = true, FileTypeFilter = [FilePickerFileTypes.ImageAll] }); foreach (var file in files) { await using var stream = await file.OpenReadAsync(); try { Images.Add(new Bitmap(files[0].Path.LocalPath)); //Images[0] = bitmap; // Trigger UI update Debug.WriteLine($"Loaded image: {file.Name}"); Debug.WriteLine("Loaded image: " + file.Name); } catch (Exception ex) { Debug.WriteLine($"Failed to load image {file.Name}: {ex.Message}"); } } } } }MainWindow.cs
<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:MemoryLane.ViewModels" x:Class="MemoryLane.Views.MainWindow" x:DataType="vm:MainWindowViewModel" Title="MemoryLane" Width="1000" Height="800" Background="LightBlue" Icon="/Assets/Images/icon.png"> <!-- Design-time DataContext --> <Design.DataContext> <vm:MainWindowViewModel/> </Design.DataContext> <!-- Main grid: two columns (nav + content), two rows (content + upload button) --> <Grid RowDefinitions="*,Auto" ColumnDefinitions="200,*" Margin="0"> <!-- LEFT NAVIGATION PANEL --> <StackPanel Grid.Row="0" Grid.Column="0" Width="200" Background="White"> <TextBlock Text="MemoryLane" Foreground="DeepSkyBlue" FontWeight="Bold" FontSize="20" Margin="10"/> <Button Content="Home" Command="{Binding HomeButtonCommand}" Margin="10"/> <Button Content="Gallery" Command="{Binding GalleryButtonCommand}" Margin="10"/> <Button Content="Settings" Command="{Binding SettingsButtonCommand}" Margin="10"/> </StackPanel> <!-- MAIN CONTENT AREA --> <Grid Grid.Row="0" Grid.Column="1" RowDefinitions="auto,*" Margin="5"> <!-- TOP BAR --> <Border Grid.Row="0" Height="50" Background="Black" CornerRadius="5"> <TextBlock Text="Welcome to MemoryLane" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10"/> </Border> <!-- IMAGE GALLERY --> <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" Background="LightGray"> <StackPanel Margin="10" Background="Red"> <ItemsControl ItemsSource="{Binding Images}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Image Source="{Binding}" Stretch="UniformToFill"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </StackPanel> </ScrollViewer> </Grid> <!-- UPLOAD BUTTON (bottom row, spans both columns) --> <Button Grid.Row="0" Grid.ColumnSpan="1" Height="50" Content="Upload" Command="{Binding UploadImageCommand}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalAlignment="Bottom" Margin="10"/> </Grid> </Window>Do I need to make a model class for example like ImageViewModel -> Image? Any feedback would be appreciated. Everything seems to be working, even when I click Upload Images -> select images -> Debug prints out file01, file02, file... but my xaml is not populating or updating but no bugs. Thank you!
