David G

David G

  • 1.5k
  • 224
  • 14.7k

Wpf System.Windows.Media.ImageSourcesConverter cannot be applied

Feb 2 2022 2:58 AM

Hey all it has been a few years since I last worked on my WPF code and sadly I'm not remembering what all I did in order for it to work as its coded.

The current issue I am facing is this:

An object of the type 'System.Windows.Media.ImageSourcesConverter' cannot be applied to a property that expects the type 'System.Windows.Data.IValueConverter'.

It has the above error on this line of code:

     <Image Source="{Binding Path, 
                     Converter={StaticResource ImageSourceConverter}}"
                     Stretch="Fill"
     />

The full XAML code being:

<Window.Resources>
        <!-- List of supported animations -->
        <FluidKit:SlideTransition x:Key="SlideTransition" x:Shared="False"/>
        <FluidKit:CubeTransition x:Key="CubeTransition" Rotation="BottomToTop" x:Shared="False"/>
        <FluidKit:FlipTransition x:Key="FlipTransition" x:Shared="False"/>
    
        <local1:ImageSourceConverter x:Key="ImageSourceConverter"/>
        <!-- Data template for animations -->
        <DataTemplate x:Key="ItemTemplate" x:Shared="False">
            <Image Source="{Binding Path, 
                Converter={StaticResource ImageSourceConverter}}"
                   Stretch="Fill"/>
        </DataTemplate>
    </Window.Resources>
    <Grid x:Name="imageAreas" HorizontalAlignment="Left" Height="1920" Margin="0,0,0,0" VerticalAlignment="Top" Width="1080" ScrollViewer.VerticalScrollBarVisibility="Disabled">
            <Grid HorizontalAlignment="Left" Height="726" VerticalAlignment="Top" Width="1080" x:Name="topGrid">
                <FluidKit:TransitionPresenter RestDuration="0:0:3" 
                                          IsLooped="True" 
                                        Transition="{StaticResource FlipTransition}" 
                                       ItemsSource="{Binding Images1}" 
                                             Width="357" 
                                            Height="272" 
                               HorizontalAlignment="Left" 
                                 VerticalAlignment="Top" 
                                      ItemTemplate="{StaticResource ItemTemplate}" 
                                            x:Name="box1" 
                                            Margin="0,0,0,454"/>
                <FluidKit:TransitionPresenter RestDuration="0:0:3" 
                                          IsLooped="True" 
                                        Transition="{StaticResource FlipTransition}" 
                                       ItemsSource="{Binding Images2}" 
                                             Width="357" 
                                            Height="272" 
                               HorizontalAlignment="Left" 
                                 VerticalAlignment="Top" 
                                      ItemTemplate="{StaticResource ItemTemplate}" 
                                            x:Name="box2" 
                                            Margin="357,0,0,0"/>
      ....ETC....

It is references what I believe is this class (ImageSourceConverter.cs):

    /// <summary>
    /// This converter automatically disposes image streams as soon as images
    /// are loaded, thus avoiding file access exceptions when attempting to delete images.
    /// </summary>
    public sealed class ImageSourceConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string path = value as string;
            if (path != null)
            {
                //create new stream and create bitmap frame
                var bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = new FileStream(path, FileMode.Open, FileAccess.Read);
                //load the image now so we can immediately dispose of the stream
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                bitmapImage.EndInit();

                //clean up the stream to avoid file access exceptions when attempting to delete images
                bitmapImage.StreamSource.Dispose();

                return bitmapImage;
            }
            else
            {
                return DependencyProperty.UnsetValue;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return DependencyProperty.UnsetValue;
        }
    }

