-1

I have a list of files I am displaying that has a text box to input the name of a file, a button to press that allows you to select a file from the file explorer, and a text indicator that updates to let the user know when the file is in the progress of being loaded and when it has finished loading. I want to change the text indicator to a gif/jpg indicator. I would like a loading indicator to appear when the file begins to load and then a check mark to appear when the file has finished loading. I have not been able to find anything on how to bind images/gifs to a list view. Is this possible and if so how can it be done? Is there a better way to try to handle this functionality?

Model

using AuditEfficiencyMVVM.Helpers;
using AuditEfficiencyMVVM.Sources;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AuditEfficiencyMVVM.Model
{
    public class File : INotifyPropertyChanged
    {
        private Enums.FileType _type;
        private string _location;        
        private SourceBase _source;
        private Enums.FileLoadStatus _fileLoadStatus;
        private List<Enums.TestType> _tests = new List<Enums.TestType>();

        public Enums.FileType Type
        {
            get
            {
                return _type;
            }
            set
            {
                if (_type != value)
                {
                    _type = value;
                    RaisePropertyChanged("Type");
                }
            }
        }

        public string Location
        {
            get
            {
                return _location;
            }
            set
            {
                if (_location != value)
                {
                    _location = value;
                    RaisePropertyChanged("Location");
                }
            }
        }

        public List<Enums.TestType> Tests
        {
            get
            {
                return _tests;
            }
            set
            {
                if (_tests != value)
                {
                    _tests = value;
                }
            }
        }

        public SourceBase Source
        {
            get
            {
                return _source;
            }
            set
            {
                if (_source != value)
                {
                    _source = value;
                }
            }
        }

        public Enums.FileLoadStatus FileLoadStatus {
            get
            {
                return _fileLoadStatus;
            }
            set
            {
                if (_fileLoadStatus != value)
                {
                    _fileLoadStatus = value;
                    RaisePropertyChanged("FileLoadStatus");
                }
            }

            }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }
}

ViewModel

// Populate the List of Files on startup
public void LoadFiles()
        {
            ObservableCollection<Model.File> files = new ObservableCollection<Model.File>();

            foreach (Model.Test test in IncludedTests)
            {
                foreach (Enums.FileType type in test.ExpectedSources)
                {
                    Boolean containsType = false;
                    foreach (Model.File file in files)
                    {
                        if (file.Type == type)
                        {
                            containsType = true;
                            break;
                        }
                    }

                    if (!containsType)
                    {
                        files.Add(new Model.File { Type = type, Location = "", Source = null, FileLoadStatus = Enums.FileLoadStatus.NotStarted, Tests = new List<Enums.TestType> { test.Type } });
                    }
                    else
                    {
                        files.Where(t => t.Type == type).First().Tests.Add(test.Type);
                    }
                }
            }

            Files = files;
        }

// Logic to load the files on a button press
private async Task<SortedList<Enums.FileType, DataTable>> LoadFilesAsync()
        {
            try
            {
                SortedList<Enums.FileType, DataTable> fileList = new SortedList<Enums.FileType, DataTable>();

                foreach (var file in Files)
                {
                    // I want this to be something like LoadStatus = spinner.gif
                    file.FileLoadStatus = Enums.FileLoadStatus.InProgress;
                    fileList.Add(file.Type, await file.Source.LoadRecords(file));
                    // I want this to be something like LoadStatus = checkmark.jpg
                    file.FileLoadStatus = Enums.FileLoadStatus.Completed;
                }
                return fileList;
            }
            catch (Exception)
            {
                return null;
            }
        }

View

<ListView Grid.Row="1" Grid.Column="1" Grid.RowSpan="4" Margin="10" ItemsSource="{Binding Path=Files}">
            <ListView.View>
                <GridView x:Name="file">
                    <GridViewColumn Header="File Type" DisplayMemberBinding="{Binding Type, Mode=OneWay}"/>
                    <GridViewColumn Header="File Location" Width="250">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBox Text="{Binding Path=Location, Mode=TwoWay}" Width="225"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>                    
                    <GridViewColumn>
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <Button Width="30" Height="20" Command="{Binding Path=DataContext.SelectFileCommand, 
                                                                        RelativeSource={RelativeSource AncestorType=ListView}}" 
                                                            CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, 
                                                                                AncestorType={x:Type GridViewRowPresenter}}, Path=DataContext}" Content="..."></Button>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Load Status" DisplayMemberBinding="{Binding FileLoadStatus, Mode=OneWay}"/>
                </GridView>
            </ListView.View>
        </ListView>
Tim Hutchison
  • 3,483
  • 9
  • 40
  • 76
  • If someone is down voting, it would be good if they do it with a reason. –  May 01 '17 at 15:09

2 Answers2

1

Give your viewmodel an IsLoading property and an IsLoaded property, both bool.

Give your view an animated spinner control of some kind that's visible while IsLoading is true, and a "loaded" marker of some kind that's visible while IsLoaded is true. I'd superimpose the spinner on top of the listview:

<Grid>
    <ListView ...>
        <!-- ...stuff... -->
    </ListView>
    <Grid 
        Visibility="{Binding IsLoading, Converter={StaticResource BoolToVisibility}}"
        >
        <!-- Spinner stuff -->
    </Grid>
</Grid>

Set IsLoading and IsLoaded appropriately in LoadFileAsync().

I have not been able to find anything on how to bind images/gifs to a list view.

How hard did you look? Put an Image control in a cell template and bind its Source property to an ImageSource property of the row item viewmodel. This may help.

Community
  • 1
  • 1
0

I discovered this tutorial which is how I ended up implementing the loading spinner.

Note: I have since changed from ListView to DataGrid for displaying data which is why my View is slightly different.

CircularProgressBar

<UserControl x:Class="AuditEfficiencyMVVM.View.CircularProgressBar"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:AuditEfficiencyMVVM.View"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             Height="Auto" Width="Auto" Background="Transparent"
             IsVisibleChanged="HandleVisibleChanged">
    <Grid x:Name="LayoutRoot" Background="Transparent"
          ToolTip="Searching...."
          HorizontalAlignment="Center"
          VerticalAlignment="Center">
        <Canvas RenderTransformOrigin="0.5,0.5"
                HorizontalAlignment="Center"
             VerticalAlignment="Center" Width="120"
             Height="120" Loaded="HandleLoaded"
                Unloaded="HandleUnloaded"  >
            <Ellipse x:Name="C0" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="1.0"/>
            <Ellipse x:Name="C1" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.9"/>
            <Ellipse x:Name="C2" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.8"/>
            <Ellipse x:Name="C3" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.7"/>
            <Ellipse x:Name="C4" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.6"/>
            <Ellipse x:Name="C5" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.5"/>
            <Ellipse x:Name="C6" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.4"/>
            <Ellipse x:Name="C7" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.3"/>
            <Ellipse x:Name="C8" Width="20" Height="20"
                     Canvas.Left="0"
                     Canvas.Top="0" Stretch="Fill"
                     Fill="Black" Opacity="0.2"/>
            <Canvas.RenderTransform>
                <RotateTransform x:Name="SpinnerRotate"
                     Angle="0" />
            </Canvas.RenderTransform>
        </Canvas>
    </Grid>
</UserControl>

View

<DataGrid Grid.Row="1" Grid.ColumnSpan="3" Margin="10" ItemsSource="{Binding Path=Files}" SelectedValue="{Binding Path=SelectedUploadFile}" AutoGenerateColumns="False" CanUserAddRows="False">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Viewbox Width="25" Height="25"
                                        HorizontalAlignment="Center"
                                        VerticalAlignment="Center">
                                <local:CircularProgressBar Visibility="{Binding Path=Loading}" />
                            </Viewbox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

ViewModel

public class AuditTests : INotifyPropertyChanged
{
    public ObservableCollection<FileMeta> Files { get; set; }

    private void AddFileRequested()
    {
        Files.Add(new FileMeta());
        SaveFilesCommand.RaiseCanExecuteChanged();
    }

    private void RemoveFileRequested()
    {
        Files.Remove(SelectedUploadFile);
        SaveFilesCommand.RaiseCanExecuteChanged();
    }

    public void InitializeData()
    {
        Files = new ObservableCollection<FileMeta>() { new FileMeta () };
    }
}

FileMeta

public partial class FileMeta : INotifyPropertyChanged
{
    private System.Windows.Visibility _loading;

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }

    public System.Windows.Visibility Loading
    {
        get
        {
            return _loading;
        }
        set
        {
            if (_loading != value)
            {
                _loading = value;
                RaisePropertyChanged("Loading");
            }
        }
    }
}
Tim Hutchison
  • 3,483
  • 9
  • 40
  • 76