0

I hit a block and I want to save an Image into my Database alongside its Name, Description, and Price but when I display it, only the Name, Description, and Price are being displayed. I want to know if I used the correct method.

This is what my code looks like:

SQLiteHelper.cs:

using System.Collections.Generic;
using System.Text;
using SQLite;
using System.Threading.Tasks;
using projectDev.Model;
using System.IO;

namespace projectDev
{
    public class SQLiteHelper
    {
        private readonly SQLiteAsyncConnection db;
        public SQLiteHelper(string dbPath)
        {
            db = new SQLiteAsyncConnection(dbPath);
            db.CreateTableAsync<ProductModel>();
        }
        public Task<int> CreateProduct(ProductModel product)
        {
            return db.InsertAsync(product);
        }
        public Task<List<ProductModel>> ReadProducts()
        {
            return db.Table<ProductModel>().ToListAsync();
        }
        public Task<int> UpdateProduct(ProductModel product)
        {
            return db.UpdateAsync(product);
        }
        public Task<int> DeleteProduct(ProductModel product)
        {
            return db.DeleteAsync(product);
        }
        public Task<List<ProductModel>> Search(string search)
        {
            return db.Table<ProductModel>().Where(p => p.Name.StartsWith(search)).ToListAsync();
        }
    }
}

This is where the user enters a new item:

<popup:PopupPage 
        xmlns="http://xamarin.com/schemas/2014/forms" 
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:popup="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup" 
        x:Class="projectDev.ProductDetail">

    <StackLayout
                 Margin="20"
                 HorizontalOptions="Center"
                 VerticalOptions="Center"
                 WidthRequest="350" 
                 HeightRequest="660"
                 BackgroundColor="#61892f" >
        <ImageButton x:Name="imageEntry" Source="addimage.png" Clicked="Button_Clicked_1" 
                MinimumHeightRequest="500"
                BackgroundColor="Transparent"/>
        <Entry Placeholder="Name"  
                   x:Name="nameEntry" />
        <Entry Placeholder="Description"  
                   x:Name="descEntry"/>
        <Entry Placeholder="Price" 
               x:Name="priceEntry"/>
        <Button Text="Save"  
                    Clicked="Button_Clicked"/>
    </StackLayout>
</popup:PopupPage>

Code-Behind:

using System.IO;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Plugin.Media;
using Plugin.Media.Abstractions;
using projectDev.Model;

namespace projectDev
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ProductDetail : Rg.Plugins.Popup.Pages.PopupPage
    {
        byte[] imageData;

        ProductModel _product;

        public ProductDetail()
        {
            InitializeComponent();
        }

        public ProductDetail(ProductModel product) : this()
        {
            Title = "Edit Product";
            _product = product;
            nameEntry.Text = product.Name;
            descEntry.Text = product.Description;
            priceEntry.Text = product.Price;
            imageEntry.Source = ImageSource.FromStream(() => new MemoryStream(product.Image));
            nameEntry.Focus();
        }

        async void Button_Clicked(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(nameEntry.Text) || string.IsNullOrWhiteSpace(descEntry.Text) || string.IsNullOrWhiteSpace(priceEntry.Text))
            {
                await DisplayAlert("Invalid", "Blank is Invalid!", "OK");
                return;
            }

            byte[] imageArray = imageData ?? (_product?.Image ?? Array.Empty<byte>());

            if (_product != null)
            {
                _product.Name = nameEntry.Text;
                _product.Description = descEntry.Text;
                _product.Price = priceEntry.Text;
                _product.Image = imageArray;
                await App.MyDatabase.UpdateProduct(_product);
            }
            else
            {
                var newProduct = new ProductModel
                {
                    Name = nameEntry.Text,
                    Description = descEntry.Text,
                    Price = priceEntry.Text,
                    Image = imageArray
                };
                await App.MyDatabase.CreateProduct(newProduct);
            }

            await Navigation.PopAsync();
        }

        async void Button_Clicked_1(object sender, EventArgs e)
        {
            await UploadPhoto();
        }

        async Task UploadPhoto()
        {
            await CrossMedia.Current.Initialize();
            if (!CrossMedia.Current.IsPickPhotoSupported)
            {
                await DisplayAlert("Photos Not Supported", "Permission not granted to photos.", "OK");
                return;
            }

            var file = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
            {
                PhotoSize = PhotoSize.Full,
                CompressionQuality = 40
            });

            if (file == null)
                return;

            imageData = File.ReadAllBytes(file.Path);
            imageEntry.Source = ImageSource.FromStream(() => file.GetStream());
        }
    }
}