My View Model (MainWindowViewModel.cs) is this:   

    public class MainWindowViewModel : IDisposable
    {
        private readonly IDisposable _token1;
        private readonly IDisposable _token2;
        private readonly IDisposable _token3;
        private readonly IDisposable _token4;
        private readonly IDisposable _token5;
        private readonly IDisposable _token6;
        private readonly IDisposable _token7;
        private readonly IDisposable _token8;
        private readonly IDisposable _token9;
        private readonly IDisposable _token10;

        public MainWindowViewModel(IImageSource imageSource)
        {
            // subscribe to update images at regular intervals
            _token1 = imageSource
                .GetImages(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "box1"))
                .ObserveOn(DispatcherScheduler.Current)
                .Subscribe(i => UpdateImages(i, box1), ex => ShowError(ex));

            _token2 = imageSource
                .GetImages(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "box2"))
                .ObserveOn(DispatcherScheduler.Current)
                .Subscribe(i => UpdateImages(i, box2), ex => ShowError(ex));

            _token3 = imageSource
                .GetImages(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "box3"))
                .ObserveOn(DispatcherScheduler.Current)
                .Subscribe(i => UpdateImages(i, box3), ex => ShowError(ex));

            _token4 = imageSource
                .GetImages(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "box4"))
                .ObserveOn(DispatcherScheduler.Current)
                .Subscribe(i => UpdateImages(i, box4), ex => ShowError(ex));

            _token5 = imageSource
                .GetImages(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "box5"))
                .ObserveOn(DispatcherScheduler.Current)
                .Subscribe(i => UpdateImages(i, box5), ex => ShowError(ex));

            _token6 = imageSource
                .GetImages(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "box6"))
                .ObserveOn(DispatcherScheduler.Current)
                .Subscribe(i => UpdateImages(i, box6), ex => ShowError(ex));

            _token7 = imageSource
                .GetImages(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "box7"))
                .ObserveOn(DispatcherScheduler.Current)
                .Subscribe(i => UpdateImages(i, box7), ex => ShowError(ex));

            _token8 = imageSource
                .GetImages(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "box8"))
                .ObserveOn(DispatcherScheduler.Current)
                .Subscribe(i => UpdateImages(i, box8), ex => ShowError(ex));

            _token9 = imageSource
                .GetImages(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "box9"))
                .ObserveOn(DispatcherScheduler.Current)
                .Subscribe(i => UpdateImages(i, box9), ex => ShowError(ex));

            _token10 = imageSource
                .GetImages(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "box10"))
                .ObserveOn(DispatcherScheduler.Current)
                .Subscribe(i => UpdateImages(i, box10), ex => ShowError(ex));
        }

        private void ShowError(Exception ex)
        {
            MessageBox.Show(ex.Message,
                            "Photo Gallery", MessageBoxButton.OK, MessageBoxImage.Error);
        }

        /// <summary>
        /// Updates the animation's images.
        /// </summary>
        /// <param name="images">The images to update with</param>
        /// <param name="animation">The animation to update</param>
        private void UpdateImages(IEnumerable<string> images, ObservableCollection<ImageViewModel> animation)
        {
            animation.Clear();
            foreach (var i in images)
            {
                animation.Add(new ImageViewModel { Path = i });
            }
        }

        /// <summary>
        /// Gets or sets a collection of images used for the first animation. 
        /// </summary>
        public ObservableCollection<ImageViewModel> box1 { get; set; } =
            new ObservableCollection<ImageViewModel>();

        /// <summary>
        /// Gets or sets a collection of images used for the second animation. 
        /// </summary>
        public ObservableCollection<ImageViewModel> box2 { get; set; } =
            new ObservableCollection<ImageViewModel>();

        /// <summary>
        /// Gets or sets a collection of images used for the third animation. 
        /// </summary>
        public ObservableCollection<ImageViewModel> box3 { get; set; } =
            new ObservableCollection<ImageViewModel>();

        /// <summary>
        /// Gets or sets a collection of images used for the fourth animation. 
        /// </summary>
        public ObservableCollection<ImageViewModel> box4 { get; set; } =
            new ObservableCollection<ImageViewModel>();

        /// <summary>
        /// Gets or sets a collection of images used for the fifth animation. 
        /// </summary>
        public ObservableCollection<ImageViewModel> box5 { get; set; } =
            new ObservableCollection<ImageViewModel>();

        /// <summary>
        /// Gets or sets a collection of images used for the sixth animation. 
        /// </summary>
        public ObservableCollection<ImageViewModel> box6 { get; set; } =
            new ObservableCollection<ImageViewModel>();

        /// <summary>
        /// Gets or sets a collection of images used for the seventh animation. 
        /// </summary>
        public ObservableCollection<ImageViewModel> box7 { get; set; } =
            new ObservableCollection<ImageViewModel>();

        /// <summary>
        /// Gets or sets a collection of images used for the eighth animation. 
        /// </summary>
        public ObservableCollection<ImageViewModel> box8 { get; set; } =
            new ObservableCollection<ImageViewModel>();

        /// <summary>
        /// Gets or sets a collection of images used for the nineth animation. 
        /// </summary>
        public ObservableCollection<ImageViewModel> box9 { get; set; } =
            new ObservableCollection<ImageViewModel>();

        /// <summary>
        /// Gets or sets a collection of images used for the tenth animation. 
        /// </summary>
        public ObservableCollection<ImageViewModel> box10 { get; set; } =
            new ObservableCollection<ImageViewModel>();

        public void Dispose()
        {
            _token1.Dispose();
            _token2.Dispose();
            _token3.Dispose();
            _token4.Dispose();
            _token5.Dispose();
            _token6.Dispose();
            _token7.Dispose();
            _token8.Dispose();
            _token9.Dispose();
            _token10.Dispose();
        }
    }

The IImageSource.cs:

public interface IImageSource
    {
        IObservable> GetImages(string path);
    }

And lastly the ImageSource.cs:   

public class ImageSource : IImageSource
    {
        TimeSpan _pollingInterval;

        public ImageSource(TimeSpan pollingInterval)
        {
            _pollingInterval = pollingInterval;
        }

        public IObservable<IEnumerable<string>> GetImages(string path)
        {
            if (!Directory.Exists(path))
            {
                return Observable.Empty<IEnumerable<string>>();
            }

            try
            {
                return Observable.Create<IEnumerable<string>>(observer =>
                {
                    return TaskPoolScheduler.Default.ScheduleAsync(async (ctrl, ct) =>
                    {
                        for (; ; )
                        {
                            if (ct.IsCancellationRequested)
                            {
                                break;
                            }

                            try
                            {
                                var images = Directory.GetFiles(path, "*.jpg");
                                observer.OnNext(images);
                            }
                            catch (Exception ex)
                            {
                                observer.OnError(ex);
                                throw;
                            }

                            await ctrl.Sleep(_pollingInterval).ConfigureAwait(false);
                        }
                    });
                });
            } catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return null;
            }
        }
    }

From what i can remember, It loads up the XAML page there and populates each box with images that corispond to a directory called c:\images\box1...10. But as the error at the top of this says I’m not able to do that even though the program still runs just fine - be it without the images of course.

Would be great if someone could tell me what I was up too ha back those many years.