我的图像滑块代码的PropertyChanged事件未被引发

时间:2016-07-27 05:52:23

标签: c# wpf xaml mvvm

我正在尝试使用本机WPF控件实现图像滑块。单击“下一步”或“后退”或“添加新属性”时,PropertyChangedSelectedIndex属性的CurrentImage事件不会触发。

视图模型:

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();
        }
    }
}

型号:

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="&lt;" Click="Back_Click"/>
        <Button DockPanel.Dock="Right" Content="&gt;" 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();
    }
}

2 个答案:

答案 0 :(得分:2)

问题是您使用的按钮与用于显示图像的ImageList对象不同。您已在XAML中将ImageList的新实例声明为DataContext对象。您的代码隐藏确实尝试将此对象分配到_list字段,该字段支持您用来调用list和{{1}的Back()属性方法。

但是这种分配字段的尝试是错误的代码,并且甚至无法工作,因为没有人调用该属性的setter。因此,getter始终返回您在字段初始值设定项中指定的空Next()对象。

您只需提供一个getter并投射ImageList值:

DataContext

答案 1 :(得分:1)

你弄错了......这就是为什么它不起作用 属性已更改请勿设置值,仅将信号系统设置为属性的GET值。

尝试将其作为新的ImageListClass

`

public class ImageListFixed : INotifyPropertyChanged
    {
        #region Fields
    private ObservableCollection<ImageItem> images = new ObservableCollection<ImageItem>();
    private int selectedIndex;
    private ImageItem currentImage;

    #endregion Fields

    #region Properties

    public ObservableCollection<ImageItem> Images
    {
        get { return images; }
        set { images = value; }
    }

    public int SelectedIndex
    {
        get { return selectedIndex; }
        set
        {
            if(value < Images.Count && value > -1)
            {
                selectedIndex = value; OnPropertyChanged();
                CurrentImage = Images[selectedIndex];
            }
        }
    }

    public ImageItem CurrentImage
    {
        get { return currentImage; }
        set { currentImage = value; OnPropertyChanged(); }
    }

    #endregion Properties

    #region Public Methods

    public void Next()
    {
        SelectedIndex ++;
    }

    public void Back()
    {
        SelectedIndex--;
    }

    #endregion Public Methods

    #region Methods

    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) });
            SelectedIndex = Images.Count - 1;
        }
    }

    #endregion Methods

    #region Constructors

    public ImageListFixed()
    {
        _canExecute = true;
    }

    #endregion Constructors

    #region Commands

    private ICommand _clickCommand;
    public ICommand ClickCommand
    {
        get
        {
            return _clickCommand ?? (_clickCommand = new CommandHandler(() => AddNewImage(), _canExecute));
        }
    }

    private bool _canExecute;

    private ICommand nextCommand;

    public ICommand NextCommand
    {
        get
        {
            if (nextCommand == null)
            {
                nextCommand = new CommandHandler(()=> OnNextCommand(), true);
            }
            return nextCommand;
        }
        set { nextCommand = value; }
    }

    private void OnNextCommand()
    {
        Next();
    }
    private ICommand backCommand;

    public ICommand BackCommand
    {
        get
        {
            if(backCommand == null)
            {
                backCommand = new CommandHandler(() => OnBackCommand(), true);
            }
            return backCommand;
        }
        set { backCommand = value; }
    }

    private void OnBackCommand()
    {
        Back();
    }

    #endregion Commands




    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion INotifyPropertyChanged

}`

删除窗口中的所有后退代码,并将窗口代码更改为以下内容:

<DockPanel>
    <Button Content="&lt;" Command="{Binding BackCommand}"/>
    <Button DockPanel.Dock="Right" Content="&gt;" Command="{Binding NextCommand}"/>
    <Image Source="{Binding CurrentImage.Source, Mode=OneWay}"/>
    <Button Content="Add" Command="{Binding ClickCommand}"></Button>
</DockPanel>