and this is where I want the Items to be displayed:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:local="clr-namespace:Plugin.Media;assembly=Plugin.Media"
             x:Class="projectDev.ItemPage">
    <ContentPage.Resources>
        <local:CrossMedia x:Key="ImageByteArrayToImageSourceConverter" />
    </ContentPage.Resources>
    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Add" 
                     IconImageSource="add.png" 
                     Clicked="ToolbarItem_Clicked"/>
    </ContentPage.ToolbarItems>
    <StackLayout>
        <StackLayout Margin="10">
            <SearchBar TextChanged="SearchBar_TextChanged" Placeholder="Search Items..." PlaceholderColor="White" TextColor="White" BackgroundColor="#6b6e70"/>
        </StackLayout>
        <CollectionView x:Name="myCollectionView" 
                        SelectionMode="Single" 
                        Margin="20, 5, 20, 0">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <SwipeView>
                        <SwipeView.RightItems>
                            <SwipeItems>
                                <SwipeItem Text="Edit" 
                                           BackgroundColor="Green" 
                                           CommandParameter="{Binding .}" 
                                           Invoked="SwipeItem_Invoked"/>
                                <SwipeItem Text="Delete" 
                                           BackgroundColor="Red" 
                                           CommandParameter="{Binding .}" 
                                           Invoked="SwipeItem_Invoked_1"/>
                            </SwipeItems>
                        </SwipeView.RightItems>
                        <Grid RowSpacing="0">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="20"/>
                            </Grid.ColumnDefinitions>
                            <Image Source="{Binding Image}"
                                   Grid.Row="0" Grid.RowSpan="3" Grid.Column="0"
                                   HeightRequest="50" WidthRequest="50" Aspect="AspectFill"/>
                            <Label Text="{Binding Name}" 
                                   Grid.Row="0" Grid.Column="1" 
                                   VerticalOptions="CenterAndExpand" 
                                   FontSize="20" 
                                   FontAttributes="Bold"/>
                            <Label Text="{Binding Description}" 
                                   Grid.Row="1" Grid.Column="1"/>
                            <Label Text="{Binding Price}" 
                                   Grid.Row="2" Grid.Column="1"/>
                        </Grid>
                    </SwipeView>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
</ContentPage>

Code-Behind:

using Rg.Plugins.Popup.Pages;
using Rg.Plugins.Popup.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace projectDev
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ItemPage : ContentPage
    {
        public ItemPage()
        {
            InitializeComponent();
        }
        protected override async void OnAppearing()
        {
            try
            {
                base.OnAppearing();
                myCollectionView.ItemsSource = await App.MyDatabase.ReadProducts();
            }
            catch { }
        }
        async void ToolbarItem_Clicked(object sender, EventArgs e)
        {
            await PopupNavigation.Instance.PushAsync(new ProductDetail());
        }
        async void SwipeItem_Invoked(object sender, EventArgs e)
        {
            var item = sender as SwipeItem; 
            var emp = item.CommandParameter as ProductModel;
            await PopupNavigation.Instance.PushAsync(new ProductDetail(emp));
        }
        async void SwipeItem_Invoked_1(object sender, EventArgs e)
        {
            var item = sender as SwipeItem;
            var emp = item.CommandParameter as ProductModel; 
            var result = await DisplayAlert("Delete", $"Delete {emp.Name} from the Database?", "Yes", "No");
            if (result)
            {
                await App.MyDatabase.DeleteProduct(emp);
                myCollectionView.ItemsSource = await App.MyDatabase.ReadProducts();
            }
        }
        private async void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
        {
            myCollectionView.ItemsSource = await App.MyDatabase.Search(e.NewTextValue);
        }
    }
}

ProductModel:

using System.Collections.Generic;
using System.Text;
using SQLite;
using Xamarin.Forms;
using System.IO;
namespace projectDev.Model
{
    public class ProductModel
    {
        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
        [MaxLength(50)]
        public string Name { get; set; }
        public string Description { get; set; }
        public string Price { get; set; }
        public byte[] Image { get; set; }
    }
}
1
  • generally its a better idea to store images in the file system, and just store the path in the db. However you should be able to store them in the db. Have you debugged every step of the save/load to verify that it is doing what you expect it to do?
    – Jason
    Commented Jun 12, 2024 at 13:42

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.