简体   繁体   中英

Bind listview image source to image (Sqlite/ UWP/ C#)

The following code can add images from a database to a listview, however I would like to bind the image property to the pictures in XAML using Image Source rather than use listview1.Items.Add. Can this code be easily modified to do this or do I have to go about this another way. Hopefully this isn't a stupid question to ask and I would appreciate any help.

public async void showImage()
    {
        var query = GetAll();

        foreach (var stuff in query)
        {
            string FileName;
            FileName = stuff.RecipeImage;
            var file = await
            Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(FileName);
            var stream = await file.OpenReadAsync();
            var bitmapImage = new BitmapImage();
            bitmapImage.SetSource(stream);

            Image ctrlImage = new Image();
            ctrlImage.Source = bitmapImage;
            ctrlImage.Height = 50;
            ctrlImage.Width = 50;
            ctrlImage.Stretch = Stretch.UniformToFill;

            listView1.Items.Add(ctrlImage);
        }
    }

I need to add the image to the item source that is already used for my database which contains:

public class AddRecipe
{
    [PrimaryKey,AutoIncrement]
    public int ID { get; set; }
    public string RecipeName { get; set; }
    public string RecipeImage { get; set; }
} 

 <ListView x:Name="listView" HorizontalAlignment="Left" Height="493" Margin="725,60,0,0" VerticalAlignment="Top" Width="528" IsItemClickEnabled="True" SelectionMode="None" ItemClick="listView_SelectionChanged" FontSize="26.667">
        <ListView.ItemTemplate>
            <DataTemplate >
                <StackPanel Orientation="Vertical"  Margin="4">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding RecipeName}" Foreground="Black"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding MealType}" Foreground="Black"/>
                    </StackPanel>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

We can use ListView.ItemTemplate to set the DataTemplate used to display each item and put all the images into a ObservableCollection<BitmapImage> as ListView 's ItemsSource . Then in DataTemplate , we can use Bind to set the Image.Source . Following is a simple sample:

In XAML, set DataTemplate with {x:Bind} to show image.

<ListView ItemsSource="{x:Bind ImgList}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="BitmapImage">
            <Image Width="50"
                   Height="50"
                   Source="{x:Bind }"
                   Stretch="UniformToFill" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

ImgList is defined in code-behind, it's defined as ObservableCollection<BitmapImage> , so the DataType of DataTemplate is BitmapImage and as I just bind the whole BitmapImage object to Image.Source so here just use Source="{x:Bind }" .

The code-behind may like following:

public sealed partial class MainPage : Page
{
    public ObservableCollection<BitmapImage> ImgList = new ObservableCollection<BitmapImage>();

    public MainPage()
    {
        this.InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        showImage();
    }

    public async void showImage()
    {
        var query = GetAll();

        foreach (var stuff in query)
        {
            string FileName = stuff.RecipeImage;
            var file = await Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(FileName);
            var stream = await file.OpenReadAsync();
            var bitmapImage = new BitmapImage();
            bitmapImage.SetSource(stream);

            ImgList.Add(bitmapImage);
        }
    }
}

Besides, I noticed that you are getting images form Pictures Library. If these images are stored by your app earlier, then storing them in app data would be better as this makes the binding easier and in Pictures Library, these images could be easily deleted by users.

To store images in app data, we can using ApplicationData.Current.LocalFolder to retrieve app's local data folder. For example, copy selected image into local data folder:

//This method copies selected image into local data folder and returns new file's name.
public async Task<string> CopySelectedImage()
{
    FileOpenPicker openPicker = new FileOpenPicker();
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;

    openPicker.FileTypeFilter.Clear();
    openPicker.FileTypeFilter.Add(".bmp");
    openPicker.FileTypeFilter.Add(".jpg");
    openPicker.FileTypeFilter.Add(".jpeg");
    openPicker.FileTypeFilter.Add(".png");

    var file = await openPicker.PickSingleFileAsync();

    if (file != null)
    {
        var localFolder = ApplicationData.Current.LocalFolder;
        var newCopy = await file.CopyAsync(localFolder, file.Name, NameCollisionOption.GenerateUniqueName);
        return newCopy.Name;
    }
    else
    {
        return null;
    }
}

Then we can using code like following to retrieve the image and create the BitmapImage :

var path = await CopySelectedImage();
var bitmapImage = new BitmapImage(new Uri($"ms-appdata:///local/{path}"));

Update:

I suppose you have had RecipeImage in your item source, then you can add a Image control into your DataTemplate and bind RecipeImage to it's Source with a ImageConverter like following:

<ListView.ItemTemplate>
    <DataTemplate>
        <StackPanel Margin="4" Orientation="Vertical">
            <StackPanel Orientation="Horizontal">
                <TextBlock Foreground="Black" Text="{Binding RecipeName}" />
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Foreground="Black" Text="{Binding MealType}" />
            </StackPanel>
            <Image Width="50"
                   Height="50"
                   Source="{Binding RecipeImage,
                                    Converter={StaticResource ImageConverter}}"
                   Stretch="UniformToFill" />
        </StackPanel>
    </DataTemplate>
</ListView.ItemTemplate>

ImageConverter is used to convert string to BitmapImage as your RecipeImage is defined as string but Image.Source need a BitmapImage . Before using it in Binding , we need set it as a StaticResource firstly:

<Page.Resources>
    <local:ImageConverter x:Key="ImageConverter" />
</Page.Resources>

The code of ImageConverter may like:

public class ImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        string FileName = value as string;
        var file = Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(FileName).AsTask().Result;
        var stream = file.OpenReadAsync().AsTask().Result;
        var bitmapImage = new BitmapImage();
        bitmapImage.SetSource(stream);
        return bitmapImage;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Simple

xaml

<ListView Name="listView1">
     <ListView.ItemTemplate>
          <DataTemplate>
               <Grid>
                    <Image Source="{Binding}" Height="50" Width="50" Stretch="UniformToFill" />
               </Grid>
           </DataTemplate>
      </ListView.ItemTemplate>
</ListView>

и в коде добавляем List<BitmapImage>

List<BitmapImage> data_list = new List<BitmapImage>();

foreach (var stuff in query)
        {
            string FileName;
            FileName = stuff.RecipeImage;
            var file = await
            Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(FileName);
            BitmapImage bitmapImage;
            using (var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
            {
                bitmapImage = new BitmapImage();
                bitmapImage.SetSource(stream);
            }

          data_list.Add(bitmapImage);
        }

 listView1.ItemsSource = data_list; 

then we just fill in the data into our ListView

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM