I am trying to implement an image slider with native WPF controls. The PropertyChanged
events for the SelectedIndex
and CurrentImage
properties aren't firing when I click Next or Back or Add a new one.
ViewModel:
namespace WpfApplication2.ImageSlider
{
public class ImageList : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<ImageItem> _Images = new ObservableCollection<ImageItem>();
public ObservableCollection<ImageItem> Images
{
get
{ return _Images; }
}
private int _SelectedIndex;
public static readonly PropertyChangedEventArgs SelectedIndexProperty = new PropertyChangedEventArgs("SelectedIndex");
public int SelectedIndex
{
get { return _SelectedIndex; }
set
{
_SelectedIndex = value;
var handler = PropertyChanged; // value is null
if (handler != null)
{
handler(this, SelectedIndexProperty);
handler(this, CurrentImageProperty);
}
}
}
public static readonly PropertyChangedEventArgs CurrentImageProperty = new PropertyChangedEventArgs("CurrentImage"); //Not Firing
private ImageItem _CurrentImage;
public ImageItem CurrentImage //Not Firing
{
get { return _CurrentImage; }
set
{
_CurrentImage = value;
if (Images.Count > 0)
{
CurrentImage =
Images[SelectedIndex];
}
}
}
public void Next()
{
if (SelectedIndex < Images.Count - 1)
SelectedIndex++;
else
SelectedIndex = 0;
}
public void Back()
{
if (SelectedIndex == 0)
SelectedIndex = Images.Count - 1;
else
SelectedIndex--;
}
private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
return _clickCommand ?? (_clickCommand = new CommandHandler(() => AddNewImage(), _canExecute));
}
}
public ImageList()
{
_canExecute = true;
}
private bool _canExecute;
public void AddNewImage()
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.gif, *.png, *.bmp, *.tif) | *.jpg; *.jpeg; *.jpe; *.gif; *.png, *.bmp, *.tif";
dlg.ShowDialog();
if (dlg.FileName != "")
{
Images.Add(new ImageItem() { URI = new Uri(dlg.FileName) });
var handler = PropertyChanged;
if (handler != null)
{
handler(this, CurrentImageProperty);
}
}
}
}
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}
}
Model:
namespace WpfApplication2.ImageSlider
{
public class ImageItem
{
public Uri URI { get; set; }
private BitmapSource _Source;
public BitmapSource Source
{
get
{
try
{
if (_Source == null) _Source = new BitmapImage(URI);//lazy loading
}
catch (Exception)
{
_Source = null;
}
return _Source;
}
}
public void Save(string filename)
{
var img = BitmapFrame.Create(Source);
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(img);
using (var saveStream = System.IO.File.OpenWrite(filename))
encoder.Save(saveStream);
}
}
}
XAML:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication2.ImageSlider"
mc:Ignorable ="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BitmapImage x:Key="NotFound" UriSource="E:\..\NotFound.png"/>
</Window.Resources>
<Window.DataContext>
<local:ImageList/>
</Window.DataContext>
<DockPanel>
<Button Content="<" Click="Back_Click"/>
<Button DockPanel.Dock="Right" Content=">" Click="Next_Click"/>
<Image Source="{Binding CurrentImage.Source, Mode=OneWay,
TargetNullValue={StaticResource NotFound},
FallbackValue={StaticResource NotFound}}"/>
<Button Content="Add" Command="{Binding ClickCommand}"></Button>
</DockPanel>
</Window>
XAML.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private ImageList _list= new ImageList();
public ImageList list
{
get { return _list; }
set { _list = DataContext as ImageList; } //The count of the images is always 0;
}
private void Next_Click(object sender, RoutedEventArgs e)
{
list.Next();
}
private void Back_Click(object sender, RoutedEventArgs e)
{
list.Back();
}
}